在Django中,我该如何从初始化脚本调用子命令“syncdb”?

51
我对Python和Django不熟悉,在阅读Django Book时,了解到了命令'python manage.py syncdb',它可以为我生成数据库表。在开发环境中,我使用内存中的sqlite数据库,因此每次重新启动服务器时都会自动清除。那么如何编写脚本来执行'syncdb'命令?(这应该在'settings.py'文件中完成吗?) 澄清 OP正在使用内存数据库,需要在处理针对该数据库定义的Django模型的任何进程开始时初始化该数据库。最好的方法是确保数据库在每个进程启动时只初始化一次。这适用于运行测试或运行服务器,无论是通过manage.py runserver还是通过Web服务器进程(例如WSGI或mod_python)。
5个回答

89

所有Django管理命令都可以通过编程方式访问

from django.core.management import call_command
call_command('syncdb', interactive=True)
理想情况下,你应该使用runserver的预初始化信号来激活它,但是这样的信号不存在。所以,如果我是你,我会创建一个自定义的管理命令,比如runserver_newdb,并在其中执行以下操作:
from django.core.management import call_command
call_command('syncdb', interactive=True)
call_command('runserver')

查看文档,了解如何编写自定义管理命令的更多信息。


在一个典型的Django项目中,你会把 "from django.core.management import call_command call_command('syncdb', interactive=True)" 放在哪个文件里? - Edward D'Souza
对于这个用例,我会将其放置在 settings.py 中或者在从 settings.py 导入的脚本中。 - Daniel Naab

11
根据"Where to put Django startup code?"提出的建议,您可以使用中间件来实现启动代码。Django文档在这里
例如(未经测试):
startup.py:
from django.core.exceptions import MiddlewareNotUsed
from django.conf import settings
from django.core.management import call_command

class StartupMiddleware(object):
    def __init__(self):
        # The following db settings name is django 1.2.  django < 1.2 will use settings.DATABASE_NAME
        if settings.DATABASES['default']['NAME'] == ':memory:':
            call_command('syncdb', interactive=False)

        raise MiddlewareNotUsed('Startup complete')

并且在您的settings.py文件中:

 MIDDLEWARE_CLASSES = (
     'your_project.middleware.startup.StartupMiddleware',

     # Existing middleware classes here
 )

7
更新:
我在项目的根目录中添加了一个名为 run.sh 的脚本。这对于我使用 SQLite 数据库是有效的。
#!/usr/bin/python
from django.core.management import call_command
call_command('syncdb')
call_command('runserver')

原始答案

我不确定你所说的“脚本同步数据库命令”的意思。通常,您会在命令行中执行python manage.py syncdb。这通常是在添加新模型后完成的。如果您想要使用简单的shell脚本轻松完成此操作,则可以这样做。我没有看到任何理由将(或调用)syncdb放置在settings.py中。

您能否添加更多细节以回答问题?添加上下文并解释您要完成的确切内容是什么?


我希望像调用其他Python方法一样来调用'syncdb'命令,并将其放置在settings.py中,这样每次启动应用程序时它都会自动创建数据库。 - Thiago Padilha
明白了。但我并不认为settings.py是最好的存放位置。我们可以就此意见不合 :) - Manoj Govindan
你还有其他建议吗?我对Python完全是新手。正如Craig Trader所说,'syncdb'的调用必须发生在同一个进程内,所以我猜这就排除了使用shell脚本的可能性。 - Thiago Padilha
找到了通过API调用syncdb的机制。已更新答案。目前还没有更好的想法放在哪里 :( - Manoj Govindan
既然Daniel回答得最早,因此他获得了积分,但是还是要感谢您的帮助,给您一个加1。 - Thiago Padilha

0

@Daniel Naab的回答和官方网站上的文档并不适用于将管理命令作为入口点执行。

当您想在像AWS Lambda或Google Cloud Functions这样的托管云环境中使用管理命令作为入口点时,可以查看 manage.py 并尝试类似的操作。

import os
from django.core.management import execute_from_command_line

def publishing_fn(data, context):
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'YOURAPP.settings')
    # The first argument is "manage.py" when it's run from CLI.
    # It can be an empty string in this case
    execute_from_command_line(['', 'COMMAND', 'ARGS...'])

-1

您可以创建一个新的脚本,而不是调用manage.py,来调用manage.py:

from subprocess import call
call(["python", "manage.py", "syncdb"])
call(["python", "manage.py", "runserver"])

如果您不需要添加管理员,您可以将第二行更改为以下内容:
call(["python", "manage.py", "syncdb", "--noinput"])

我假设你想做的是每次用一个命令创建你的数据库并启动服务器。


我本来希望能够像使用Python API一样访问“syncdb”,但没关系。 - Thiago Padilha
这对于内存数据库可能行不通,因为每个“调用”都会调用一个单独的进程,该进程将具有自己的内存数据库。 - Craig Trader
是的,你说得对。这可能排除了Bash脚本的选择。 - Thiago Padilha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接