2017-05-22 1 views
1

私はFooというモデルを持っています。存在しないフィールド名を割り当てても、このモデルの新しいインスタンスを作成してデータベースに保存できます。例えば:Djangoモデルのこの誤って入力されたフィールド名が例外をスローしないのはなぜですか?

foobar = Foo.objects.create() 
foobar.abcdefg = True # The field abcdefg does not exist! 
foobar.full_clean() 
foobar.save() 

存在しないフィールドに代入するときにDjangoが例外をスローしないのはなぜですか?少なくともfull_cleanの間、例外をスローするようにするにはどうすればよいですか?

答えて

1

foobarは、クラスのインスタンスに過ぎません。あなたはいつでも任意のインスタンスと同様に、属性を追加することができます。

>>> class Test(object): 
...  myval = 7 
... 
>>> t = Test() 
>>> t.myval 
7 
>>> t.otherval = 'another' 
>>> t.otherval 
'another' 

を(コメントにFlimmで述べたように、あなたのクラスに__slots__属性を追加することでこれを防ぐことができます)

あなたは使用することができself.__dict__無関係の属性をチェックするにはfull_cleanメソッドを使用しますが、どの属性がそこにあるのかを判断できる必要があります。モデルインスタンスには、残しておく必要がある_state属性があることに注意してください。

あなたは(this answerから)このリストの内包表記を使用して、モデルのフィールド名のリストを取得することができます。

[f.name for f in self._meta.get_fields()] 

ので、その後、ちょうどself.__dict__を反復し、任意のキーがあることがわかっている場合は例外を発生させますそのモデルフィールドのリストにはなく、アンダースコアで始まらないようにしてください。

+0

[__slots__](http://book.pythontips.com/en/latest/__slots__magic.html)を使用すると、いつでも新しい属性を追加することができなくなります。 – Flimm

+0

それは良い点です。しかし、Djangoがあなたのモデルに追加する属性をチェックし、 '__slots__'にそれらの属性を含めて、まだ動作していることを確認する必要があります。 – FamousJameous

1

Pythonでは、どのような名前の属性も事実上すべてのインスタンスに格納できます。これをブロックすることも可能です(クラスをC言語で記述することによって)。

ほとんどのインスタンスは、その属性をディクショナリに格納しているためです。辞書は、__dict__というインスタンス属性に格納されます。実際には、「クラスは辞書の文法的な砂糖です」と言う人もいます。つまり、辞書を使ってクラスでできることはすべて実行できます。クラスで簡単にできます。

あなたは、コンパイル時にすべての属性を定義する必要がある静的言語に慣れています。 Pythonでは、クラス定義はコンパイルされずに実行されます。クラスはほかのオブジェクトと同じようにオブジェクトです。属性を追加することは辞書に項目を追加するのと同じくらい簡単です。これは設計によるものです。

実際には、宣言のようなものは存在しません。つまり、そこに格納されるオブジェクトの種類についての記述だけでなく、「このクラスにはメソッドfooがある」または「このクラスのインスタンスには属性バーがあります」と決して宣言することはありません。メソッド、属性、クラスなどを定義するだけで、それが追加されます。

+0

[__slots__'を使って](http://book.pythontips.com/en/latest/__slots__magic.html)は、この回答の反例です。オブジェクトは常に '__dict__'を使用するとは限りません。 – Flimm

関連する問題