def contribute_to_class(self, cls, name):
        # 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.rel.symmetrical and (self.rel.to == "self" or self.rel.to == cls._meta.object_name):
            self.rel.related_name = "%s_rel_+" % name

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

        # 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 self.rel.through and not cls._meta.abstract and not getattr(cls._meta, 'swapped', False):
            self.rel.through = create_many_to_many_intermediary_model(self, cls)

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

        # Set up the accessor for the m2m table name for the relation
        self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)

        # Populate some necessary rel arguments so that cross-app relations
        # work correctly.
        if isinstance(self.rel.through, six.string_types):
            def resolve_through_model(field, model, cls):
                field.rel.through = model
            add_lazy_relation(cls, self, self.rel.through, resolve_through_model)
Esempio n. 2
0
    def get_intermediate_model_meta_class(self, klass, from_field_name,
                                          to_field_name,
                                          sort_value_field_name):
        managed = True
        to_model = self.rel.to
        if isinstance(self.rel.to, six.string_types):
            if self.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
                def set_managed(field, model, cls):
                    field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
                add_lazy_relation(klass, self, to_model, set_managed)
            else:
                managed = klass._meta.managed
        else:
            managed = klass._meta.managed or to_model._meta.managed

        options = {
            'db_table': self._get_m2m_db_table(klass._meta),
            'managed': managed,
            'auto_created': klass,
            'app_label': klass._meta.app_label,
            'db_tablespace': klass._meta.db_tablespace,
            'unique_together': ((from_field_name, to_field_name),),
            'ordering': (sort_value_field_name,),
            'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_field_name, 'to': to_field_name},
            'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_field_name, 'to': to_field_name},
        }
        # Django 1.6 support.
        if hasattr(self.model._meta, 'apps'):
            options.update({
                'apps': self.model._meta.apps,
            })
        return type(str('Meta'), (object,), options)
Esempio n. 3
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

        cls._meta.add_field(self)
        setattr(cls, name, self)
        if not cls._meta.abstract:
            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):

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

                add_lazy_relation(cls, self, self.through,
                                  resolve_related_class)
            else:
                self.post_through_setup(cls)
Esempio n. 4
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

        cls._meta.add_field(self)
        setattr(cls, name, self)
        if not cls._meta.abstract:
            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):

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

                add_lazy_relation(cls, self, self.through, resolve_related_class)
            else:
                self.post_through_setup(cls)
Esempio n. 5
0
    def contribute_to_class(self, source, name):
        if not issubclass(source, NodeModel):
            raise TypeError("Relationships may only extend from Nodes.")
        self.creation_counter = source.creation_counter

        # make sure this relationship doesn't overlap with another of the same
        # type and direction
        if hasattr(source._meta, '_relationships'):
            for r in source._meta._relationships.values():
                if r.rel_type == self.name and r.direction == self.direction:
                    import warnings
                    warnings.warn('`%s` and `%s` share a relationship type and '
                                  'direction. Is this what you meant to do?'
                                  % (r.name, name))
        bound = self._get_new_bound_relationship(source, name)
        source._meta.add_field(bound)
        if not hasattr(source._meta, '_relationships'):
            source._meta._relationships = {}
        source._meta._relationships[name] = bound
        setattr(source, name, bound)
        if isinstance(self.__target, basestring):
            def setup(field, target, source):
                if not issubclass(target, NodeModel):
                    raise TypeError("Relationships may only extend from Nodes.")
                # replace the string target with the real target
                self.__target = target
                bound._setup_reversed(target)
            add_lazy_relation(source, self, self.__target, setup)
        target = self.__target
        if not self.__is_reversed:
            bound._setup_reversed(target)
Esempio n. 6
0
 def contribute_to_class(self, cls, name):
   self.name = self.column = self.attname = name
   if self.column:
     self.concrete = True
   self.model = cls
   
   # Put together permission codename using the models name
   self.codename = "%s_%s" % (
     self.permission,
     self.model._meta.object_name.lower()
   )
   
   cls._meta.add_field(self)
   setattr(cls, name, self)
   
   # Store the opts for related_query_name()
   self.opts = cls._meta
   
   if not cls._meta.abstract:
     if isinstance(self.through, basestring):
       def resolve_related_class(field, model, cls):
         self.through = model
         self.post_through_setup(cls)
       add_lazy_relation(
         cls, self, self.through, resolve_related_class
       )
     else:
       self.post_through_setup(cls)
Esempio n. 7
0
 def contribute_to_class(self, cls, name, virtual_only=False):
     # We need to skip RelatedField in the mro, so we can't use `super()`
     Field.contribute_to_class(
         self, cls, name, virtual_only=virtual_only
     )
     self.opts = cls._meta
     if not cls._meta.abstract and self.rel.related_name:
         related_name = force_text(self.rel.related_name) % {
             'class': cls.__name__.lower(),
             'app_label': cls._meta.app_label.lower()
         }
         self.rel.related_name = related_name
     for state in system_layout.allowed_values:
         with system_layout.as_value(state):
             other = self.to
             if other is None:
                 # This should only happen if `cls` is not going to be
                 # used for `state`. Just leave the null value there
                 continue
             if isinstance(other, str) or other._meta.pk is None:
                 def resolve_related_class(field, model, cls, state=state):
                     with system_layout.as_value(state):
                         field.to = model
                         field.do_related_class(model, cls)
                 add_lazy_relation(cls, self, other, resolve_related_class)
             else:
                 self.do_related_class(other, cls)
