我有一个带有自定义表单字段的Django应用程序,其中一些在构造函数中运行缓慢。我最近惊讶地发现,当Django本身启动时,那些构造函数会被调用,甚至在用户在视图中执行需要该表单的操作之前。
为什么它们会在服务器启动时实例化?
示例:
urls.py:
from myapp.views import view1
...
url(r'^test$', view1.test),
视图/ view1.py:
class MyForm(ModelForm):
class Meta:
model = MyModel
field1 = MyChoiceField()
class MyChoiceField(ChoiceField):
def __init__(self, choices=(), required=True, widget=None, label=None,
initial=None, help_text=None, *args, **kwargs):
super(ChoiceField, self).__init__(required, widget, label, initial,
help_text, *args, **kwargs)
self.choices = [(m.id, m.name) for m in ReallyLargeTableModel.objects.all()]
如果我在该字段构造函数中设置了一个断点,然后启动Django,它会在我第一次请求任何页面时中断,即使所讨论的视图不需要该表单或字段。 stacktrace返回urls.py中的导入行。
这是因为我在urls.py中导入view1而不是导入view1.test吗?
编辑:这不是Django特有的,这里是一个测试用例说明行为:
class Something():
def __init__(self):
print "Something __init__() called"
class UsesSomething():
field = Something()
如果您在交互式终端中运行它,它将打印“Something init ()”。这对我来说是令人惊讶的,因为我实际上没有实例化一个UsesSomething对象。
答案 0 :(得分:8)
因为你实例化了表单定义中的字段,这可能是由你的一个视图导入的。
由于这个原因,字段init是执行此类动态初始化的错误位置。您需要在初始化表单时调用的内容:即表单__init__
。
那就是说,你根本不想这样做 - 你只需要使用forms.ModelChoiceField
,它接受一个查询集并为你做动态的选择。
class MyForm(ModelForm):
field1 = forms.ModelChoiceField(queryset=ReallyLargeTableModel.objects.all())
答案 1 :(得分:0)
在你的例子中:
class UsesSomething():
field = Something()
在Python处理类定义时导入包含模块时,将执行代码行field = Something()
。这就是Python的工作原理。实际上,您可以将任意代码放在类定义中。
module:test.py:
class UsesSomething():
print "wow!"
>>> import test
wow!