我有一些代码会抛出导致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)
答案 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问题将神奇地消失。