Esempio n. 8
0
    def contribute_to_class(self, cls, name, virtual_only=False):
        # We need to skip RelatedField in the mro, so we can't use `super()`
        Field.contribute_to_class(self, cls, name, virtual_only=virtual_only)
        self.opts = cls._meta
        if not cls._meta.abstract and self.rel.related_name:
            related_name = force_text(self.rel.related_name) % {
                'class': cls.__name__.lower(),
                'app_label': cls._meta.app_label.lower()
            }
            self.rel.related_name = related_name
        for state in system_layout.allowed_values:
            with system_layout.as_value(state):
                other = self.to
                if other is None:
                    # This should only happen if `cls` is not going to be
                    # used for `state`. Just leave the null value there
                    continue
                if isinstance(other, str) or other._meta.pk is None:

                    def resolve_related_class(field, model, cls, state=state):
                        with system_layout.as_value(state):
                            field.to = model
                            field.do_related_class(model, cls)

                    add_lazy_relation(cls, self, other, resolve_related_class)
                else:
                    self.do_related_class(other, cls)
Esempio n. 9
0
    def _prepare(cls):
        """
        Creates 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 = curry(cls._get_next_or_previous_in_order, is_next=True)
            cls.get_previous_in_order = curry(cls._get_next_or_previous_in_order, is_next=False)

            # defer creating accessors on the foreign class until we are
            # certain it has been created
            def make_foreign_order_accessors(field, model, cls):
                setattr(field.rel.to, "get_%s_order" % cls.__name__.lower(), curry(method_get_order, cls))
                setattr(field.rel.to, "set_%s_order" % cls.__name__.lower(), curry(method_set_order, cls))

            add_lazy_relation(
                cls, opts.order_with_respect_to, opts.order_with_respect_to.rel.to, make_foreign_order_accessors
            )

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

        if hasattr(cls, "get_absolute_url"):
            cls.get_absolute_url = update_wrapper(
                curry(get_absolute_url, opts, cls.get_absolute_url), cls.get_absolute_url
            )

        signals.class_prepared.send(sender=cls)
Esempio n. 10
0
def setup_versioned_models(sender, **kargs):
    from versions.models import VersionsModel
    if issubclass(sender, VersionsModel):
        # Register this model with the version registry.
        qn = connection.ops.quote_name
        _versions_table_mappings[qn(sender._meta.db_table)] = sender

        try:
            name_map = sender._meta._name_map
        except AttributeError:
            name_map = sender._meta.init_name_map()

        for name, data in name_map.items():
            field = data[0]
            if isinstance(field, (related.ForeignKey, related.ManyToManyField)):
                if isinstance(field, related.ForeignKey):
                    setattr(sender, name, VersionsReverseSingleRelatedObjectDescriptor(field))
                else:
                    setattr(sender, name, VersionsReverseManyRelatedObjectsDescriptor(field))

                if isinstance(field.rel.to, basestring):
                    def resolve_related_class(field, model, cls):
                        field.rel.to = model
                        field.do_related_class(model, cls)
                        setattr(field.rel.to, field.related.get_accessor_name(), VersionsForeignRelatedObjectsDescriptor(field.related))
                    related.add_lazy_relation(sender, field, field.rel.to, resolve_related_class)
                else:
                    setattr(field.rel.to, field.related.get_accessor_name(), VersionsForeignRelatedObjectsDescriptor(field.related))

        # Clean up after ourselves so that no previously initialized field caches are invalid.
        for cache_name in ('_related_many_to_many_cache', '_name_map', '_related_objects_cache', '_m2m_cache', '_field_cache',):
            try:
                delattr(sender._meta, cache_name)
            except:
                pass
Esempio n. 11
0
    def contribute_to_class(self, source, name):
        if not issubclass(source, NodeModel):
            raise TypeError("Relationships may only extend from Nodes.")
        self.creation_counter = source.creation_counter

        # make sure this relationship doesn't overlap with another of the same
        # type and direction
        if hasattr(source._meta, '_relationships'):
            for r in source._meta._relationships.values():
                if r.rel_type == self.name and r.direction == self.direction:
                    import warnings
                    warnings.warn(
                        '`%s` and `%s` share a relationship type and '
                        'direction. Is this what you meant to do?' %
                        (r.name, name))
        bound = self._get_new_bound_relationship(source, name)
        source._meta.add_field(bound)
        if not hasattr(source._meta, '_relationships'):
            source._meta._relationships = {}
        source._meta._relationships[name] = bound
        setattr(source, name, bound)
        if isinstance(self.__target, basestring):

            def setup(field, target, source):
                if not issubclass(target, NodeModel):
                    raise TypeError(
                        "Relationships may only extend from Nodes.")
                # replace the string target with the real target
                self.__target = target
                bound._setup_reversed(target)

            add_lazy_relation(source, self, self.__target, setup)
        target = self.__target
        if not self.__is_reversed:
            bound._setup_reversed(target)
Esempio n. 12
0
    def get_intermediate_model_meta_class(self, klass, from_field_name,
                                          to_field_name,
                                          sort_value_field_name):
        managed = True
        to_model = self.rel.to
        if isinstance(self.rel.to, six.string_types):
            if self.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
                def set_managed(field, model, cls):
                    field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
                add_lazy_relation(klass, self, to_model, set_managed)
            else:
                managed = klass._meta.managed
        else:
            managed = klass._meta.managed or to_model._meta.managed

        options = {
            'db_table': self._get_m2m_db_table(klass._meta),
            'managed': managed,
            'auto_created': klass,
            'app_label': klass._meta.app_label,
            'db_tablespace': klass._meta.db_tablespace,
            'unique_together': ((from_field_name, to_field_name),),
            'ordering': (sort_value_field_name,),
            'verbose_name': '%(from)s-%(to)s relationship' % {'from': from_field_name, 'to': to_field_name},
            'verbose_name_plural': '%(from)s-%(to)s relationships' % {'from': from_field_name, 'to': to_field_name},
        }
        # Django 1.6 support.
        if hasattr(self.model._meta, 'apps'):
            options.update({
                'apps': self.model._meta.apps,
            })
        return type(str('Meta'), (object,), options)
Esempio n. 13
0
def create_one_to_many_intermediary_model(field, klass):
    """
    Identical to the 'create_many_to_many_intermediary_model' implementation
    from django.db.models.fields.related, but with a 'unique' constraint added
    to the receiving relation.
    """
    from django.db import models
    managed = True
    if isinstance(
            field.rel.to,
            basestring) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
        to_model = field.rel.to
        to = to_model.split('.')[-1]

        def set_managed(field, model, cls):
            field.rel.through._meta.managed = model._meta.managed or cls._meta.managed

        add_lazy_relation(klass, field, to_model, set_managed)
    elif isinstance(field.rel.to, basestring):
        to = klass._meta.object_name
        to_model = klass
        managed = klass._meta.managed
    else:
        to = field.rel.to._meta.object_name
        to_model = field.rel.to
        managed = klass._meta.managed or to_model._meta.managed
    name = '%s_%s' % (klass._meta.object_name, field.name)

    if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
        from_ = 'from_%s' % to.lower()
        to = 'to_%s' % to.lower()
    else:
        from_ = klass._meta.object_name.lower()
        to = to.lower()
    meta = type(
        'Meta', (object, ), {
            'db_table': field._get_m2m_db_table(klass._meta),
            'managed': managed,
            'auto_created': klass,
            'app_label': klass._meta.app_label,
            '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
            },
        })
    # Construct and return the new class.
    return type(
        name, (models.Model, ), {
            'Meta': meta,
            '__module__': klass.__module__,
            from_: models.ForeignKey(klass, related_name='%s+' % name),
            to: models.ForeignKey(
                to_model, related_name='%s+' % name, unique=True)
        })
Esempio n. 14
0
def create_many_to_many_intermediary_model(field, klass):
    """
    Copied from django, but uses FKToVersion for the
    'from' field. Fields are also always called 'from' and 'to'
    to avoid problems between version combined models.
    """
    managed = True
    if isinstance(field.rel.to, basestring) and field.rel.to != \
                related.RECURSIVE_RELATIONSHIP_CONSTANT:
        to_model = field.rel.to
        to = to_model.split('.')[-1]

        def set_managed(field, model, cls):
            managed = model._meta.managed or cls._meta.managed
            if issubclass(cls, VersionView):
                managed = False
            field.rel.through._meta.managed = managed
        related.add_lazy_relation(klass, field, to_model, set_managed)
    elif isinstance(field.rel.to, basestring):
        to = klass._meta.object_name
        to_model = klass
        managed = klass._meta.managed
    else:
        to = field.rel.to._meta.object_name
        to_model = field.rel.to
        managed = klass._meta.managed or to_model._meta.managed
        if issubclass(klass, VersionView):
            managed = False

    name = '%s_%s' % (klass._meta.object_name, field.name)
    if field.rel.to == related.RECURSIVE_RELATIONSHIP_CONSTANT or \
                        to == klass._meta.object_name:
        from_ = 'from_%s' % to.lower()
        to = 'to_%s' % to.lower()
    else:
        from_ = klass._meta.object_name.lower()
        to = to.lower()
    meta = type('Meta', (object,), {
        'db_table': field._get_m2m_db_table(klass._meta),
        'managed': managed,
        '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},
    })

    # Construct and return the new class.
    return type(name, (models.Model,), {
        'Meta': meta,
        '__module__': klass.__module__,
        'from': FKToVersion(klass, related_name='%s+' % name,
                            db_tablespace=field.db_tablespace),
        'to': models.ForeignKey(to_model, related_name='%s+' % name,
                                db_tablespace=field.db_tablespace)
    })
Esempio n. 15
0
 def contribute_to_class(self, model, name):
     self.__m2m_name = name
     # Call Field, not super, to skip Django's ManyToManyField extra stuff
     # we don't need
     ListField.contribute_to_class(self, model, name)
     # Do the rest after resolving the 'to' relation
     add_lazy_relation(model, self, self._mm2m_to_or_name,
                       self.contribute_after_resolving)
Esempio n. 16
0
 def contribute_to_class(self, model, name):
     self.__m2m_name = name
     # Call Field, not super, to skip Django's ManyToManyField extra stuff
     # we don't need
     ListField.contribute_to_class(self, model, name)
     # Do the rest after resolving the 'to' relation
     add_lazy_relation(model, self, self._mm2m_to_or_name,
                       self.contribute_after_resolving)
Esempio n. 17
0
 def contribute_to_class(self):
     if isinstance(self.model, six.string_types) or self.model._meta.pk is None:
         def resolve_related_class(rel, model, cls):
             rel.model = model
             rel.do_related_class()
         add_lazy_relation(self.field.model, self, self.model,
                           resolve_related_class)
     else:
         self.do_related_class()
Esempio n. 18
0
 def contribute_to_class(self, cls, name):
     super(MaxCardinalityManyToManyField, self).contribute_to_class(cls, name)
     if self.max_cardinality or self.reverse_max_cardinality:
         through = self.rel.through
         if through:
             if isinstance(through, basestring):
                 add_lazy_relation(cls, self, through,
                     lambda self, through, cls: self.__connect_through_signals(through))
             else:
                 self.__connect_through_signals(through)
Esempio n. 19
0
    def create_many_to_many_intermediary_model(field, klass):
        """
        This function is a large copy/paste from django in order to construct
        correct through tables for `ManyToManyField` relationships.
        """
        from django.db import models
        from django_unsigned_fields.fields import UnsignedForeignKey
        from django.db.models.fields.related import (
            add_lazy_relation,
            RECURSIVE_RELATIONSHIP_CONSTANT,
        )
        managed = True
        if isinstance(field.rel.to, six.string_types) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
            to_model = field.rel.to
            to = to_model.split('.')[-1]

            def set_managed(field, model, cls):
                field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
            add_lazy_relation(klass, field, to_model, set_managed)
        elif isinstance(field.rel.to, six.string_types):
            to = klass._meta.object_name
            to_model = klass
            managed = klass._meta.managed
        else:
            to = field.rel.to._meta.object_name
            to_model = field.rel.to
            managed = klass._meta.managed or to_model._meta.managed
        name = '%s_%s' % (klass._meta.object_name, field.name)
        if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
            from_ = 'from_%s' % to.lower()
            to = 'to_%s' % to.lower()
        else:
            from_ = klass._meta.model_name
            to = to.lower()
        meta = type(str('Meta'), (object,), {
            'db_table': field._get_m2m_db_table(klass._meta),
            'managed': managed,
            '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,
        })
        to_field_klass = UnsignedForeignKey if field.to_unsigned else models.ForeignKey
        from_field_klass = UnsignedForeignKey if field.from_unsigned else models.ForeignKey
        # Construct and return the new class.
        return type(str(name), (models.Model,), {
            'Meta': meta,
            '__module__': klass.__module__,
            from_: from_field_klass(klass, related_name='%s+' % name, db_tablespace=field.db_tablespace, db_constraint=field.rel.db_constraint),
            to: to_field_klass(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace, db_constraint=field.rel.db_constraint)
        })
Esempio n. 20
0
 def __new__(cls, name, bases, attrs):
     new_cls = super().__new__(cls, name, bases, attrs)
     new_cls._meta.custom_fields_inheritance_by_model = {}
     new_cls._meta.custom_fields_inheritance_by_path = {}
     # for each field in custom field inheritance, call
     # `add_custom_field_inheritance` - it will be called lazy, only when
     # model will be loaded
     for field_path, model in new_cls.custom_fields_inheritance.items():
         add_lazy_relation(new_cls, field_path, model,
                           add_custom_field_inheritance)
     return new_cls
Esempio n. 21
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)
Esempio n. 22
0
def create_sorted_many_to_many_intermediate_model(field, klass):
    from django.db import models
    managed = True
    if isinstance(field.rel.to, six.string_types) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
        to_model = field.rel.to
        to = to_model.split('.')[-1]

        def set_managed(field, model, cls):
            field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
        add_lazy_relation(klass, field, to_model, set_managed)
    elif isinstance(field.rel.to, six.string_types):
        to = klass._meta.object_name
        to_model = klass
        managed = klass._meta.managed
    else:
        to = field.rel.to._meta.object_name
        to_model = field.rel.to
        managed = klass._meta.managed or to_model._meta.managed
    name = '%s_%s' % (klass._meta.object_name, field.name)
    if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
        from_ = 'from_%s' % to.lower()
        to = 'to_%s' % to.lower()
    else:
        from_ = klass._meta.model_name
        to = to.lower()
    meta = type('Meta', (object,), {
        'db_table': field._get_m2m_db_table(klass._meta),
        'managed': managed,
        'auto_created': klass,
        'app_label': klass._meta.app_label,
        'db_tablespace': klass._meta.db_tablespace,
        'unique_together': (from_, to),
        'ordering': (field.sort_value_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.
    def default_sort_value(name):
        model = models.get_model(klass._meta.app_label, name)
        return model._default_manager.count()

    default_sort_value = curry(default_sort_value, name)

    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.rel.db_constraint),
        to: models.ForeignKey(to_model, related_name='%s+' % name, db_tablespace=field.db_tablespace, db_constraint=field.rel.db_constraint),
        field.sort_value_field_name: models.IntegerField(default=default_sort_value),
        '_sort_field_name': field.sort_value_field_name,
        '_from_field_name': from_,
        '_to_field_name': to,
    })
Esempio n. 23
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')
        add_lazy_relation(cls, self, "self", self.bind_m2m_changed)
Esempio n. 24
0
    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,(str,unicode)):
            # if ``other_model`` is a string, it certainly is a lazy relation.
            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)
Esempio n. 25
0
def validate_not_to_tenant_model(field, to, model):
    """
    Make sure the `to` relationship is not pointing to an instance of
    `TenantModelBase`.
    """
    if isinstance(to, string_types):
        add_lazy_relation(model, field, to, validate_not_to_tenant_model)
    elif isinstance(to, TenantModelBase):
        remove_from_app_cache(model, quiet=True)
        raise ImproperlyConfigured(
            "`%s.%s`'s `to` option` can't point to an instance of "
            "`TenantModelBase` since it's not one itself." %
            (model.__name__, field.name))
Esempio n. 26
0
    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,(str,unicode)):
            # if ``other_model`` is a string, it certainly is a lazy relation.
            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)
Esempio n. 27
0
    def _prepare(cls):
        """
        Creates 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 = curry(cls._get_next_or_previous_in_order,
                                          is_next=True)
            cls.get_previous_in_order = curry(
                cls._get_next_or_previous_in_order, is_next=False)

            # defer creating accessors on the foreign class until we are
            # certain it has been created
            def make_foreign_order_accessors(field, model, cls):
                setattr(field.rel.to, 'get_%s_order' % cls.__name__.lower(),
                        curry(method_get_order, cls))
                setattr(field.rel.to, 'set_%s_order' % cls.__name__.lower(),
                        curry(method_set_order, cls))

            add_lazy_relation(cls, opts.order_with_respect_to,
                              opts.order_with_respect_to.rel.to,
                              make_foreign_order_accessors)

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

        if hasattr(cls, 'get_absolute_url'):
            cls.get_absolute_url = update_wrapper(
                curry(get_absolute_url, opts, cls.get_absolute_url),
                cls.get_absolute_url)

        if hasattr(cls, 'get_resource_url_list'):
            cls.get_resource_url_list = staticmethod(
                curry(get_resource_url_list, opts, cls.get_resource_url_list))

        if hasattr(cls, 'get_resource_url_count'):
            cls.get_resource_url_count = update_wrapper(
                curry(get_resource_url_count, opts,
                      cls.get_resource_url_count), cls.get_resource_url_count)

        if hasattr(cls, 'get_resource_url_detail'):
            cls.get_resource_url_detail = update_wrapper(
                curry(get_resource_url_detail, opts,
                      cls.get_resource_url_detail),
                cls.get_resource_url_detail)

        signals.class_prepared.send(sender=cls)
