为什么Django启动时会调用表单字段的__init__方法?
我有一个Django应用,里面有一些自定义的表单字段,这些字段在创建的时候会执行一些比较慢的操作。最近我发现,当Django启动的时候,这些字段的创建方法就会被调用,甚至在用户还没做任何需要这个表单的操作之前。
为什么在服务器启动时就会创建这些字段呢?
举个例子:
urls.py:
from myapp.views import view1
...
url(r'^test$', view1.test),
views/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,第一次请求任何页面的时候就会停下来,即使那个页面并不需要这个表单或字段。错误追踪信息显示是从urls.py的导入行开始的。
这是因为我在urls.py里导入了view1,而不是导入view1.test吗?
补充:这并不是Django特有的,这里有一个测试案例来说明这个行为:
class Something():
def __init__(self):
print "Something __init__() called"
class UsesSomething():
field = Something()
如果你在交互式终端运行这个代码,它会打印出“Something init() called”。这让我很惊讶,因为我实际上并没有创建一个UsesSomething对象。
2 个回答
1
在你的例子中:
class UsesSomething():
field = Something()
这行代码 field = Something()
会在你导入这个模块时执行,因为Python在处理类定义的时候就是这样工作的。其实你可以在类定义里面放任何代码。
模块:test.py:
class UsesSomething():
print "wow!"
>>> import test
wow!
11
因为你在表单定义中实例化了字段,这个表单很可能是被你某个视图导入的。
字段的初始化不是进行这种动态初始化的合适地方,正是因为这个原因。你需要的是在表单初始化时调用的东西,也就是表单的 __init__
方法。
不过,实际上你根本不需要这样做——你只需要使用 forms.ModelChoiceField
,它会接收一个查询集,并为你动态分配选项。
class MyForm(ModelForm):
field1 = forms.ModelChoiceField(queryset=ReallyLargeTableModel.objects.all())