使用 Python.h 从 C++ 调用 Django
Posted
技术标签:
【中文标题】使用 Python.h 从 C++ 调用 Django【英文标题】:Calling Django from C++ using Python.h 【发布时间】:2013-06-11 09:11:17 【问题描述】:我需要从 C++ 调用 Django 函数并在我的 C++ 代码中获取它们的输出。 如您所知,Django 是通过调用 Manage.py Python 脚本来使用的,需要的函数作为第一个参数,然后是参数。
现在我有一个名为“test”的测试函数,它返回一个 JSON 格式的字符串。
因此,如果我打电话:
python manage.py test
我得到以下信息:
'products': ['id': 125, 'label': 'Robin', 'id': 4, 'label': 'Robinou']
要在 cpp 中得到这个,我可以:
system(python path.../manage.py test);
并捕获输出。但我不喜欢它。我也可以使用 Boost.Python。我也不喜欢。
出于大小和速度方面的考虑,我希望能够仅在 C++/Python.h 中执行此操作。
这是我正在运行的 manage.py:
import os
import sys
sys.path.append('C:\ds')
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "frontoffice.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)
如果我添加一个 print sys.argv
,我会得到以下输出:['manage.py', 'test']
。
所以我设法以一种讨厌的方式做到了:
bool initPython()
Py_Initialize();
int check = 0;
check = PyRun_SimpleString("import sys");
check = PyRun_SimpleString("import os");
check = PyRun_SimpleString("sys.path.append('C:\\ds')");
check = PyRun_SimpleString("os.environ.setdefault(\"DJANGO_SETTINGS_MODULE\", \"frontoffice.settings\")");
check = PyRun_SimpleString("from django.core.management import execute_from_command_line");
if(check == 0) return true;
else return false;
std::string execPythonCommand(std::string cmd)
std::string command = std::string("robin = ['dontreallycarewhatitis', '").append(cmd).append("']");
PyRun_SimpleString(command.c_str());
PyRun_SimpleString("execute_from_command_line(robin)");
没什么特别的。具有跨平台的优势,但捕获输出是一团糟,所以它可以工作,但这不是我想要的。我希望能够直接得到 execute_from_comand_line 命令的输出。
这是我目前所想出的。运行 initPython() 后:
PyObject* executeCmd = PyImport_Import(PyString_FromString("django.core.management"));
PyObject* executeFunc = PyObject_GetAttrString(executeCmd, "execute_from_command_line");
std::cout << "Imported function." << " isNULL: " << (executeFunc == NULL) << " isExecutable: " << PyCallable_Check((executeFunc)) << std::endl;
所以我设法获得了 execute_from_command_line 函数的 Cpp 对象 - 它是可调用的。这就是棘手的地方。我怎么称呼它?
sys.argv,根据 Python 文档,是一个列表。所以我尝试重新创建完全相同的东西并调用它:
PyObject* pRobin = PyList_New(2);
PyObject* pString = PyString_FromString("test");
PyObject* pString0 = PyString_FromString("manage.py");
PyList_Append(pRobin,pString0);
PyList_Append(pRobin,pString);
PyObject* pValue = PyObject_CallObject(executeFunc, pRobin);
//PyObject* pValue = PyObject_CallFunctionObjArgs(executeFunc, pRobin, NULL); //Doesn't work either
现在我什么都试过了。 PyObject_CallObject、CallFunction、CallFunctionObjArgs,使用元组而不是列表,并且 PyErr_Print() 没有给我任何明确的信息。我真的不是 Python 专家,并且正在努力解决这个问题。如何获取 pValue 来存储测试例程的输出 JSON 字符串?
仅供参考:
>>> inspect.getargspec(django.core.management.execute_from_command_line)
ArgSpec(args=['argv'], varargs=None, keywords=None, defaults=(None,))
我需要经常快速地运行 manage.py xxx(其中 xxx 是一个命令),所以我真的很想使用 C/API 而不是做一些讨厌的 stdio 捕获。
仅供参考,我在后面使用 VS2012、Windows 8、Python 2.7 和 PostGRE。 任何和所有的想法将不胜感激。谢谢!
【问题讨论】:
【参考方案1】:我对从 C++ 调用 Python 一无所知,但是在 Python 中动态调用管理命令的方法是使用 django.core.management.call_command
。使用它可能会让您的事情变得更轻松。
【讨论】:
理论上,这就是我想要的。我很震惊花了这么多时间却没有找到这个功能。PyRun_SimpleString("from django.core.management import call_command");
check = PyRun_SimpleString("call_command('test')");
工作。但是我仍然不能使用 PyObjects 来做到这一点。有什么想法吗?
没关系:PyObject* executeFunc = PyObject_GetAttrString(executeCmd, "call_command");
PyObject* pValue = PyObject_CallFunctionObjArgs(executeFunc, PyString_FromString("test"), NULL);
按我的意愿工作。非常感谢丹尼尔!以上是关于使用 Python.h 从 C++ 调用 Django的主要内容,如果未能解决你的问题,请参考以下文章