为什么在Django启动时调用表单字段__init__方法?

时间:2012-01-20 16:12:59

标签: python django

我有一个带有自定义表单字段的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对象。

2 个答案:

答案 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!