Esempio n. 28
0
def create_sorted_many_to_many_intermediate_model(field, klass):
    from django.db import models
    managed = True
    if isinstance(field.rel.to, basestring) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
        to_model = field.rel.to
        to = to_model.split('.')[-1]
        def set_managed(field, model, cls):
            field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
        add_lazy_relation(klass, field, to_model, set_managed)
    elif isinstance(field.rel.to, basestring):
        to = klass._meta.object_name
        to_model = klass
        managed = klass._meta.managed
    else:
        to = field.rel.to._meta.object_name
        to_model = field.rel.to
        managed = klass._meta.managed or to_model._meta.managed
    name = '%s_%s' % (klass._meta.object_name, field.name)
    if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
        from_ = 'from_%s' % to.lower()
        to = 'to_%s' % to.lower()
    else:
        from_ = klass._meta.object_name.lower()
        to = to.lower()
    meta = type('Meta', (object,), {
        'db_table': field._get_m2m_db_table(klass._meta),
        'managed': managed,
        'auto_created': klass,
        'app_label': klass._meta.app_label,
        'unique_together': (from_, to),
        'ordering': (SORT_VALUE_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},
    })
    # Construct and return the new class.
    def default_sort_value(name):
        model = models.get_model(klass._meta.app_label, name)
        return model._default_manager.count()

    default_sort_value = curry(default_sort_value, name)

    return type(name, (models.Model,), {
        'Meta': meta,
        '__module__': klass.__module__,
        from_: models.ForeignKey(klass, related_name='%s+' % name),
        to: models.ForeignKey(to_model, related_name='%s+' % name),
        SORT_VALUE_FIELD_NAME: models.IntegerField(default=default_sort_value),
        '_sort_field_name': SORT_VALUE_FIELD_NAME,
        '_from_field_name': from_,
        '_to_field_name': to,
    })
Esempio n. 29
0
 def contribute_to_class(self, cls, name):
     super(PolymorphicTypeField, self).contribute_to_class(cls, name)
     polymorphic_type = self.rel.polymorphic_type
     if (isinstance(polymorphic_type, string_types) or
         polymorphic_type._meta.pk is None):
         def resolve_polymorphic_type(field, model, cls):
             field.validate_polymorphic_type(model)
             field.rel.polymorphic_type = model
             field.do_polymorphic_type(model)
         add_lazy_relation(
             cls, self, polymorphic_type, resolve_polymorphic_type
         )
     else:
         self.do_polymorphic_type(polymorphic_type)
Esempio n. 30
0
    def contribute_to_class(self, cls, name, **kwargs):
        super(RelatedBitField, self).contribute_to_class(cls, name, **kwargs)
        other = self.fake_rel.to
        if isinstance(other, six.string_types) or other._meta.pk is None:

            def resolve_related_class(field, model, cls):
                rel = field.fake_rel
                rel.to = model
                rel.field_name = rel.field_name or model._meta.pk.name

            add_lazy_relation(cls, self, other, resolve_related_class)
        else:
            rel = self.fake_rel
            rel.field_name = rel.field_name or other._meta.pk.name
Esempio n. 31
0
 def contribute_to_class(self, cls, name):
     super(PolymorphicTypeField, self).contribute_to_class(cls, name)
     polymorphic_type = self.rel.polymorphic_type
     if (isinstance(polymorphic_type, string_types) or
         polymorphic_type._meta.pk is None):
         def resolve_polymorphic_type(field, model, cls):
             field.validate_polymorphic_type(model)
             field.rel.polymorphic_type = model
             field.do_polymorphic_type(model)
         add_lazy_relation(
             cls, self, polymorphic_type, resolve_polymorphic_type
         )
     else:
         self.do_polymorphic_type(polymorphic_type)
