生成model类对象时,传入的每个field对象都会调用其contribute_to_class函数,生成对应的属性。
def contribute_to_class(self, cls, name, virtual_only=False): super(RelatedField, self).contribute_to_class(cls, name, virtual_only=virtual_only) self.opts = cls._meta if not cls._meta.abstract: if self.remote_field.related_name: related_name = force_text(self.remote_field.related_name) % { 'class': cls.__name__.lower(), 'app_label': cls._meta.app_label.lower() } self.remote_field.related_name = related_name def resolve_related_class(model, related, field):#如果是关联field的话,会对关联model产生动作 field.remote_field.model = related field.do_related_class(related, model) lazy_related_operation(resolve_related_class, cls, self.remote_field.model, field=self)
field.do_related_class(related, model):
def do_related_class(self, other, cls): self.set_attributes_from_rel() self.contribute_to_related_class(other, self.remote_field) def set_attributes_from_rel(self): self.name = ( self.name or (self.remote_field.model._meta.model_name + '_' + self.remote_field.model._meta.pk.name) ) if self.verbose_name is None: self.verbose_name = self.remote_field.model._meta.verbose_name self.remote_field.set_field_name()#设置了远程field的名字 def contribute_to_related_class(self, cls, related):#related为远程filed # Internal FK's - i.e., those with a related name ending with '+' - # and swapped models don't get a related descriptor. if not self.remote_field.is_hidden() and not related.related_model._meta.swapped:
#为关联model设置了一个属性:category = models.ForeignKey(Category, related_name='forums'
#Category.category_id的属性related_accessor_class,然后就可以调用related_accessor_class的
#add,remove等函数
setattr(cls, related.get_accessor_name(), self.related_accessor_class(related)) # While 'limit_choices_to' might be a callable, simply pass # it along for later - this is too early because it's still # model load time. if self.remote_field.limit_choices_to: cls._meta.related_fkey_lookups.append(self.remote_field.limit_choices_to)