2012-01-20 22 views
2

カスタムフォームフィールドを持つDjangoアプリケーションがありますが、その中にはコンストラクタの処理が遅いものがあります。私は最近、Django自体が起動したとき、たとえユーザーがそのフォームをビューで必要とする何かをする前であっても、それらのコンストラクターが呼び出されていることを知りました。Djangoの起動時にフォームフィールド__init__メソッドが呼び出されるのはなぜですか?

なぜサーバー起動時にインスタンス化されるのですか?

例:

urls.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()]  

from myapp.views import view1 
... 
url(r'^test$', view1.test), 

ビュー/ view1.py Djangoを起動すると、問題のビューがそのfを必要としなくても、私はどのページも要求するのが初めてですormまたはフィールド。スタックトレースは、urls.pyのインポート行に戻ります。

これは、view1.testをインポートするのではなく、urls.pyでview1をインポートするためですか?

編集:これはここで、特定のジャンゴされていない動作を示したテストケースである:

class Something(): 
    def __init__(self): 
     print "Something __init__() called" 

class UsesSomething(): 
    field = Something() 

あなたが対話型端末でこれを実行した場合、それは(「を初期化何かを印刷します)と呼ばれる。私はUsesSomethingオブジェクトを実際にインスタンス化していないので、これは私には驚くべきことでした。

+0

それは私のアプリケーションで重要だったことがないだので、本当に、正直に注意を払ったことはありませんが、それは右に感じることはありません。 '__init__'はクラスがインスタンス化されるまで呼び出されません。通常、クラスには実際に初期化を実行するために必要な追加データが必要です。それでも、ビューをインポートせずに単に 'url(r '^ test $'、 'myapp.views.view1.test')を使うとどうなりますか? –

答えて

8

フォーム定義でフィールドをインスタンス化するため、ビューの1つでインポートされていると思われるためです。

このような理由から、このような動的初期化を行うには、フィールドinitが間違った場所です。フォームが初期化されるときに呼び出されるもの、つまりフォームの__init__が必要です。

つまり、実際にはこれをやりたいとは限りません。forms.ModelChoiceFieldを使用する必要があります。これはクエリーセットを取り、選択肢の動的割り当てを行います。あなたの例では

class MyForm(ModelForm): 
    field1 = forms.ModelChoiceField(queryset=ReallyLargeTableModel.objects.all()) 
+0

あなたは正しいですが、実際にMyFormオブジェクトをインスタンス化する前に、MyFormをインポートしてModelChoiceField()コンストラクタを呼び出す理由を理解しようとしています。私の編集を参照してください。 –

+1

クラスレベルで宣言されたもの、つまり '__init__'や他のメソッドの中で宣言されているものはクラス属性です。クラスには利用できますが、特定のインスタンスには使用できません。クラス定義は実行可能なコードであるため、その定義内のフィールドを呼び出すと、クラスが定義されたとき、つまりそのモジュールの最初のインポート時にその呼び出しが実行されます。 –

0

:Pythonはクラス定義を処理するときに、あなたが含むモジュールをインポートするとき

class UsesSomething(): 
    field = Something() 

コードfield = Something()の行が実行されます。これはPythonの動作方法です。実際には、任意のコードをクラス定義の中に入れることができます。

モジュール:test.py:

class UsesSomething(): 
    print "wow!" 

>>> import test 
wow! 
+0

私は数年前からPythonを使用してきましたが、これはまだ私に驚きました。おそらくそれはJavaでは起こらないからでしょう。 –

+1

@ChaseSeibert C++から来て、私も驚いていました。しかし、あなたがそれについて考えるなら、それは理にかなっています。通常は、クラス定義内で属性の代入や関数定義を行うだけです。これらの属性は、そのクラスのインスタンスとは独立して存在するクラス属性です。クラスはPythonの第一レベルのオブジェクトなので、クラス定義自体は実際にオブジェクトを作成しています(クラスのインスタンスではなく実際のクラスオブジェクト)。 –

関連する問題