Esempio n. 32
0
 def contribute_to_class(self, cls, name):
     self.name = self.column = name
     self.model = cls
     cls._meta.add_field(self)
     setattr(cls, name, self)
     if not cls._meta.abstract:
         if isinstance(self.through, basestring):
             def resolve_related_class(field, model, cls):
                 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):
        super(GenericManyToManyField, self).contribute_to_class(cls, name)
        self.name = self.column = name
        self.model = cls
        cls._meta.add_field(self)

        setattr(cls, self.name, ReverseGenericManyRelatedObjectsDescriptor(self))

        if not cls._meta.abstract:
            if isinstance(self.through, basestring):
                def resolve_related_class(field, model, cls):
                    self.through = model
                add_lazy_relation(
                    cls, self, self.through, resolve_related_class
                )
Esempio n. 34
0
 def validate_through(cls, field, rel_to, model):
     """
     Make sure the related fields with a specified through points to an
     instance of `TenantModelBase`.
     """
     through = field.rel.through
     if isinstance(through, string_types):
         add_lazy_relation(model, field, through, cls.validate_through)
     elif not isinstance(through, cls):
         del cls.references[model]
         remove_from_app_cache(model, quiet=True)
         raise ImproperlyConfigured(
             "Since `%s.%s` is originating from an instance of "
             "`TenantModelBase` its `through` option must also be pointing "
             "to one." % (model.__name__, field.name))
Esempio n. 35
0
 def contribute_to_class(self, cls, name):
     self.name = self.column = name
     self.model = cls
     cls._meta.add_field(self)
     setattr(cls, name, self)
     if not cls._meta.abstract:
         if isinstance(self.through, basestring):
             def resolve_related_class(field, model, cls):
                 self.through = model
                 self.post_through_setup(cls)
             add_lazy_relation(
                 cls, self, self.through, resolve_related_class
             )
         else:
             self.post_through_setup(cls)
Esempio n. 36
0
 def contribute_to_class(self, cls, name):
     """
     Replace the descriptor with our custom descriptor, so that the
     position field (which is saved in the formfield clean()) gets saved
     """
     if self.sort_field_name is not None:
         def resolve_sort_field(field, model, cls):
             field.sort_field = model._meta.get_field(field.sort_field_name)
         if isinstance(self.rel.through, basestring):
             add_lazy_relation(cls, self, self.rel.through, resolve_sort_field)
         else:
             resolve_sort_field(self, self.rel.through, cls)
     super(ManyToManyField, self).contribute_to_class(cls, name)
     if self.sort_field_name is not None:
         setattr(cls, self.name, SortableReverseManyRelatedObjectsDescriptor(self))
Esempio n. 37
0
def validate_not_to_tenant_model(field, to, model):
    """
    Make sure the `to` relationship is not pointing to an instance of
    `TenantModelBase`.
    """
    if isinstance(to, basestring):
        add_lazy_relation(model, field, to, validate_not_to_tenant_model)
    elif isinstance(to, TenantModelBase):
        remove_from_app_cache(model, quiet=True)
        raise ImproperlyConfigured(
            "`%s.%s`'s `to` option` can't point to an instance of "
            "`TenantModelBase` since it's not one itself." % (
                model.__name__, field.name
            )
        )
Esempio n. 38
0
 def validate_through(cls, field, rel_to, model):
     """
     Make sure the related fields with a specified through points to an
     instance of `TenantModelBase`.
     """
     through = field.rel.through
     if isinstance(through, basestring):
         add_lazy_relation(model, field, through, cls.validate_through)
     elif not isinstance(through, cls):
         del cls.references[model]
         remove_from_app_cache(model, quiet=True)
         raise ImproperlyConfigured(
             "Since `%s.%s` is originating from an instance of "
             "`TenantModelBase` its `through` option must also be pointing "
             "to one." % (model.__name__, field.name)
         )
Esempio n. 39
0
    def contribute_to_class(self, cls, name):
        if not self.sorted:
            return super(SortedManyToManyField,
                         self).contribute_to_class(cls, name)

        # 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.rel.symmetrical and (self.rel.to == "self"
                                     or self.rel.to == cls._meta.object_name):
            self.rel.related_name = "%s_rel_+" % name

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

        # 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.
        if not self.rel.through and not cls._meta.abstract:
            self.rel.through = create_sorted_many_to_many_intermediate_model(
                self, cls)

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

        # Set up the accessor for the m2m table name for the relation
        self.m2m_db_table = curry(self._get_m2m_db_table, cls._meta)

        # Populate some necessary rel arguments so that cross-app relations
        # work correctly.
        if isinstance(self.rel.through, six.string_types):

            def resolve_through_model(field, model, cls):
                field.rel.through = model

            add_lazy_relation(cls, self, self.rel.through,
                              resolve_through_model)

        if hasattr(cls._meta, 'duplicate_targets'):  # Django<1.5
            if isinstance(self.rel.to, six.string_types):
                target = self.rel.to
            else:
                target = self.rel.to._meta.db_table
            cls._meta.duplicate_targets[self.column] = (target, "m2m")
Esempio n. 40
0
    def _set_model(self, model):
        # We need to know the model to generate a valid key for the lookup but
        # EmbeddedModelFields are not contributed_to_class if used in ListFields
        # (and friends), so we can only know the model when the ListField sets
        # our 'model' attribute in its contribute_to_class method.

        if model is not None and isinstance(self.embedded_model, basestring):
            # The model argument passed to __init__ was a string, so we need
            # to make sure to resolve that string to the corresponding model
            # class, similar to relation fields. We abuse some of the relation
            # fields' code to do the lookup here:
            def _resolve_lookup(self_, resolved_model, model):
                self.embedded_model = resolved_model
            from django.db.models.fields.related import add_lazy_relation
            add_lazy_relation(model, self, self.embedded_model, _resolve_lookup)

        self._model = model
def create_one_to_many_intermediary_model(field, klass):
    """
    Identical to the 'create_many_to_many_intermediary_model' implementation
    from django.db.models.fields.related, but with a 'unique' constraint added
    to the receiving relation.
    """
    from django.db import models
    managed = True
    if isinstance(field.rel.to, basestring) and field.rel.to != RECURSIVE_RELATIONSHIP_CONSTANT:
        to_model = field.rel.to
        to = to_model.split('.')[-1]
        def set_managed(field, model, cls):
            field.rel.through._meta.managed = model._meta.managed or cls._meta.managed
        add_lazy_relation(klass, field, to_model, set_managed)
    elif isinstance(field.rel.to, basestring):
        to = klass._meta.object_name
        to_model = klass
        managed = klass._meta.managed
    else:
        to = field.rel.to._meta.object_name
        to_model = field.rel.to
        managed = klass._meta.managed or to_model._meta.managed
    name = '%s_%s' % (klass._meta.object_name, field.name)

    if field.rel.to == RECURSIVE_RELATIONSHIP_CONSTANT or to == klass._meta.object_name:
        from_ = 'from_%s' % to.lower()
        to = 'to_%s' % to.lower()
    else:
        from_ = klass._meta.object_name.lower()
        to = to.lower()
    meta = type('Meta', (object,), {
        'db_table': field._get_m2m_db_table(klass._meta),
        'managed': managed,
        'auto_created': klass,
        'app_label': klass._meta.app_label,
        '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},
    })
    # Construct and return the new class.
    return type(name, (models.Model,), {
        'Meta': meta,
        '__module__': klass.__module__,
        from_: models.ForeignKey(klass, related_name='%s+' % name),
        to: models.ForeignKey(to_model, related_name='%s+' % name, unique=True)
    })
