19

について非常に基本的な質問がありdjango.db.modelsます。

この公式の django チュートリアルで単語 " " を検索するchoice_setと、変数 " choice_set" がどこにも宣言されていないことがわかりますが、魔法のように、コードで使用を開始できます。

*_set 変数を魔法のように作成したものはdjango.db.models.Model何をするのでしょうか? また、他にどのような変数を作成するのでしょうか?

4

4 に答える 4

31

dir関数を使用して、定義した属性と定義された属性の両方のクラスの属性の完全なリストを取得できます。

 dir(Poll)

あなたは少し似たものになるでしょう(正確ではありませんが、私は回り道でそれを構築しています):

['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__',
'__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__',
'__init__', '__metaclass__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', 
'__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__',
 '__weakref__', '_base_manager', '_default_manager', '_deferred', '_get_FIELD_display', 
'_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', 
'_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_set_pk_val', 
'clean', 'clean_fields', 'curve_set', 'date_error_message', 'delete', 'full_clean', 'objects', 
'pk', 'prepare_database_save', 'save', 'save_base', 'choice_set',
'serializable_value', 'unique_error_message', 'validate_unique']

それは多くの価値です!DoesNotExistやのような例外MultipleObjectsReturnedと、最も重要なobjects. しかし、これらの属性のいくつかは Django によって追加されませんでした。そうすれば、すべてのオブジェクトdir(object())の属性のリストが見つかります:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__']

ほとんどの場合、 two で始まり 2 で終わるものは無視できます__。他のほとんどは Django によって追加されました。


これらを実際に設定する方法と場所について: Django はmodels.Modelメタクラスを使用して、各新しいモデルの属性のほとんどを動的に設定します。最初に知っておくべきことは、次のsetattr関数を使用して、クラスにメンバーまたはメソッドを動的に追加できることです。

class X:
    pass
setattr(X, "q", 12)
print X.q  # prints 12

これが、属性の名前に基づいて新しい属性を作成する方法です。

チュートリアルでは、これらの追加属性の定義を開始できるようにする重要な行は次のとおりです。

class Poll(models.Model):

これは、クラスが (Django に属する)Pollクラスを継承することを意味します。models.Model継承には多くの便利なプロパティがあります。基本的に、Pollクラスはクラスが設定した動作の一部を継承しmodels.Modelますが、これらの新しい属性のほとんどを定義する場所は Modelメタクラスです。メタクラスは難しい概念ですが、基本的には新しいクラスを作成するためのレシピとして機能し、メタクラスを定義することで、Django はmodels.pyメタクラスが定義されているときに介入し、新しい を定義します。

Model メタクラスのコードは、ここ(55 行目から) にあります。これは、実際にゼロからクラスを段階的に作成する一連のコードです。見た目は複雑ですが、変数名を見るだけで多くのことがわかります。たとえば、有望な名前のadd_to_classメソッドを見てください。

def add_to_class(cls, name, value):
    if hasattr(value, 'contribute_to_class'):
        value.contribute_to_class(cls, name)
    else:
        setattr(cls, name, value)

'contribute_to_class(重要ではない)の 1 つの特殊なケースを除けば、これは新しい属性 (メソッドやメンバーなど) をクラスに追加するためのメソッドです。それが呼び出された場所は、それが追加しているもののヒントを与えてくれます:

 class.add_to_class('DoesNotExist', subclass_exception(str('DoesNotExist') ...<truncated>...

ここでは例外を追加しています。これは、存在しないDoesNotExistを要求した場合に返されるものです。Poll( を実行Poll.objects.get(pk=1337)するか、直接入力して確認してくださいPoll.DoesNotExist)。

しかし、実際には Django はそれよりもさらに複雑です。あなたが求めている特定 の属性は、すべてのモデルに対して構築されるわけではありません-フィールドが a によって別のフィールドに関連付けられたときに作成されます (あなたのとのように)。割り当てられるさまざまな場所は非常に複雑ですが、基本的にはすべてrelated.pyのこの関数に戻ります。_setForeignKeyPollChoiceget_accessor_name

def get_accessor_name(self):
    # This method encapsulates the logic that decides what name to give an
    # accessor descriptor that retrieves related many-to-one or
    # many-to-many objects. It uses the lower-cased object_name + "_set",
    # but this can be overridden with the "related_name" option.
    if self.field.rel.multiple:
        # If this is a symmetrical m2m relation on self, there is no reverse accessor.
        if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model:
            return None
        return self.field.rel.related_name or (self.opts.object_name.lower() + '_set')
    else:
        return self.field.rel.related_name or (self.opts.object_name.lower())

それはちょうど名前を思いついたところです。それをさかのぼって、それがどのようにクラスに追加されたかを理解することは簡単なことではありません。しかし、このことから、Django にはこのような属性を追加する機会がたくさんあることがわかると思います。

于 2013-01-09T05:31:01.500 に答える
11

これはいくつかのForeignKey魔法です:)

Choiceモデルには、オブジェクトに対する属性pollである があります。Django はオブジェクトに便利なメソッドを追加します。これにより、そのオブジェクトを参照するすべてのオブジェクトを含む が提供されます。ForeignKeyPollchoice_setPollQuerySetChoicePoll

したがって、この(疑似)コードを考えると

myPoll = Poll(question='Is Django awesome?')
option_yes = Choice(poll=myPoll, choice='Yes')
option_no = Choice(poll=myPoll, choice='No')

後で実行できます

poll = Poll.objects.get(question='Is Django awesome?')
options = poll.choice_set.all()

オプションには、関連するChoiceオブジェクトが含まれます。

related_nameを定義するときにオプションを使用して、この属性の名前を変更できますForeignKey

于 2013-01-09T05:29:06.707 に答える