在syncdb期间保持代码不运行

时间:2009-06-01 23:36:13

标签: python django django-models django-syncdb syncdb

我有一些代码会抛出导致syncdb抛出错误(因为它在创建表之前尝试访问模型)。

有没有办法阻止代码在syncdb上运行?类似的东西:

if not syncdb:
    run_some_code()

谢谢:)

编辑:PS - 我考虑过使用post_init信号...来访问数据库的代码,这是一个好主意吗?

更多信息

以下是根据要求提供的更多信息:)

我遇到过这种情况,例如......我正在攻击django-cron并确定在加载django时确保没有现有作业是必要的(因为它会搜索所有已安装的应用程序无论如何,工作并加载它们。)

所以我将以下代码添加到__init__.py文件的顶部:

import sqlite3

try:
        # Delete all the old jobs from the database so they don't interfere with this instance of django
        oldJobs = models.Job.objects.all()
        for oldJob in oldJobs:
                oldJob.delete()
except sqlite3.OperationalError:
        # When you do syncdb for the first time, the table isn't 
        # there yet and throws a nasty error... until now
        pass

由于显而易见的原因,这是废话。它与sqlite绑定,我有更好的地方来放置这个代码(这就是我在这个问题上发生的事情)但它确实有效。

正如你所看到的,你得到的错误是操作错误(在sqlite中),堆栈跟踪说的是“找不到表django_cron_job”的内容

解决方案

最后,目标是在加载任何网页之前运行一些代码

这可以通过在urls.py文件中执行来完成,因为必须在提供页面之前导入它(显然)。

我能够删除那个丑陋的尝试/除了块:)感谢上帝(和S. Lott)

2 个答案:

答案 0 :(得分:4)

“编辑:PS - 我考虑过使用post_init信号......对于访问数据库的代码,这是一个好主意吗?”

从不。

如果你有代码在创建表之前访问模型,那么你就会遇到很大的问题。你可能做错了。

通常,您大约运行一次syncdb。数据库已创建。您的Web应用程序使用数据库。

有时,您进行了设计更改,删除并重新创建数据库。然后您的Web应用程序会长时间使用该数据库。

您(通常)不需要__init__.py模块中的代码。您(几乎)永远不会拥有在__init__.py模块中实际工作的可执行代码。对于Django来说,这是非常非常罕见的。

Django Cron表示您在__init__.py进行排程安排时,我不确定您为何会弄错urls.py


修改

清除记录是一回事。

__init__.py和Django-cron的base.py混在一起显然是完全错误的方法。如果这很复杂,你做错了。

不可能告诉你要做什么,但这应该是微不足道的。

您的urls.py只能在syncdb之后运行,并且所有ORM资料都已正确配置并绑定后。

例如,您的urls.py可以删除一些行,然后向表中添加一些行。此时,所有syncdb问题都已解决。

为什么你没有urls.py中的逻辑?

答案 1 :(得分:2)

尝试在模型创建之前访问模型的代码几乎只存在于模块级别;它必须是导入模块时运行的可执行代码,如您的示例所示。正如您所猜测的那样,syncdb失败的原因。它尝试导入模块,但导入模块的行为导致应用程序级代码执行;如果你愿意,那就是“副作用”。

在Python中避免导致副作用的模块导入的愿望非常强烈,以至于可执行python脚本的if __name__ == '__main__':约定已经变得司空见惯。当只是加载代码库导致应用程序开始执行时,头痛随之发生: - )

对于Django应用程序,这变得非常令人头痛。考虑每次导入模块时执行oldJob.delete()的效果。当您使用Django开发服务器运行时,它似乎只执行一次,但在生产环境中,它会经常执行。例如,如果你使用Apache,Apache会频繁启动几个等待处理请求的子进程。随着长时间运行的服务器的发展,每次为Web服务器分叉处理程序时,您的Django应用程序都将被引导,这意味着将导入模块并且将多次调用delete(),通常是不可预测的。遗憾的是,信号无助,因为每次初始化Apache进程时都会触发信号。

它不是,顺便说一句,只是一个可能导致您的代码无意中执行的网络服务器。如果您使用像epydoc这样的工具,例如,他们将导入您的代码以生成API文档。这反过来会导致您的应用程序逻辑开始执行,这显然是仅运行文档解析器的不良副作用。

出于这个原因,像这样的清理代码要么最好由cron作业处理,它会定期查找过时的作业并清理数据库。此自定义脚本也可以手动运行,也可以由任何进程运行(例如,在部署期间,或作为单元测试setUp()函数的一部分,以确保运行干净的测试)。无论你如何做,重要的是这样的代码应该始终执行显式,而不是隐式作为打开源文件的结果。

我希望有所帮助。我知道它没有提供一种方法来确定syncdb是否正在运行,但如果你考虑到生产部署设计你的Django应用程序,syncdb问题将神奇地消失。