Django/参照処理を読む(逆参照の注入とINSERT)
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
単語検索
|
最終更新
|
ヘルプ
]
開始行:
[[Djangoを読む]]
#contents
*はじめに [#j1aa88c0]
前回までで単独テーブルのINSERT、JOINについて見てきました...
# Give the Question a couple of Choices. The create call...
# Choice object, does the INSERT statement, adds the cho...
# of available choices and returns the new Choice object...
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via t...
>>> q = Question.objects.get(pk=1)
# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking ag...
について見ていきます。
*django.db.models.fields.related [#g373d45d]
今回の問題は、「Questionにchoice_setなどという属性はいつ...
#code(Python){{
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=mode...
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
}}
Question側にchoice_setなどという属性はありません。一方、C...
[[以前>http://www.dzeta.jp/~junjis/code_reading/index.php...
Fieldが追加されるとcontribute_to_classメソッドが呼び出さ...
#code(Python){{
def contribute_to_class(self, cls, name, private_only...
super(RelatedField, self).contribute_to_class(cls...
self.opts = cls._meta
if not cls._meta.abstract:
if self.remote_field.related_name:
related_name = self.remote_field.related_...
else:
related_name = self.opts.default_related_...
if related_name:
# 省略
if self.remote_field.related_query_name:
# 省略
def resolve_related_class(model, related, fie...
field.remote_field.model = related
field.do_related_class(related, model)
lazy_related_operation(resolve_related_class,...
}}
related_name, related_query_nameはともに設定していないの...
で、遅延処理っぽいことが行われています。lazy_related_oper...
#code(Python){{
def lazy_related_operation(function, model, *related_mode...
"""
Schedule `function` to be called once `model` and all...
have been imported and registered with the app regist...
be called with the newly-loaded model classes as its ...
plus any optional keyword arguments.
The `model` argument must be a model class. Each subs...
argument is another model, or a reference to another ...
`resolve_relation()` for the various forms these may ...
references will be resolved relative to `model`.
This is a convenience wrapper for `Apps.lazy_model_op...
registry model used is the one found in `model._meta....
"""
models = [model] + [resolve_relation(model, rel) for ...
model_keys = (make_model_tuple(m) for m in models)
apps = model._meta.apps
return apps.lazy_model_operation(partial(function, **...
}}
まあコメントに書いてある通り全部のモデルが登録されたらfun...
+model_keysとして指定されているモデルを一つ取り出す(firs...
+firstのモデルがまだ登録されてないなら後回し(ちなみにmod...
+モデルが登録されているなら渡された関数に、そのモデルクラ...
+restを引数にして、lazy_model_operationを呼び出す
つまり、一つずつモデルクラスを引数として設定していくとい...
**RelatedField.contribute_to_related_class [#f0851c75]
さて、話をRelatedFieldに戻しましょう。なんやかんやでresol...
#code(Python){{
def do_related_class(self, other, cls):
self.set_attributes_from_rel()
self.contribute_to_related_class(other, self.remo...
}}
このうち、set_attributes_from_relは自分(今はChoiceクラス...
contribute_to_related_classはForeignKeyでも定義されていま...
#code(Python){{
def contribute_to_related_class(self, cls, related):
# Internal FK's - i.e., those with a related name...
# and swapped models don't get a related descript...
if not self.remote_field.is_hidden() and not rela...
setattr(cls._meta.concrete_model, related.get...
# While 'limit_choices_to' might be a callabl...
# it along for later - this is too early beca...
# model load time.
if self.remote_field.limit_choices_to:
cls._meta.related_fkey_lookups.append(sel...
}}
setattrの行が明らかに怪しいです。
related、その実体はreverse_relatedモジュールのManyToOneRe...
#code(Python){{
def get_accessor_name(self, model=None):
# This method encapsulates the logic that decides...
# accessor descriptor that retrieves related many...
# many-to-many objects. It uses the lower-cased o...
# but this can be overridden with the "related_na...
# Due to backwards compatibility ModelForms need ...
# an alternate model. See BaseInlineFormSet.get_d...
opts = model._meta if model else self.related_mod...
model = model or self.related_model
if self.multiple:
# If this is a symmetrical m2m relation on se...
if self.symmetrical and model == self.model:
return None
if self.related_name:
return self.related_name
return opts.model_name + ('_set' if self.multiple...
}}
個々に追いかけるのはやめますが、ともかくこれで'choice_set...
relatedモジュールに戻って、contribute_to_related_classの...
#code(Python){{
from .related_descriptors import (
ForwardManyToOneDescriptor, ManyToManyDescriptor,
ReverseManyToOneDescriptor, ReverseOneToOneDescriptor,
)
class ForeignObject(RelatedField):
related_accessor_class = ReverseManyToOneDescriptor
}}
です。つまり、choice_setとはデスクリプタのようです。
*django.db.models.fields.related_descriptors [#ib3f90aa]
さて、デスクリプタなので__get__を見てみます。
#code(Python){{
def __get__(self, instance, cls=None):
"""
Get the related objects through the reverse relat...
With the example above, when getting ``parent.chi...
- ``self`` is the descriptor managing the ``child...
- ``instance`` is the ``parent`` instance
- ``cls`` is the ``Parent`` class (unused)
"""
if instance is None:
return self
return self.related_manager_cls(instance)
}}
related_manager_cls。プロパティです。
#code(Python){{
@cached_property
def related_manager_cls(self):
related_model = self.rel.related_model
return create_reverse_many_to_one_manager(
related_model._default_manager.__class__,
self.rel,
)
}}
確認。self.relとはManyToOneRelで、related_modelとはChoice...
さて、create_reverse_many_to_one_managerです。
#code(Python){{
def create_reverse_many_to_one_manager(superclass, rel):
"""
Create a manager for the reverse side of a many-to-on...
This manager subclasses another manager, generally th...
the related model, and adds behaviors specific to man...
"""
class RelatedManager(superclass):
def __init__(self, instance):
super(RelatedManager, self).__init__()
self.instance = instance
self.model = rel.related_model
self.field = rel.field
self.core_filters = {self.field.name: instance}
# 省略
return RelatedManager
}}
なんの冗談?と思われるかもしれませんがマジです。動的にク...
*RelatedManager.create [#o63381f0]
さて、というわけでchoice_setの(__get__時の)正体がわかっ...
#code(Python){{
def create(self, **kwargs):
kwargs[self.field.name] = self.instance
db = router.db_for_write(self.model, instance...
return super(RelatedManager, self.db_manager(...
}}
self.fieldはChoiceのqustionフィールド、self.instanceはQue...
親クラス、というかQuerySetのcreateメソッドです。
#code(Python){{
def create(self, **kwargs):
"""
Creates a new object with the given kwargs, savin...
and returning the created object.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
}}
というわけでChoiceモデルを作って保存する際に、ForeignKey...
ForeignKeyが相手のid取得するまで結構長いのだけど、めんど...
*おわりに [#ud94ae10]
今回は複数テーブルの関連、手始めにQuestionにいつの間にか...
Managerは動的に作られ、Questionのインスタンスと関連付けら...
SELECTについても同じようにQuestionインスタンスが設定され...
終了行:
[[Djangoを読む]]
#contents
*はじめに [#j1aa88c0]
前回までで単独テーブルのINSERT、JOINについて見てきました...
# Give the Question a couple of Choices. The create call...
# Choice object, does the INSERT statement, adds the cho...
# of available choices and returns the new Choice object...
# a set to hold the "other side" of a ForeignKey relation
# (e.g. a question's choice) which can be accessed via t...
>>> q = Question.objects.get(pk=1)
# Create three choices.
>>> q.choice_set.create(choice_text='Not much', votes=0)
<Choice: Not much>
>>> q.choice_set.create(choice_text='The sky', votes=0)
<Choice: The sky>
>>> c = q.choice_set.create(choice_text='Just hacking ag...
について見ていきます。
*django.db.models.fields.related [#g373d45d]
今回の問題は、「Questionにchoice_setなどという属性はいつ...
#code(Python){{
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question, on_delete=mode...
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
}}
Question側にchoice_setなどという属性はありません。一方、C...
[[以前>http://www.dzeta.jp/~junjis/code_reading/index.php...
Fieldが追加されるとcontribute_to_classメソッドが呼び出さ...
#code(Python){{
def contribute_to_class(self, cls, name, private_only...
super(RelatedField, self).contribute_to_class(cls...
self.opts = cls._meta
if not cls._meta.abstract:
if self.remote_field.related_name:
related_name = self.remote_field.related_...
else:
related_name = self.opts.default_related_...
if related_name:
# 省略
if self.remote_field.related_query_name:
# 省略
def resolve_related_class(model, related, fie...
field.remote_field.model = related
field.do_related_class(related, model)
lazy_related_operation(resolve_related_class,...
}}
related_name, related_query_nameはともに設定していないの...
で、遅延処理っぽいことが行われています。lazy_related_oper...
#code(Python){{
def lazy_related_operation(function, model, *related_mode...
"""
Schedule `function` to be called once `model` and all...
have been imported and registered with the app regist...
be called with the newly-loaded model classes as its ...
plus any optional keyword arguments.
The `model` argument must be a model class. Each subs...
argument is another model, or a reference to another ...
`resolve_relation()` for the various forms these may ...
references will be resolved relative to `model`.
This is a convenience wrapper for `Apps.lazy_model_op...
registry model used is the one found in `model._meta....
"""
models = [model] + [resolve_relation(model, rel) for ...
model_keys = (make_model_tuple(m) for m in models)
apps = model._meta.apps
return apps.lazy_model_operation(partial(function, **...
}}
まあコメントに書いてある通り全部のモデルが登録されたらfun...
+model_keysとして指定されているモデルを一つ取り出す(firs...
+firstのモデルがまだ登録されてないなら後回し(ちなみにmod...
+モデルが登録されているなら渡された関数に、そのモデルクラ...
+restを引数にして、lazy_model_operationを呼び出す
つまり、一つずつモデルクラスを引数として設定していくとい...
**RelatedField.contribute_to_related_class [#f0851c75]
さて、話をRelatedFieldに戻しましょう。なんやかんやでresol...
#code(Python){{
def do_related_class(self, other, cls):
self.set_attributes_from_rel()
self.contribute_to_related_class(other, self.remo...
}}
このうち、set_attributes_from_relは自分(今はChoiceクラス...
contribute_to_related_classはForeignKeyでも定義されていま...
#code(Python){{
def contribute_to_related_class(self, cls, related):
# Internal FK's - i.e., those with a related name...
# and swapped models don't get a related descript...
if not self.remote_field.is_hidden() and not rela...
setattr(cls._meta.concrete_model, related.get...
# While 'limit_choices_to' might be a callabl...
# it along for later - this is too early beca...
# model load time.
if self.remote_field.limit_choices_to:
cls._meta.related_fkey_lookups.append(sel...
}}
setattrの行が明らかに怪しいです。
related、その実体はreverse_relatedモジュールのManyToOneRe...
#code(Python){{
def get_accessor_name(self, model=None):
# This method encapsulates the logic that decides...
# accessor descriptor that retrieves related many...
# many-to-many objects. It uses the lower-cased o...
# but this can be overridden with the "related_na...
# Due to backwards compatibility ModelForms need ...
# an alternate model. See BaseInlineFormSet.get_d...
opts = model._meta if model else self.related_mod...
model = model or self.related_model
if self.multiple:
# If this is a symmetrical m2m relation on se...
if self.symmetrical and model == self.model:
return None
if self.related_name:
return self.related_name
return opts.model_name + ('_set' if self.multiple...
}}
個々に追いかけるのはやめますが、ともかくこれで'choice_set...
relatedモジュールに戻って、contribute_to_related_classの...
#code(Python){{
from .related_descriptors import (
ForwardManyToOneDescriptor, ManyToManyDescriptor,
ReverseManyToOneDescriptor, ReverseOneToOneDescriptor,
)
class ForeignObject(RelatedField):
related_accessor_class = ReverseManyToOneDescriptor
}}
です。つまり、choice_setとはデスクリプタのようです。
*django.db.models.fields.related_descriptors [#ib3f90aa]
さて、デスクリプタなので__get__を見てみます。
#code(Python){{
def __get__(self, instance, cls=None):
"""
Get the related objects through the reverse relat...
With the example above, when getting ``parent.chi...
- ``self`` is the descriptor managing the ``child...
- ``instance`` is the ``parent`` instance
- ``cls`` is the ``Parent`` class (unused)
"""
if instance is None:
return self
return self.related_manager_cls(instance)
}}
related_manager_cls。プロパティです。
#code(Python){{
@cached_property
def related_manager_cls(self):
related_model = self.rel.related_model
return create_reverse_many_to_one_manager(
related_model._default_manager.__class__,
self.rel,
)
}}
確認。self.relとはManyToOneRelで、related_modelとはChoice...
さて、create_reverse_many_to_one_managerです。
#code(Python){{
def create_reverse_many_to_one_manager(superclass, rel):
"""
Create a manager for the reverse side of a many-to-on...
This manager subclasses another manager, generally th...
the related model, and adds behaviors specific to man...
"""
class RelatedManager(superclass):
def __init__(self, instance):
super(RelatedManager, self).__init__()
self.instance = instance
self.model = rel.related_model
self.field = rel.field
self.core_filters = {self.field.name: instance}
# 省略
return RelatedManager
}}
なんの冗談?と思われるかもしれませんがマジです。動的にク...
*RelatedManager.create [#o63381f0]
さて、というわけでchoice_setの(__get__時の)正体がわかっ...
#code(Python){{
def create(self, **kwargs):
kwargs[self.field.name] = self.instance
db = router.db_for_write(self.model, instance...
return super(RelatedManager, self.db_manager(...
}}
self.fieldはChoiceのqustionフィールド、self.instanceはQue...
親クラス、というかQuerySetのcreateメソッドです。
#code(Python){{
def create(self, **kwargs):
"""
Creates a new object with the given kwargs, savin...
and returning the created object.
"""
obj = self.model(**kwargs)
self._for_write = True
obj.save(force_insert=True, using=self.db)
return obj
}}
というわけでChoiceモデルを作って保存する際に、ForeignKey...
ForeignKeyが相手のid取得するまで結構長いのだけど、めんど...
*おわりに [#ud94ae10]
今回は複数テーブルの関連、手始めにQuestionにいつの間にか...
Managerは動的に作られ、Questionのインスタンスと関連付けら...
SELECTについても同じようにQuestionインスタンスが設定され...
ページ名: