def contribute_to_class(self, cls, name, **kwargs):
        # To support multiple relations to self, it's useful to have a non-None
        # related name on symmetrical relations for internal reasons. The
        # concept doesn't make a lot of sense externally ("you want me to
        # specify *what* on my non-reversible relation?!"), so we set it up
        # automatically. The funky name reduces the chance of an accidental
        # clash.
        if self.remote_field.symmetrical and (
                self.remote_field.model == "self" or self.remote_field.model == cls._meta.object_name):
            self.remote_field.related_name = "%s_rel_+" % name
        elif self.remote_field.is_hidden():
            # If the backwards relation is disabled, replace the original
            # related_name with one generated from the m2m field name. Django
            # still uses backwards relations internally and we need to avoid
            # clashes between multiple m2m fields with related_name == '+'.
            self.remote_field.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)

        super(ArrayManyToManyField, self).contribute_to_class(cls, name)

        if not cls._meta.abstract:
            setattr(cls, self.name, MultiReferenceDescriptor(self.remote_field, reverse=False))

            self.opts = cls._meta
            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)
Exemple #2
0
def make_model_sealable(model):
    """
    Replace forward fields descriptors by sealable ones and reverse fields
    descriptors attached to SealableModel subclasses as well.

    This function should be called on a third-party model once all apps are
    done loading models such as from an AppConfig.ready().
    """
    opts = model._meta
    for field in (opts.local_fields + opts.local_many_to_many +
                  opts.private_fields):
        make_descriptor_sealable(model, field.name)
        remote_field = field.remote_field
        if remote_field:
            # Use lazy_related_operation because lazy relationships might not
            # be resolved yet.
            lazy_related_operation(make_remote_field_descriptor_sealable,
                                   model,
                                   remote_field.model,
                                   remote_field=remote_field)
    # Non SealableModel subclasses won't have remote fields descriptors
    # attached to them made sealable so make sure to make locally defined
    # related objects sealable.
    if not issubclass(model, SealableModel):
        for related_object in opts.related_objects:
            make_descriptor_sealable(model, related_object.get_accessor_name())
    def contribute_to_class(self, cls, name, **kwargs):
        # To support multiple relations to self, it's useful to have a non-None
        # related name on symmetrical relations for internal reasons. The
        # concept doesn't make a lot of sense externally ("you want me to
        # specify *what* on my non-reversible relation?!"), so we set it up
        # automatically. The funky name reduces the chance of an accidental
        # clash.
        if self.remote_field.symmetrical and (
                self.remote_field.model == "self" or self.remote_field.model == cls._meta.object_name):
            self.remote_field.related_name = "%s_rel_+" % name
        elif self.remote_field.is_hidden():
            # If the backwards relation is disabled, replace the original
            # related_name with one generated from the m2m field name. Django
            # still uses backwards relations internally and we need to avoid
            # clashes between multiple m2m fields with related_name == '+'.
            self.remote_field.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)

        super(ArrayManyToManyField, self).contribute_to_class(cls, name)

        if not cls._meta.abstract:
            setattr(cls, self.name, MultiReferenceDescriptor(self.remote_field, reverse=False))

            self.opts = cls._meta
            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 contribute_to_class(self,
                            cls: Type[models.Model],
                            name: str,
                            private_only: bool = False) -> None:

        # pylint: disable=arguments-differ,unused-argument

        self.name = name
        self.attname = name
        self.model = cls
        cls._meta.add_field(self, private=False)
        setattr(
            cls,
            self.name,
            ReverseGenericManyToOneDescriptor(
                self.remote_field),  # type: ignore
        )

        self.opts = cls._meta
        if not cls._meta.abstract:

            def resolve_related_class(model, related, field):  # type: ignore
                field.remote_field.model = related
                field.do_related_class(related, model)

            lazy_related_operation(resolve_related_class,
                                   cls,
                                   self.remote_field.model,
                                   field=self)
Exemple #5
0
    def contribute_to_class(self, cls, name):
        self.set_attributes_from_name(name)
        self.model = cls
        self.opts = cls._meta

        cls._meta.add_field(self)
        setattr(cls, name, self)
        if not cls._meta.abstract:
            if isinstance(self.remote_field.model, str):

                def resolve_related_class(cls, model, field):
                    field.remote_field.model = model

                lazy_related_operation(resolve_related_class,
                                       cls,
                                       self.remote_field.model,
                                       field=self)
            if isinstance(self.through, str):

                def resolve_related_class(cls, model, field):
                    self.through = model
                    self.remote_field.through = model
                    self.post_through_setup(cls)

                lazy_related_operation(resolve_related_class,
                                       cls,
                                       self.through,
                                       field=self)
            else:
                self.post_through_setup(cls)
Exemple #6
0
    def contribute_to_class(self, cls, name, **kwargs):
        kwargs['private_only'] = True
        super().contribute_to_class(cls, name, **kwargs)
        self.model = cls
        # Disable the reverse relation for fields inherited by subclasses of a
        # model in multi-table inheritance. The reverse relation points to the
        # field of the base model.
        if self.mti_inherited:
            self.remote_field.related_name = '+'
            self.remote_field.related_query_name = None
        setattr(cls, self.name,
                ReverseGenericManyToOneDescriptor(self.remote_field))

        # Add get_RELATED_order() and set_RELATED_order() to the model this
        # field belongs to, if the model on the other end of this relation
        # is ordered with respect to its corresponding GenericForeignKey.
        if not cls._meta.abstract:

            def make_generic_foreign_order_accessors(related_model, model):
                if self._is_matching_generic_foreign_key(
                        model._meta.order_with_respect_to):
                    make_foreign_order_accessors(model, related_model)

            lazy_related_operation(make_generic_foreign_order_accessors,
                                   self.model, self.remote_field.model)
Exemple #7
0
    def contribute_to_class(self, cls, name, *args, **kwargs):
        super(DBToGitManyToManyField, self).contribute_to_class(cls, name, *args, **kwargs)
        setattr(cls, name, DBToGitManyToManyDescriptor(self))

        def resolve_related_class(model, related, field):
            field.target = related
            # TODO: Support backward relation
        lazy_related_operation(resolve_related_class, cls, self.to, field=self)
Exemple #8
0
def create_many_to_many_intermediary_model(field, klass):
    from django.db import models

    def set_managed(model, related, through):
        through._meta.managed = model._meta.managed or related._meta.managed

    to_model = resolve_relation(klass, field.remote_field.model)
    name = '%s_%s' % (klass._meta.object_name, field.name)
    lazy_related_operation(set_managed, klass, to_model, name)

    to = make_model_tuple(to_model)[1]
    from_ = klass._meta.model_name
    if to == from_:
        to = 'to_%s' % to
        from_ = 'from_%s' % from_

    meta = type(
        str('Meta'), (object, ), {
            'db_table': field._get_m2m_db_table(klass._meta),
            'auto_created': klass,
            'app_label': klass._meta.app_label,
            'db_tablespace': klass._meta.db_tablespace,
            'unique_together': (from_, to),
            'verbose_name': _('%(from)s-%(to)s relationship') % {
                'from': from_,
                'to': to
            },
            'verbose_name_plural': _('%(from)s-%(to)s relationships') % {
                'from': from_,
                'to': to
            },
            'apps': field.model._meta.apps,
        })
    # Construct and return the new class.
    return type(
        str(name), (models.Model, ), {
            'Meta':
            meta,
            '__module__':
            klass.__module__,
            from_:
            models.ForeignKey(
                klass,
                related_name='%s+' % name,
                db_tablespace=field.db_tablespace,
                db_constraint=field.remote_field.db_constraint,
                on_delete=DATABASE_CASCADE,
            ),
            to:
            models.ForeignKey(
                to_model,
                related_name='%s+' % name,
                db_tablespace=field.db_tablespace,
                db_constraint=field.remote_field.db_constraint,
                on_delete=DATABASE_CASCADE,
            )
        })
Exemple #9
0
def compat_add_lazy_relation(cls, field, relation, operation):
    if add_lazy_relation is not None:
        return add_lazy_relation(cls, field, relation, operation)

    # Rearrange args for new Apps.lazy_model_operation
    def function(local, related, field):
        return operation(field, related, local)

    lazy_related_operation(function, cls, relation, field=field)
def add_lazy_relation(cls, field, relation, operation):
    if _add_lazy_relation is not None:
        return _add_lazy_relation(cls, field, relation, operation)

    # Rearrange args for new Apps.lazy_model_operation
    def function(local, related, field):
        return operation(field, related, local)

    lazy_related_operation(function, cls, relation, field=field)
Exemple #11
0
 def contribute_to_class(self, cls, name):
     super(PolymorphicTypeField, self).contribute_to_class(cls, name)
     polymorphic_type = self.polymorphic_type
     if (isinstance(polymorphic_type, string_types) or
             polymorphic_type._meta.pk is None):
         def resolve_polymorphic_type(model, related_model, field):
             field.do_polymorphic_type(related_model)
         lazy_related_operation(resolve_polymorphic_type, cls, polymorphic_type, field=self)
     else:
         self.do_polymorphic_type(polymorphic_type)
Exemple #12
0
 def contribute_to_class(self, cls, name):
     super(PolymorphicTypeField, self).contribute_to_class(cls, name)
     polymorphic_type = self.polymorphic_type
     if (isinstance(polymorphic_type, string_types) or
             polymorphic_type._meta.pk is None):
         def resolve_polymorphic_type(model, related_model, field):
             field.do_polymorphic_type(related_model)
         lazy_related_operation(resolve_polymorphic_type, cls, polymorphic_type, field=self)
     else:
         self.do_polymorphic_type(polymorphic_type)
Exemple #13
0
    def contribute_to_class(self, cls, name):
        if VERSION < (1, 7):
            self.name = self.column = self.attname = name
        else:
            self.set_attributes_from_name(name)
        self.model = cls
        self.opts = cls._meta

        cls._meta.add_field(self)
        setattr(cls, name, self)
        if not cls._meta.abstract:
            # rel.to renamed to remote_field.model in Django 1.9
            if VERSION >= (1, 9):
                if isinstance(self.remote_field.model, six.string_types):

                    def resolve_related_class(cls, model, field):
                        field.remote_field.model = model

                    lazy_related_operation(resolve_related_class,
                                           cls,
                                           self.remote_field.model,
                                           field=self)
            else:
                if isinstance(self.rel.to, six.string_types):

                    def resolve_related_class(field, model, cls):
                        field.rel.to = model

                    add_lazy_relation(cls, self, self.rel.to,
                                      resolve_related_class)

            if isinstance(self.through, six.string_types):
                if VERSION >= (1, 9):

                    def resolve_related_class(cls, model, field):
                        self.through = model
                        self.remote_field.through = model
                        self.post_through_setup(cls)

                    lazy_related_operation(resolve_related_class,
                                           cls,
                                           self.through,
                                           field=self)
                else:

                    def resolve_related_class(field, model, cls):
                        self.through = model
                        _remote_field(self).through = model
                        self.post_through_setup(cls)

                    add_lazy_relation(cls, self, self.through,
                                      resolve_related_class)
            else:
                self.post_through_setup(cls)
    def contribute_to_class(self, cls, name, private_only=False, **kwargs):
        self.set_attributes_from_name(name)
        self.model = cls
        self.opts = cls._meta

        if not cls._meta.abstract:
            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)
        setattr(cls, self.name, self.forward_related_accessor_class(self))
Exemple #15
0
    def contribute_to_class(self, cls, name, *args, **kwargs):
        super(GitToGitForeignKey, self).contribute_to_class(cls, name)
        setattr(cls, self.name, self.forward_descriptor(self))

        def resolve_related_class(model, related, field):
            field.target = related
            field.do_related_class(related, model)

        lazy_related_operation(resolve_related_class,
                               cls,
                               self.target,
                               field=self)
Exemple #16
0
def create_sortable_many_to_many_intermediary_model(field, klass, sort_field_name, base_classes=None):
    def set_managed(model, related, through):
        through._meta.managed = model._meta.managed or related._meta.managed

    to_model = resolve_relation(klass, field.remote_field.model)
    name = '%s_%s' % (klass._meta.object_name, field.name)
    lazy_related_operation(set_managed, klass, to_model, name)
    base_classes = base_classes if base_classes else (models.Model,)

    # TODO : use autoincrement here ?
    sort_field = models.IntegerField(default=0)

    to = make_model_tuple(to_model)[1]
    from_ = klass._meta.model_name
    if to == from_:
        to = 'to_%s' % to
        from_ = 'from_%s' % from_

    meta = type('Meta', (), {
        'db_table': field._get_m2m_db_table(klass._meta),  # pylint: disable=protected-access
        'auto_created': klass,
        'app_label': klass._meta.app_label,
        'db_tablespace': klass._meta.db_tablespace,
        'unique_together': (from_, to),
        'ordering': (sort_field_name,),
        'verbose_name': _('%(from)s-%(to)s relationship') % {'from': from_, 'to': to},
        'verbose_name_plural': _('%(from)s-%(to)s relationships') % {'from': from_, 'to': to},
        'apps': field.model._meta.apps,
    })

    # Construct and return the new class.
    return type(force_str(name), base_classes, {
        'Meta': meta,
        '__module__': klass.__module__,
        from_: models.ForeignKey(
            klass,
            related_name='%s+' % name,
            db_tablespace=field.db_tablespace,
            db_constraint=field.remote_field.db_constraint,
            on_delete=models.CASCADE,
        ),
        to: models.ForeignKey(
            to_model,
            related_name='%s+' % name,
            db_tablespace=field.db_tablespace,
            db_constraint=field.remote_field.db_constraint,
            on_delete=models.CASCADE,
        ),
        # Sort fields
        sort_field_name: sort_field,
        '_sort_field_name': sort_field_name,
    })
Exemple #17
0
    def contribute_to_class(self):
        if isinstance(self.model, str) or self.model._meta.pk is None:

            def resolve_related_class(cls, model, rel):
                rel.model = model
                rel.do_related_class()

            lazy_related_operation(resolve_related_class,
                                   self.field.model,
                                   self.model,
                                   rel=self)
        else:
            self.do_related_class()
Exemple #18
0
    def contribute_to_class(self, cls, name):
        super(ImplicitRoleField, self).contribute_to_class(cls, name)
        setattr(cls, self.name, ImplicitRoleDescriptor(self))

        if not hasattr(cls, '__implicit_role_fields'):
            setattr(cls, '__implicit_role_fields', [])
        getattr(cls, '__implicit_role_fields').append(self)

        post_save.connect(self._post_save, cls, True, dispatch_uid='implicit-role-post-save')
        post_delete.connect(self._post_delete, cls, True, dispatch_uid='implicit-role-post-delete')

        function = lambda local, related, field: self.bind_m2m_changed(field, related, local)
        lazy_related_operation(function, cls, "self", field=self)
Exemple #19
0
    def contribute_to_class(self, cls, name, **kwargs):
        # To support multiple relations to self, it's useful to have a non-None
        # related name on symmetrical relations for internal reasons. The
        # concept doesn't make a lot of sense externally ("you want me to
        # specify *what* on my non-reversible relation?!"), so we set it up
        # automatically. The funky name reduces the chance of an accidental
        # clash.
        if self.remote_field.symmetrical and (self.remote_field.model == "self"
                                              or self.remote_field.model
                                              == cls._meta.object_name):
            self.remote_field.related_name = "%s_rel_+" % name
        elif self.remote_field.is_hidden():
            # If the backwards relation is disabled, replace the original
            # related_name with one generated from the m2m field name. Django
            # still uses backwards relations internally and we need to avoid
            # clashes between multiple m2m fields with related_name == '+'.
            self.remote_field.related_name = "_%s_%s_+" % (
                cls.__name__.lower(), name)

        super(models.ManyToManyField,
              self).contribute_to_class(cls, name, **kwargs)

        # The intermediate m2m model is not auto created if:
        #  1) There is a manually specified intermediate, or
        #  2) The class owning the m2m field is abstract.
        #  3) The class owning the m2m field has been swapped out.
        if not cls._meta.abstract:
            if self.remote_field.through:

                def resolve_through_model(_, model, field):
                    field.remote_field.through = model

                lazy_related_operation(resolve_through_model,
                                       cls,
                                       self.remote_field.through,
                                       field=self)
            elif not cls._meta.swapped:
                using_db = self.db_list_for_read.first(
                ).get_name if self.db_list_for_read else None

                self.remote_field.through = create_Sharded_many_to_many_intermediary_model(
                    self, cls, db=using_db)

        # Add the descriptor for the m2m relation.
        #print(CustomManyToManyDescriptor(self.remote_field, reverse=False))
        setattr(cls, self.name,
                ManyToManyDescriptor(self.remote_field, reverse=False))

        # Set up the accessor for the m2m table name for the relation.
        self.m2m_db_table = partial(self._get_m2m_db_table, cls._meta)
Exemple #20
0
    def contribute_to_class(self, cls, name):
        self.set_attributes_from_name(name)
        self.model = cls
        self.opts = cls._meta

        cls._meta.add_field(self)
        setattr(cls, name, self)
        if not cls._meta.abstract:
            if self.remote_field.related_name:
                related_name = self.remote_field.related_name
            else:
                related_name = self.opts.default_related_name
            if related_name:
                related_name = related_name % {
                    "class": cls.__name__.lower(),
                    "model_name": cls._meta.model_name.lower(),
                    "app_label": cls._meta.app_label.lower(),
                }
                self.remote_field.related_name = related_name

            if self.remote_field.related_query_name:
                related_query_name = self.remote_field.related_query_name % {
                    "class": cls.__name__.lower(),
                    "app_label": cls._meta.app_label.lower(),
                }
                self.remote_field.related_query_name = related_query_name

            if isinstance(self.remote_field.model, str):

                def resolve_related_class(cls, model, field):
                    field.remote_field.model = model

                lazy_related_operation(resolve_related_class,
                                       cls,
                                       self.remote_field.model,
                                       field=self)
            if isinstance(self.through, str):

                def resolve_related_class(cls, model, field):
                    self.through = model
                    self.remote_field.through = model
                    self.post_through_setup(cls)

                lazy_related_operation(resolve_related_class,
                                       cls,
                                       self.through,
                                       field=self)
            else:
                self.post_through_setup(cls)
Exemple #21
0
    def contribute_to_class(self, cls, name, **kwargs):
        kwargs['private_only'] = True
        super(GenericRelation, self).contribute_to_class(cls, name, **kwargs)
        self.model = cls
        setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field))

        # Add get_RELATED_order() and set_RELATED_order() to the model this
        # field belongs to, if the model on the other end of this relation
        # is ordered with respect to its corresponding GenericForeignKey.
        if not cls._meta.abstract:

            def make_generic_foreign_order_accessors(related_model, model):
                if self._is_matching_generic_foreign_key(model._meta.order_with_respect_to):
                    make_foreign_order_accessors(model, related_model)

            lazy_related_operation(make_generic_foreign_order_accessors, self.model, self.remote_field.model)
Exemple #22
0
    def contribute_to_class(self, cls, name, **kwargs):
        kwargs['private_only'] = True
        super().contribute_to_class(cls, name, **kwargs)
        self.model = cls
        setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field))

        # Add get_RELATED_order() and set_RELATED_order() to the model this
        # field belongs to, if the model on the other end of this relation
        # is ordered with respect to its corresponding GenericForeignKey.
        if not cls._meta.abstract:

            def make_generic_foreign_order_accessors(related_model, model):
                if self._is_matching_generic_foreign_key(model._meta.order_with_respect_to):
                    make_foreign_order_accessors(model, related_model)

            lazy_related_operation(make_generic_foreign_order_accessors, self.model, self.remote_field.model)
Exemple #23
0
    def contribute_to_class(self, cls, name, virtual_only=True):
        self.set_attributes_from_name(name)
        self.model = cls
        if virtual_only:
            cls._meta.add_field(self, virtual=True)
        else:
            cls._meta.add_field(self)
        if self.choices:
            setattr(cls, 'get_%s_display' % self.name,
                    curry(cls._get_FIELD_display, field=self))
        setattr(cls, self.name, self.forward_descriptor(self))

        def resolve_related_class(model, related, field):
            field.target = related
            field.do_related_class(related, model)

        lazy_related_operation(resolve_related_class, cls, self.target, field=self)
Exemple #24
0
def create_many_to_many_intermediary_model(field, klass):
    from django.db import models

    def set_managed(model, related, through):
        through._meta.managed = model._meta.managed or related._meta.managed

    to_model = resolve_relation(klass, field.remote_field.model)
    name = '%s_%s' % (klass._meta.object_name, field.name)
    lazy_related_operation(set_managed, klass, to_model, name)

    to = make_model_tuple(to_model)[1]
    from_ = klass._meta.model_name
    if to == from_:
        to = 'to_%s' % to
        from_ = 'from_%s' % from_

    meta = type(str('Meta'), (object,), {
        'db_table': field._get_m2m_db_table(klass._meta),
        'auto_created': klass,
        'app_label': klass._meta.app_label,
        'db_tablespace': klass._meta.db_tablespace,
        'unique_together': (from_, to),
        'verbose_name': _('%(from)s-%(to)s relationship') % {'from': from_, 'to': to},
        'verbose_name_plural': _('%(from)s-%(to)s relationships') % {'from': from_, 'to': to},
        'apps': field.model._meta.apps,
    })
    # Construct and return the new class.
    return type(str(name), (models.Model,), {
        'Meta': meta,
        '__module__': klass.__module__,
        from_: models.ForeignKey(
            klass,
            related_name='%s+' % name,
            db_tablespace=field.db_tablespace,
            db_constraint=field.remote_field.db_constraint,
            on_delete=DATABASE_CASCADE,
        ),
        to: models.ForeignKey(
            to_model,
            related_name='%s+' % name,
            db_tablespace=field.db_tablespace,
            db_constraint=field.remote_field.db_constraint,
            on_delete=DATABASE_CASCADE,
        )
    })
    def contribute_to_class(self, cls, name, **kwargs):
        if not self.sorted:
            return super(SortedManyToManyField,
                         self).contribute_to_class(cls, name, **kwargs)

        # To support multiple relations to self, it's useful to have a non-None
        # related name on symmetrical relations for internal reasons. The
        # concept doesn't make a lot of sense externally ("you want me to
        # specify *what* on my non-reversible relation?!"), so we set it up
        # automatically. The funky name reduces the chance of an accidental
        # clash.
        rel = get_rel(self)

        if rel.symmetrical and (rel.model == "self"
                                or rel.model == cls._meta.object_name):
            rel.related_name = "%s_rel_+" % name
        elif rel.is_hidden():
            # If the backwards relation is disabled, replace the original
            # related_name with one generated from the m2m field name. Django
            # still uses backwards relations internally and we need to avoid
            # clashes between multiple m2m fields with related_name == '+'.
            rel.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)

        # pylint: disable=bad-super-call
        super(_ManyToManyField, self).contribute_to_class(cls, name, **kwargs)

        # The intermediate m2m model is not auto created if:
        #  1) There is a manually specified intermediate, or
        #  2) The class owning the m2m field is abstract.
        #  3) The class owning the m2m field has been swapped out.
        if not cls._meta.abstract:
            if rel.through:

                def resolve_through_model(_, model):
                    rel.through = model

                lazy_related_operation(resolve_through_model, cls, rel.through)
            elif not cls._meta.swapped:
                rel.through = self.create_intermediate_model(cls)

        # Add the descriptor for the m2m relation
        setattr(cls, self.name, SortedManyToManyDescriptor(self))

        # Set up the accessor for the m2m table name for the relation
        self.m2m_db_table = partial(self._get_m2m_db_table, cls._meta)  # pylint: disable=attribute-defined-outside-init
Exemple #26
0
    def contribute_to_class(self, cls, name):
        if VERSION < (1, 7):
            self.name = self.column = self.attname = name
        else:
            self.set_attributes_from_name(name)
        self.model = cls
        self.opts = cls._meta

        cls._meta.add_field(self)
        setattr(cls, name, self)
        if not cls._meta.abstract:
            # rel.to renamed to remote_field.model in Django 1.9
            if VERSION >= (1, 9):
                if isinstance(self.remote_field.model, six.string_types):
                    def resolve_related_class(cls, model, field):
                        field.remote_field.model = model
                    lazy_related_operation(
                        resolve_related_class, cls, self.remote_field.model, field=self
                    )
            else:
                if isinstance(self.rel.to, six.string_types):
                    def resolve_related_class(field, model, cls):
                        field.rel.to = model
                    add_lazy_relation(cls, self, self.rel.to, resolve_related_class)

            if isinstance(self.through, six.string_types):
                if VERSION >= (1, 9):
                    def resolve_related_class(cls, model, field):
                        self.through = model
                        self.remote_field.through = model
                        self.post_through_setup(cls)
                    lazy_related_operation(
                        resolve_related_class, cls, self.through, field=self
                    )
                else:
                    def resolve_related_class(field, model, cls):
                        self.through = model
                        _remote_field(self).through = model
                        self.post_through_setup(cls)
                    add_lazy_relation(
                        cls, self, self.through, resolve_related_class
                    )
            else:
                self.post_through_setup(cls)
    def setup(self, this_model):
        super(DependOnRelated, self).setup(this_model)

        # FIXME: this should not be necessary
        if self.other_model == related.RECURSIVE_RELATIONSHIP_CONSTANT:
            self.other_model = self.this_model

        if isinstance(self.other_model, six.string_types):
            # if ``other_model`` is a string, it certainly is a lazy relation.
            try:
                def function(local, related, field):
                    return self.resolved_model(field, related, local)

                related.lazy_related_operation(function, self.this_model, self.other_model, field=None)
            except AttributeError:  # Django<2.0
                related.add_lazy_relation(self.this_model, None, self.other_model, self.resolved_model)
        else:
            # otherwise it can be resolved directly
            self.resolved_model(None, self.other_model, None)
Exemple #28
0
    def contribute_to_class(self, cls, name, **kwargs):
        kwargs['private_only'] = True
        super(GenericRelation, self).contribute_to_class(cls, name, **kwargs)
        self.model = cls
        setattr(cls, self.name,
                ReverseGenericManyToOneDescriptor(self.remote_field))

        # Add get_RELATED_order() and set_RELATED_order() methods if the model
        # on the other end of this relation is ordered with respect to this.
        def matching_gfk(field):
            return (isinstance(field, GenericForeignKey)
                    and self.content_type_field_name == field.ct_field
                    and self.object_id_field_name == field.fk_field)

        def make_generic_foreign_order_accessors(related_model, model):
            if matching_gfk(model._meta.order_with_respect_to):
                make_foreign_order_accessors(model, related_model)

        lazy_related_operation(make_generic_foreign_order_accessors,
                               self.model, self.remote_field.model)
Exemple #29
0
    def contribute_to_class(self, cls, name, **kwargs):
        kwargs['virtual_only'] = True
        super(GenericRelation, self).contribute_to_class(cls, name, **kwargs)
        self.model = cls
        setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field))

        # Add get_RELATED_order() and set_RELATED_order() methods if the model
        # on the other end of this relation is ordered with respect to this.
        def matching_gfk(field):
            return (
                isinstance(field, GenericForeignKey) and
                self.content_type_field_name == field.ct_field and
                self.object_id_field_name == field.fk_field
            )

        def make_generic_foreign_order_accessors(related_model, model):
            if matching_gfk(model._meta.order_with_respect_to):
                make_foreign_order_accessors(model, related_model)

        lazy_related_operation(make_generic_foreign_order_accessors, self.model, self.remote_field.model)
Exemple #30
0
    def _prepare(cls):
        """Create some methods once self._meta has been populated."""
        opts = cls._meta
        opts._prepare(cls)

        if opts.order_with_respect_to:
            cls.get_next_in_order = partialmethod(
                cls._get_next_or_previous_in_order, is_next=True)
            cls.get_previous_in_order = partialmethod(
                cls._get_next_or_previous_in_order, is_next=False)

            # Defer creating accessors on the foreign class until it has been
            # created and registered. If remote_field is None, we're ordering
            # with respect to a GenericForeignKey and don't know what the
            # foreign class is - we'll add those accessors later in
            # contribute_to_class().
            if opts.order_with_respect_to.remote_field:
                wrt = opts.order_with_respect_to
                remote = wrt.remote_field.model
                lazy_related_operation(make_foreign_order_accessors, cls,
                                       remote)

        # Give the class a docstring -- its definition.
        if cls.__doc__ is None:
            cls.__doc__ = "%s(%s)" % (cls.__name__, ", ".join(
                f.name for f in opts.fields))

        get_absolute_url_override = settings.ABSOLUTE_URL_OVERRIDES.get(
            opts.label_lower)
        if get_absolute_url_override:
            setattr(cls, 'get_absolute_url', get_absolute_url_override)

        # Set the name of _meta.indexes. This can't be done in
        # Options.contribute_to_class() because fields haven't been added to
        # the model at that point.
        for index in cls._meta.indexes:
            if not index.name:
                index.set_name_with_model(cls)

        class_prepared.send(sender=cls)
Exemple #31
0
    def contribute_to_class(self, cls, name, **kwargs):
        kwargs['private_only'] = True
        super().contribute_to_class(cls, name, **kwargs)
        self.model = cls
        # Disable the reverse relation for fields inherited by subclasses of a
        # model in multi-table inheritance. The reverse relation points to the
        # field of the base model.
        if self.mti_inherited:
            self.remote_field.related_name = '+'
            self.remote_field.related_query_name = None
        setattr(cls, self.name, ReverseGenericManyToOneDescriptor(self.remote_field))

        # Add get_RELATED_order() and set_RELATED_order() to the model this
        # field belongs to, if the model on the other end of this relation
        # is ordered with respect to its corresponding GenericForeignKey.
        if not cls._meta.abstract:

            def make_generic_foreign_order_accessors(related_model, model):
                if self._is_matching_generic_foreign_key(model._meta.order_with_respect_to):
                    make_foreign_order_accessors(model, related_model)

            lazy_related_operation(make_generic_foreign_order_accessors, self.model, self.remote_field.model)
Exemple #32
0
    def contribute_to_class(self, cls, name, **kwargs):
            # To support multiple relations to self, it's useful to have a non-None
            # related name on symmetrical relations for internal reasons. The
            # concept doesn't make a lot of sense externally ("you want me to
            # specify *what* on my non-reversible relation?!"), so we set it up
            # automatically. The funky name reduces the chance of an accidental
            # clash.
            if self.remote_field.symmetrical and (
                    self.remote_field.model == "self" or self.remote_field.model == cls._meta.object_name):
                self.remote_field.related_name = "%s_rel_+" % name
            elif self.remote_field.is_hidden():
                # If the backwards relation is disabled, replace the original
                # related_name with one generated from the m2m field name. Django
                # still uses backwards relations internally and we need to avoid
                # clashes between multiple m2m fields with related_name == '+'.
                self.remote_field.related_name = "_%s_%s_+" % (cls.__name__.lower(), name)

            super(models.ManyToManyField, self).contribute_to_class(cls, name, **kwargs)

            # The intermediate m2m model is not auto created if:
            #  1) There is a manually specified intermediate, or
            #  2) The class owning the m2m field is abstract.
            #  3) The class owning the m2m field has been swapped out.
            if not cls._meta.abstract:
                if self.remote_field.through:
                    def resolve_through_model(_, model, field):
                        field.remote_field.through = model
                    lazy_related_operation(resolve_through_model, cls, self.remote_field.through, field=self)
                elif not cls._meta.swapped:
                    self.remote_field.through = create_many_to_many_intermediary_model(self, cls)

            # Add the descriptor for the m2m relation.
            setattr(cls, self.name, ManyToManyDescriptor(self.remote_field, reverse=False))

            # Set up the accessor for the m2m table name for the relation.
            self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)
Exemple #33
0
    def create_versioned_many_to_many_intermediary_model(
            field, cls, field_name):
        # TODO: Verify functionality against
        # django.db.models.fields.related:1048
        # Let's not care too much on what flags could potentially be set on
        #   that intermediary class (e.g. managed, etc)
        # Let's play the game, as if the programmer had specified a class
        #   within his models... Here's how.

        # FIXME: VersionedManyToManyModels do not get registered in the
        #   apps models.
        # FIXME: This is usually done at django/db/models/base.py:284,
        # invoked by create_many_to_many_intermediary_model at
        #   django.db.models.fields.related:1048

        def set_managed(model, related, through):
            through._meta.managed = model._meta.managed or \
                                    related._meta.managed

        to_model = resolve_relation(cls, field.remote_field.model)

        name = '%s_%s' % (cls._meta.object_name, field_name)
        lazy_related_operation(set_managed, cls, to_model, name)

        # Force 'to' to be a string (and leave the hard work to Django)
        to = make_model_tuple(to_model)[1]
        from_ = cls._meta.model_name
        if to == from_:
            from_ = 'from_%s' % from_
            to = 'to_%s' % to

        meta = type(
            'Meta',
            (object, ),
            {
                'db_table': field._get_m2m_db_table(cls._meta),
                'auto_created': cls,
                'app_label': cls._meta.app_label,
                'db_tablespace': cls._meta.db_tablespace,
                # 'unique_together' is not applicable as is, due to multiple
                #   versions to be allowed to exist.
                # 'unique_together': (from_, to),
                'verbose_name': '%(from)s-%(to)s relationship' % {
                    'from': from_,
                    'to': to
                },
                'verbose_name_plural': '%(from)s-%(to)s relationships' % {
                    'from': from_,
                    'to': to
                },
                'apps': field.model._meta.apps,
            })
        return type(
            str(name), (Versionable, ), {
                'Meta':
                meta,
                '__module__':
                cls.__module__,
                from_:
                VersionedForeignKey(
                    cls,
                    related_name='%s+' % name,
                    db_tablespace=field.db_tablespace,
                    db_constraint=field.remote_field.db_constraint,
                    auto_created=name,
                    on_delete=DO_NOTHING,
                ),
                to:
                VersionedForeignKey(
                    to_model,
                    related_name='%s+' % name,
                    db_tablespace=field.db_tablespace,
                    db_constraint=field.remote_field.db_constraint,
                    auto_created=name,
                    on_delete=DO_NOTHING,
                ),
            })
Exemple #34
0
def add_lazy_relation(cls, field, relation, operation):
    # Rearrange args for new Apps.lazy_model_operation
    def function(local, related, field):
        return operation(field, related, local)

    lazy_related_operation(function, cls, relation, field=field)
Exemple #35
0
    def contribute_to_class(self, cls, virtual_only=False):

        # Connect the descriptor for this field
        setattr(cls, self.field.attname, SourceGM2MDescriptor(self.field))

        if cls._meta.abstract or cls._meta.swapped:
            # do not do anything for abstract or swapped model classes
            return

        if not self.through:
            self.set_init('through',
                          create_gm2m_intermediary_model(self.field, cls))
            # we set through_fields to the default intermediary model's
            # THROUGH_FIELDS as it carries fields assignments for
            # ModelState instances
            self.set_init('through_fields', THROUGH_FIELDS)

        # set related name
        if not self.field.model._meta.abstract and self.related_name:
            self.set_init(
                'related_name', self.related_name % {
                    'class': self.field.model.__name__.lower(),
                    'app_label': self.field.model._meta.app_label.lower()
                })

        def calc_field_names(rel):
            # Extract field names from through model and stores them in
            # rel.through_field (so that they are sent on deconstruct and
            # passed to ModelState instances)

            tf_dict = {}

            if is_fake_model(rel.through):
                # we populate the through field dict using rel.through_fields
                # that was either provided or computed beforehand with the
                # actual model
                for f, k in zip(rel.through_fields,
                                ('src', 'tgt', 'tgt_ct', 'tgt_fk')):
                    tf_dict[k] = f
                rel.through._meta._field_names = tf_dict
                return

            if rel.through_fields:
                tf_dict['src'], tf_dict['tgt'] = \
                    rel.through_fields[:2]
                for gfk in rel.through._meta.private_fields:
                    if gfk.name == tf_dict['tgt']:
                        break
                else:
                    raise FieldDoesNotExist(
                        'Generic foreign key "%s" does not exist in through '
                        'model "%s"' %
                        (tf_dict['tgt'], rel.through._meta.model_name))
                tf_dict['tgt_ct'] = gfk.ct_field
                tf_dict['tgt_fk'] = gfk.fk_field
            else:
                for f in rel.through._meta.fields:
                    try:
                        remote_field = f.remote_field
                    except AttributeError:
                        continue
                    if remote_field and (remote_field.model == rel.field.model
                                         or remote_field.model == '%s.%s' %
                                         (rel.field.model._meta.app_label,
                                          rel.field.model._meta.object_name)):
                        tf_dict['src'] = f.name
                        break
                for f in rel.through._meta.private_fields:
                    if isinstance(f, ct.GenericForeignKey):
                        tf_dict['tgt'] = f.name
                        tf_dict['tgt_ct'] = f.ct_field
                        tf_dict['tgt_fk'] = f.fk_field
                        break

            if not set(tf_dict.keys()).issuperset(('src', 'tgt')):
                raise ValueError('Bad through model for GM2M relationship.')

            rel.through._meta._field_names = tf_dict

            # save the result in rel.through_fields so that it appears
            # in the deconstruction. Without that there would be no way for
            # a ModelState constructed from a migration to know which fields
            # have which function, as all virtual fields are stripped
            tf = []
            for f in ('src', 'tgt', 'tgt_ct', 'tgt_fk'):
                tf.append(tf_dict[f])
            rel.set_init('through_fields', tf)

        # resolve through model if it's provided as a string
        if isinstance(self.through, str):

            def resolve_through_model(c, model, r):
                r.set_init('through', model)
                calc_field_names(r)

            lazy_related_operation(resolve_through_model,
                                   cls,
                                   self.through,
                                   r=self)
        else:
            calc_field_names(self)

        self.related_model = cls

        for rel in self.rels:
            # we need to make sure the GM2MUnitRel's field instance is the
            # right one. Indeed, if cls is derived from an abstract model
            # where the GM2MField is defined, rel.field is the field linked
            # to the abstract model
            rel.field = self.field
            rel.contribute_to_class()
Exemple #36
0
    def create_versioned_many_to_many_intermediary_model(field, cls,
                                                         field_name):
        # TODO: Verify functionality against
        # django.db.models.fields.related:1048
        # Let's not care too much on what flags could potentially be set on
        #   that intermediary class (e.g. managed, etc)
        # Let's play the game, as if the programmer had specified a class
        #   within his models... Here's how.

        # FIXME: VersionedManyToManyModels do not get registered in the
        #   apps models.
        # FIXME: This is usually done at django/db/models/base.py:284,
        # invoked by create_many_to_many_intermediary_model at
        #   django.db.models.fields.related:1048

        def set_managed(model, related, through):
            through._meta.managed = model._meta.managed or \
                                    related._meta.managed

        to_model = resolve_relation(cls, field.remote_field.model)

        name = '%s_%s' % (cls._meta.object_name, field_name)
        lazy_related_operation(set_managed, cls, to_model, name)

        # Force 'to' to be a string (and leave the hard work to Django)
        to = make_model_tuple(to_model)[1]
        from_ = cls._meta.model_name
        if to == from_:
            from_ = 'from_%s' % from_
            to = 'to_%s' % to

        meta = type('Meta', (object,), {
            'db_table': field._get_m2m_db_table(cls._meta),
            'auto_created': cls,
            'app_label': cls._meta.app_label,
            'db_tablespace': cls._meta.db_tablespace,
            # 'unique_together' is not applicable as is, due to multiple
            #   versions to be allowed to exist.
            # 'unique_together': (from_, to),
            'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_,
                                                              'to': to},
            'verbose_name_plural': '%(from)s-%(to)s relationships' % {
                'from': from_, 'to': to},
            'apps': field.model._meta.apps,
        })
        return type(str(name), (Versionable,), {
            'Meta': meta,
            '__module__': cls.__module__,
            from_: VersionedForeignKey(
                cls,
                related_name='%s+' % name,
                db_tablespace=field.db_tablespace,
                db_constraint=field.remote_field.db_constraint,
                auto_created=name,
                on_delete=DO_NOTHING,
            ),
            to: VersionedForeignKey(
                to_model,
                related_name='%s+' % name,
                db_tablespace=field.db_tablespace,
                db_constraint=field.remote_field.db_constraint,
                auto_created=name,
                on_delete=DO_NOTHING,
            ),
        })
from __future__ import unicode_literals
Exemple #38
0
def create_sortable_many_to_many_intermediary_model(
    field, klass, sort_field_name, base_classes=None
):
    def set_managed(model, related, through):
        through._meta.managed = model._meta.managed or related._meta.managed

    to_model = resolve_relation(klass, field.remote_field.model)
    name = "%s_%s" % (klass._meta.object_name, field.name)
    lazy_related_operation(set_managed, klass, to_model, name)
    base_classes = base_classes if base_classes else (models.Model,)

    # TODO : use autoincrement here ?
    sort_field = models.IntegerField(default=0)

    to = make_model_tuple(to_model)[1]
    from_ = klass._meta.model_name
    if to == from_:
        to = "to_%s" % to
        from_ = "from_%s" % from_

    meta = type(
        "Meta",
        (),
        {
            "db_table": field._get_m2m_db_table(klass._meta),
            "auto_created": klass,
            "app_label": klass._meta.app_label,
            "db_tablespace": klass._meta.db_tablespace,
            "unique_together": (from_, to),
            "ordering": (sort_field_name,),
            "verbose_name": _("%(from)s-%(to)s relationship") % {"from": from_, "to": to},
            "verbose_name_plural": _("%(from)s-%(to)s relationships")
            % {"from": from_, "to": to},
            "apps": field.model._meta.apps,
        },
    )

    # Construct and return the new class.
    return type(
        force_str(name),
        base_classes,
        {
            "Meta": meta,
            "__module__": klass.__module__,
            from_: models.ForeignKey(
                klass,
                related_name="%s+" % name,
                db_tablespace=field.db_tablespace,
                db_constraint=field.remote_field.db_constraint,
                on_delete=models.CASCADE,
            ),
            to: models.ForeignKey(
                to_model,
                related_name="%s+" % name,
                db_tablespace=field.db_tablespace,
                db_constraint=field.remote_field.db_constraint,
                on_delete=models.CASCADE,
            ),
            # Sort fields
            sort_field_name: sort_field,
            "_sort_field_name": sort_field_name,
        },
    )