model定义时,每个field都是一个类属性,一个对象。在生成类时,属性有contribute_to_class的方法,会调用该方法。
m2m field,它会先调用自己的contribute_to_class,然后调用父类的contribute_to_class,因为m2m类是继承自relatfield,
def contribute_to_class(self, cls, name, virtual_only=False): super(RelatedField, self).contribute_to_class(cls, name, virtual_only=virtual_only)#在option添加一个field 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.remote_field.model = related field.do_related_class(related, model) lazy_related_operation(resolve_related_class, cls, self.remote_field.model, field=self)
def do_related_class(self, other, cls):#关键是调用这个函数时把两个model类调换了,model与related位置对调。 self.set_attributes_from_rel() self.contribute_to_related_class(other, self.remote_field) def lazy_related_operation(function, model, *related_models, **kwargs): """ Schedule `function` to be called once `model` and all `related_models` have been imported and registered with the app registry. `function` will be called with the newly-loaded model classes as its positional arguments, plus any optional keyword arguments. The `model` argument must be a model class. Each subsequent positional argument is another model, or a reference to another model - see `resolve_relation()` for the various forms these may take. Any relative references will be resolved relative to `model`. This is a convenience wrapper for `Apps.lazy_model_operation` - the app registry model used is the one found in `model._meta.apps`. """ models = [model] + [resolve_relation(model, rel) for rel in related_models] model_keys = (make_model_tuple(m) for m in models) apps = model._meta.apps return apps.lazy_model_operation(partial(function, **kwargs), *model_keys) def lazy_model_operation(self, function, *model_keys): """ Take a function and a number of ("app_label", "modelname") tuples, and when all the corresponding models have been imported and registered, call the function with the model classes as its arguments. The function passed to this method must accept exactly n models as arguments, where n=len(model_keys). """ # If this function depends on more than one model, we recursively turn # it into a chain of functions that accept a single model argument and # pass each in turn to lazy_model_operation. model_key, more_models = model_keys[0], model_keys[1:] if more_models: supplied_fn = function def function(model): next_function = partial(supplied_fn, model) # Annotate the function with its field for retrieval in # migrations.state.StateApps. if getattr(supplied_fn, 'keywords', None): next_function.field = supplied_fn.keywords.get('field') self.lazy_model_operation(next_function, *more_models) # If the model is already loaded, pass it to the function immediately. # Otherwise, delay execution until the class is prepared. try: model_class = self.get_registered_model(*model_key) except LookupError: self._pending_operations[model_key].append(function) else: function(model_class)