Exemple #1
0
 def _fill_related_objects_cache(self):
     cache = SortedDict()
     parent_list = self.get_parent_list()
     for parent in self.parents:
         for obj, model in parent._meta.get_all_related_objects_with_model(
                 include_hidden=True):
             if (obj.field.creation_counter < 0 or obj.field.rel.parent_link
                 ) and obj.model not in parent_list:
                 continue
             if not model:
                 cache[obj] = parent
             else:
                 cache[obj] = model
     # Collect also objects which are in relation to some proxy child/parent of self.
     proxy_cache = cache.copy()
     for klass in get_models(include_auto_created=True,
                             only_installed=False):
         for f in klass._meta.local_fields:
             if f.rel and not isinstance(f.rel.to, basestring):
                 if self == f.rel.to._meta:
                     cache[RelatedObject(f.rel.to, klass, f)] = None
                     proxy_cache[RelatedObject(f.rel.to, klass, f)] = None
                 elif self.concrete_model == f.rel.to._meta.concrete_model:
                     proxy_cache[RelatedObject(f.rel.to, klass, f)] = None
     self._related_objects_cache = cache
     self._related_objects_proxy_cache = proxy_cache
Exemple #2
0
    def _fill_related_objects_cache(self):
        cache = SortedDict()
        parent_list = self.get_parent_list()

        for parent in self.parents:
            for obj, model in parent._meta.get_all_related_objects_with_model(include_hidden=True):

                if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list:
                    continue

                if not model:
                    cache[obj] = parent
                else:
                    cache[obj] = model

        # Collect also objects which are in relation to some proxy child/parent of self.
        proxy_cache = cache.copy()
        for klass in get_models(include_auto_created=True, only_installed=False):
            if not klass._meta.swapped:
                # 遍历所有的表内属性
                for f in klass._meta.local_fields:
                    if f.rel and not isinstance(f.rel.to, six.string_types):
                        # 如果属性所关联的表是自己
                        if self == f.rel.to._meta:
                            cache[RelatedObject(f.rel.to, klass, f)] = None
                            proxy_cache[RelatedObject(f.rel.to, klass, f)] = None
                        # 关于 self.concrete_model 参见 self.__init__() 中的说明
                        elif self.concrete_model == f.rel.to._meta.concrete_model:
                            proxy_cache[RelatedObject(f.rel.to, klass, f)] = None
        # 从上面来看, cache 记录的是一个键为 RelatedObject, 值为 None 的映射. 而 RelatedObject 中记录了属性关联表的信息.
        self._related_objects_cache = cache
        self._related_objects_proxy_cache = proxy_cache
Exemple #3
0
    def post_through_setup(self, cls):
        if RelatedObject is not None:  # Django < 1.8
            self.related = RelatedObject(cls, self.model, self)

        self.use_gfk = (self.through is None or issubclass(
            self.through, CommonGenericTaggedItemBase))

        # rel.to renamed to remote_field.model in Django 1.9
        if VERSION >= (1, 9):
            if not self.remote_field.model:
                self.remote_field.model = self.through._meta.get_field(
                    "tag").remote_field.model
        else:
            if not self.rel.to:
                self.rel.to = self.through._meta.get_field("tag").rel.to

        if RelatedObject is not None:  # Django < 1.8
            self.related = RelatedObject(self.through, cls, self)

        if self.use_gfk:
            tagged_items = GenericRelation(self.through)
            tagged_items.contribute_to_class(cls, 'tagged_items')

        for rel in cls._meta.local_many_to_many:
            if rel == self or not isinstance(rel, TaggableManager):
                continue
            if rel.through == self.through:
                raise ValueError(
                    'You can\'t have two TaggableManagers with the'
                    ' same through model.')
Exemple #4
0
 def post_through_setup(self, cls):
     self.related = RelatedObject(cls, self.model, self)
     self.use_gfk = (self.through is None
                     or issubclass(self.through, GenericTaggedItemBase))
     self.rel.to = self.through._meta.get_field("tag").rel.to
     self.related = RelatedObject(self.through, cls, self)
     if self.use_gfk:
         tagged_items = GenericRelation(self.through)
         tagged_items.contribute_to_class(cls, "tagged_items")
Exemple #5
0
    def post_through_setup(self, cls):
        self.related = RelatedObject(cls, self.model, self)
        self.use_gfk = (
            self.through is None or issubclass(self.through, GenericTaggedItemBase)
        )
        self.rel.to = self.through._meta.get_field("tag").rel.to
        self.related = RelatedObject(self.through, cls, self)
        if self.use_gfk:
            tagged_items = GenericRelation(self.through)
            tagged_items.contribute_to_class(cls, 'tagged_items')

            for rel in cls._meta.local_many_to_many:
                if isinstance(rel, TaggableManager) and rel.use_gfk and rel != self:
                    raise ValueError('You can only have one TaggableManager per model'
                        ' using generic relations.')
Exemple #6
0
    def post_through_setup(self, cls):
        self.related = RelatedObject(cls, self.model, self)
        self.use_gfk = (self.through is None
                        or issubclass(self.through, GenericTaggedItemBase))
        self.rel.to = self.through._meta.get_field("tag").rel.to
        self.related = RelatedObject(self.through, cls, self)
        if self.use_gfk:
            tagged_items = GenericRelation(self.through)
            tagged_items.contribute_to_class(cls, 'tagged_items')

        for rel in cls._meta.local_many_to_many:
            if rel == self or not isinstance(rel, TaggableManager):
                continue
            if rel.through == self.through:
                raise ValueError(
                    'You can\'t have two TaggableManagers with the'
                    ' same through model.')
Exemple #7
0
 def get_all_related_many_to_many_objects(self):
     try:  # Try the cache first.
         return self._all_related_many_to_many_objects
     except AttributeError:
         rel_objs = []
         for klass in get_models():
             for f in klass._meta.many_to_many:
                 if f.rel and self == f.rel.to._meta:
                     rel_objs.append(RelatedObject(f.rel.to, klass, f))
         self._all_related_many_to_many_objects = rel_objs
         return rel_objs
Exemple #8
0
 def do_related_class(self, other, cls):
     field = self.get_field(other, cls)
     if not hasattr(self, 'related'):
         try:
             instance_type = cls.instance_type
         except AttributeError:  # when model is reconstituted for migration
             pass  # happens during migrations
         else:
             self.related = RelatedObject(other, instance_type, self)
     transform_field(field)
     field.rel = None
 def _fill_related_objects_cache(self):
     cache = SortedDict()
     parent_list = self.get_parent_list()
     for parent in self.parents:
         for obj, model in parent._meta.get_all_related_objects_with_model():
             if (obj.field.creation_counter < 0 or obj.field.rel.parent_link) and obj.model not in parent_list:
                 continue
             if not model:
                 cache[obj] = parent
             else:
                 cache[obj] = model
     for klass in get_models():
         for f in klass._meta.local_fields:
             if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
                 cache[RelatedObject(f.rel.to, klass, f)] = None
     self._related_objects_cache = cache
Exemple #10
0
 def _fill_related_many_to_many_cache(self):
     cache = SortedDict()
     parent_list = self.get_parent_list()
     for parent in self.parents:
         for obj, model in parent._meta.get_all_related_m2m_objects_with_model():
             if obj.field.creation_counter < 0 and obj.model not in parent_list:
                 continue
             if not model:
                 cache[obj] = parent
             else:
                 cache[obj] = model
     for klass in get_models(only_installed=False):
         for f in klass._meta.local_many_to_many:
             if f.rel and not isinstance(f.rel.to, six.string_types) and self == f.rel.to._meta:
                 cache[RelatedObject(f.rel.to, klass, f)] = None
     if app_cache_ready():
         self._related_many_to_many_cache = cache
     return cache