Esempio n. 42
0
    def _set_model(self, model):
        # EmbeddedModelFields are not contribute[d]_to_class if using within
        # ListFields (and friends), so we can only know the model field is
        # used in when the IterableField sets our 'model' attribute in its
        # contribute_to_class method.
        # We need to know the model to generate a valid key for the lookup.

        if model is not None and isinstance(self.embedded_model, basestring):
            # The model argument passed to __init__ was a string, so we need
            # to make sure to resolve that string to the corresponding model
            # class, similar to relation fields. We abuse some of the
            # relation fields' code to do the lookup here:
            def _resolve_lookup(self_, resolved_model, model):
                self.embedded_model = resolved_model
            from django.db.models.fields.related import add_lazy_relation
            add_lazy_relation(model, self, self.embedded_model, _resolve_lookup)

        self._model = model
Esempio n. 43
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)
Esempio n. 44
0
    def model_prepared(self, sender, **kwargs):
        '''
        Wait for any field dependencies to be resolved, then call finalize().
        '''
        model = sender
        deps = self.get_field_dependencies(model)
        if deps:
            count = [len(deps)]

            def dependency_resolved(*args):
                count[0] = count[0] - 1
                if count[0] == 0:
                    self.finalize(model)

            for dep in deps:
                add_lazy_relation(model, None, dep.rel.to, dependency_resolved)
        else:
            self.finalize(model)
Esempio n. 45
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)
Esempio n. 46
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)
Esempio n. 47
0
    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)
Esempio n. 48
0
    def contribute_to_class(self, cls, name):
        """
        Replace the descriptor with our custom descriptor, so that the
        position field (which is saved in the formfield clean()) gets saved
        """
        if self.sort_field_name is not None:

            def resolve_sort_field(field, model, cls):
                field.sort_field = model._meta.get_field(field.sort_field_name)

            if isinstance(self.rel.through, basestring):
                add_lazy_relation(cls, self, self.rel.through,
                                  resolve_sort_field)
            else:
                resolve_sort_field(self, self.rel.through, cls)
        super(ManyToManyField, self).contribute_to_class(cls, name)
        if self.sort_field_name is not None:
            setattr(cls, self.name,
                    SortableReverseManyRelatedObjectsDescriptor(self))
Esempio n. 49
0
    def contribute_to_class(self, cls, name):
        self.item_field.model = cls
        self.item_field.name = name
        super(AbstractIterableField, self).contribute_to_class(cls, name)

        # If items' field uses SubfieldBase we also need to.
        item_metaclass = getattr(self.item_field, '__metaclass__', None)
        if item_metaclass and issubclass(item_metaclass, models.SubfieldBase):
            setattr(cls, self.name, Creator(self))

        if isinstance(self.item_field, models.ForeignKey) and isinstance(self.item_field.rel.to, six.string_types):
            """
            If rel.to is a string because the actual class is not yet defined, look up the
            actual class later.  Refer to django.models.fields.related.RelatedField.contribute_to_class.
            """
            def _resolve_lookup(_, resolved_model, __):
                self.item_field.rel.to = resolved_model
                self.item_field.do_related_class(self, cls)

            add_lazy_relation(cls, self, self.item_field.rel.to, _resolve_lookup)
Esempio n. 50
0
 def validate_related_name(cls, field, rel_to, model):
     """
     Make sure that related fields pointing to non-tenant models specify
     a related name containing a %(class)s format placeholder.
     """
     if isinstance(rel_to, string_types):
         add_lazy_relation(model, field, rel_to, cls.validate_related_name)
     elif not isinstance(rel_to, TenantModelBase):
         related_name = cls.references[model].related_names[field.name]
         if (related_name is not None
                 and not (field.rel.is_hidden()
                          or '%(class)s' in related_name)):
             del cls.references[model]
             remove_from_app_cache(model, quiet=True)
             raise ImproperlyConfigured(
                 "Since `%s.%s` is originating from an instance "
                 "of `TenantModelBase` and not pointing to one "
                 "its `related_name` option must ends with a "
                 "'+' or contain the '%%(class)s' format "
                 "placeholder." % (model.__name__, field.name))
Esempio n. 51
0
    def _set_model(self, model):
        """
        Resolves embedded model class once the field knows the model it
        belongs to.
        If the model argument passed to __init__ was a string, we need
        to make sure to resolve that string to the corresponding model
        class, similar to relation fields.
        However, we need to know our own model to generate a valid key
        for the embedded model class lookup and EmbeddedModelFields are
        not contributed_to_class if used in iterable fields. Thus we
        rely on the collection field telling us its model (by setting
        our "model" attribute in its contribute_to_class method).
        """
        self._model = model
        if model is not None and isinstance(self.embedded_model, basestring):

            def _resolve_lookup(self_, resolved_model, model):
                self.embedded_model = resolved_model

            add_lazy_relation(model, self, self.embedded_model, _resolve_lookup)
Esempio n. 52
0
 def validate_related_name(cls, field, rel_to, model):
     """
     Make sure that related fields pointing to non-tenant models specify
     a related name containing a %(class)s format placeholder.
     """
     if isinstance(rel_to, basestring):
         add_lazy_relation(model, field, rel_to, cls.validate_related_name)
     elif not isinstance(rel_to, cls):
         related_name = cls.references[model].related_names[field.name]
         if (related_name is not None and
             not (field.rel.is_hidden() or '%(class)s' in related_name)):
                 del cls.references[model]
                 remove_from_app_cache(model, quiet=True)
                 raise ImproperlyConfigured(
                     "Since `%s.%s` is originating from an instance "
                     "of `TenantModelBase` and not pointing to one "
                     "its `related_name` option must ends with a "
                     "'+' or contain the '%%(class)s' format "
                     "placeholder." % (model.__name__, field.name)
                 )
Esempio n. 53
0
    def contribute_to_class(self, cls, name):
        self.item_field.model = cls
        self.item_field.name = name
        super(AbstractIterableField, self).contribute_to_class(cls, name)

        # If items' field uses SubfieldBase we also need to.
        item_metaclass = getattr(self.item_field, '__metaclass__', None)
        if item_metaclass and issubclass(item_metaclass, models.SubfieldBase):
            setattr(cls, self.name, Creator(self))

        if isinstance(self.item_field, models.ForeignKey) and isinstance(self.item_field.rel.to, basestring):
            """
            If rel.to is a string because the actual class is not yet defined, look up the
            actual class later.  Refer to django.models.fields.related.RelatedField.contribute_to_class.
            """
            def _resolve_lookup(_, resolved_model, __):
                self.item_field.rel.to = resolved_model
                self.item_field.do_related_class(self, cls)

            add_lazy_relation(cls, self, self.item_field.rel.to, _resolve_lookup)
Esempio n. 54
0
    def _set_model(self, model):
        """
        Resolves embedded model class once the field knows the model it
        belongs to.

        If the model argument passed to __init__ was a string, we need
        to make sure to resolve that string to the corresponding model
        class, similar to relation fields.
        However, we need to know our own model to generate a valid key
        for the embedded model class lookup and EmbeddedModelFields are
        not contributed_to_class if used in iterable fields. Thus we
        rely on the collection field telling us its model (by setting
        our "model" attribute in its contribute_to_class method).
        """
        self._model = model
        if model is not None and isinstance(self.embedded_model, basestring):

            def _resolve_lookup(self_, resolved_model, model):
                self.embedded_model = resolved_model

            add_lazy_relation(model, self, self.embedded_model, _resolve_lookup)
Esempio n. 55
0
    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.
        if self.rel.symmetrical and (self.rel.to == "self" or self.rel.to == cls._meta.object_name):
            self.rel.related_name = "%s_rel_+" % name

        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.
        if not self.rel.through and not cls._meta.abstract:
            self.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 = curry(self._get_m2m_db_table, cls._meta)

        # Populate some necessary rel arguments so that cross-app relations
        # work correctly.
        if isinstance(self.rel.through, six.string_types):
            def resolve_through_model(field, model, cls):
                field.rel.through = model
            add_lazy_relation(cls, self, self.rel.through, resolve_through_model)

        if hasattr(cls._meta, 'duplicate_targets'):  # Django<1.5
            if isinstance(self.rel.to, six.string_types):
                target = self.rel.to
            else:
                target = self.rel.to._meta.db_table
            cls._meta.duplicate_targets[self.column] = (target, "m2m")
Esempio n. 56
0
 def __init__(self, cls, field, name, setup_reversed):
     add_lazy_relation(cls, field, name, self.__setup)
     self.__setup_reversed = setup_reversed
Esempio n. 57
0
def create_many_to_many_intermediary_model(field, klass):
    """
    Copied from django, but uses FKToVersion for the
    'from' field. Fields are also always called 'from' and 'to'
    to avoid problems between version combined models.
    """
    managed = True
    if (isinstance(field.remote_field.to, basestring) and
            field.remote_field.to != related.RECURSIVE_RELATIONSHIP_CONSTANT):
        to_model = field.remote_field.to
        to = to_model.split('.')[-1]

        def set_managed(field, model, cls):
            managed = model._meta.managed or cls._meta.managed
            if issubclass(cls, VersionView):
                managed = False
            field.remote_field.through._meta.managed = managed
        related.add_lazy_relation(klass, field, to_model, set_managed)
    elif isinstance(field.remote_field.to, basestring):
        to = klass._meta.object_name
        to_model = klass
        managed = klass._meta.managed
    else:
        to = field.remote_field.to._meta.object_name
        to_model = field.remote_field.to
        managed = klass._meta.managed or to_model._meta.managed
        if issubclass(klass, VersionView):
            managed = False

    name = '%s_%s' % (klass._meta.object_name, field.name)
    if (field.remote_field.to == related.RECURSIVE_RELATIONSHIP_CONSTANT or
            to == klass._meta.object_name):
        from_ = 'from_%s' % to.lower()
        to = 'to_%s' % to.lower()
    else:
        from_ = klass._meta.object_name.lower()
        to = to.lower()
    meta = type('Meta', (object,), {
        'db_table': field._get_m2m_db_table(klass._meta),
        'managed': managed,
        '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': FKToVersion(klass, related_name='%s+' % name,
                            db_tablespace=field.db_tablespace,
                            db_constraint=field.remote_field.db_constraint),
        'to': models.ForeignKey(to_model, related_name='%s+' % name,
                                db_tablespace=field.db_tablespace,
                                db_constraint=field.remote_field.db_constraint)
    })
Esempio n. 58
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:
                    # ETJ DEBUG
                    if (hasattr(f, 'rel') and f.remote_field \
                        and (f.remote_field.model == rel.field.model
                             or f.remote_field.model == '%s.%s' % (rel.field.model._meta.app_label,rel.field.model._meta.object_name)
                             or f.remote_field.model == rel.field.model._meta.object_name)):
                    # NOTE: Original code failed on Django 1.10
                    # if hasattr(f, 'rel') and f.remote_field \
                    # and (f.remote_field.model == rel.field.model
                    #      or f.remote_field.model == '%s.%s' % (
                    #         rel.field.model._meta.app_label,
                    #         rel.field.model._meta.object_name)):
                    # END DEBUG 
                        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, six.string_types):
            def resolve_through_model(r, model, c):
                r.set_init('through', model)
                calc_field_names(r)
            add_lazy_relation(cls, self, self.through, resolve_through_model)
        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()