Exemple #11
0
 def _fill_related_many_to_many_cache(self):
     from django.db.models.loading import get_models, app_cache_ready
     from django.db.models.related import RelatedObject
     from django.utils.datastructures import SortedDict
     cache = SortedDict()
     parent_list = self.get_parent_list()
     for parent in self.parents:
         for obj, model in parent._meta.get_all_related_m2m_objects_with_model():
             if obj.field.creation_counter < 0 and obj.model not in parent_list:
                 continue
             if not model:
                 cache[obj] = parent
             else:
                 cache[obj] = model
     for klass in get_models():
         for f in klass._meta.local_many_to_many:
             if f.rel and not isinstance(f.rel.to, str) and self == f.rel.to._meta:
                 cache[RelatedObject(f.rel.to, klass, f)] = None
     if app_cache_ready():
         self._related_many_to_many_cache = cache
     return cache
Exemple #12
0
 def do_related_class(self, other, cls):
     self.set_attributes_from_rel()
     self.related = RelatedObject(other, cls, self)
     if not cls._meta.abstract:
         self.contribute_to_related_class(other, self.related)
Exemple #13
0
    def introspect_class(self, cls):
        bits = self.field.split(".")

        if len(bits) < 2:
            raise ValueError("Illegal path to foreign field")

        foreign_field = None

        related_models_chain = [cls]
        related_names_chain = []

        for bit in bits[:-1]:
            meta = related_models_chain[-1]._meta

            try:
                foreign_field = meta.get_field(bit)
            except models.FieldDoesNotExist:
                raise ValueError("Field '%s' does not exist" % bit)

            if isinstance(foreign_field, models.ForeignKey):
                if isinstance(foreign_field.rel.to, basestring):
                    raise ValueError(
                        "Model with name '%s' must be class instance not string"
                        % foreign_field.rel.to)

                related_name = foreign_field.rel.related_name
                if not related_name:
                    related_name = RelatedObject(
                        foreign_field.rel.to, related_models_chain[-1],
                        foreign_field).get_accessor_name()

                related_models_chain.append(foreign_field.rel.to)
                related_names_chain.append(related_name)
            else:
                raise ValueError("Foreign fields in path must be ForeignField"
                                 "instances except last. Got %s" %
                                 foreign_field.__name__)

        native = self.native
        if not native:
            field_name = bits[-1]
            try:
                native = deepcopy(
                    related_models_chain[-1]._meta.get_field(field_name))
                native.creation_counter = models.Field.creation_counter
                models.Field.creation_counter += 1
            except models.FieldDoesNotExist:
                raise ValueError("Leaf field '%s' does not exist" % field_name)

        def get_root_instances(instance, chain):
            attr = getattr(instance, chain.pop()).all()

            if chain:
                for obj in attr:
                    for inst in get_root_instances(obj, chain):
                        yield inst
            else:
                for obj in attr:
                    yield obj

        def get_leaf_instance(instance, chain):
            for bit in chain:
                instance = getattr(instance, bit)

            return instance

        self.internal_init(
            native=native,
            trigger=[
                dict(on=(models.signals.post_save, models.signals.post_delete),
                     sender_model=related_models_chain[-1],
                     do=lambda holder, foreign, signal: getattr(
                         foreign, bits[-1]),
                     field_holder_getter=lambda foreign: get_root_instances(
                         foreign, related_names_chain[:])),
                dict(
                    on=models.signals.pre_save,
                    sender_model=related_models_chain[0],
                    do=lambda holder, _, signal: get_leaf_instance(
                        holder, bits[:]),
                    commit=False,  # to prevent recursion `save` method call
                )
            ],
            update_method=dict(queryset=lambda holder: get_leaf_instance(
                holder, bits[:-1])  #FIXME: rename queryset
                               ))
Exemple #14
0
 def do_related_class(self, other, cls):
     self.set_attributes_from_rel()
     related = RelatedObject(other, cls, self)
     self.contribute_to_related_class(other, related)
Exemple #15
0
 def post_through_setup(self, cls):
     self.rel.to = self.through._meta.get_field("tag").rel.to
     self.related = RelatedObject(self.through, cls, self)