Ticket #3871: 3871.2.diff

File 3871.2.diff, 4.7 KB (added by EspenG <espen@…>, 8 years ago)

Now also support ForeignKeys

  • django/db/models/fields/related.py

    === modified file 'django/db/models/fields/related.py'
     
    194194    # multiple "remote" values and have a ForeignKey pointed at them by
    195195    # some other model. In the example "poll.choice_set", the choice_set
    196196    # attribute is a ForeignRelatedObjectsDescriptor instance.
    197     def __init__(self, related):
     197    def __init__(self, related, manager=None):
    198198        self.related = related   # RelatedObject instance
     199        self.manager = manager
    199200
    200201    def __get__(self, instance, instance_type=None):
    201202        if instance is None:
     
    206207
    207208        # Dynamically create a class that subclasses the related
    208209        # model's default manager.
    209         superclass = self.related.model._default_manager.__class__
     210        if self.manager == None:
     211            superclass = self.related.model._default_manager.__class__
     212        else:
     213            superclass = self.manager.__class__
    210214
    211215        class RelatedManager(superclass):
    212216            def get_query_set(self):
     
    388392    # some other model (rather than having a ManyToManyField themselves).
    389393    # In the example "publication.article_set", the article_set attribute is a
    390394    # ManyRelatedObjectsDescriptor instance.
    391     def __init__(self, related):
     395    def __init__(self, related, manager=None):
    392396        self.related = related   # RelatedObject instance
    393397
    394398    def __get__(self, instance, instance_type=None):
    395399        if instance is None:
    396400            raise AttributeError, "Manager must be accessed via instance"
    397401
    398402        # Dynamically create a class that subclasses the related
    399403        # model's default manager.
     404
     405        if self.manager == None:
     406            superclass = self.related.model._default_manager.__class__
     407        else:
     408            superclass = self.manager.__class__
     409       
    400410        rel_model = self.related.model
    401         superclass = rel_model._default_manager.__class__
    402411        RelatedManager = create_many_related_manager(superclass)
    403412
    404413        qn = backend.quote_name
     
    550558        setattr(cls, self.name, ReverseSingleRelatedObjectDescriptor(self))
    551559
    552560    def contribute_to_related_class(self, cls, related):
    553         setattr(cls, related.get_accessor_name(), ForeignRelatedObjectsDescriptor(related))
     561        related_accessor_name = related.get_accessor_name()
     562        remote_accessors = related.get_remote_accessors()
     563
     564        setattr(cls, related_accessor_name, ForeignRelatedObjectsDescriptor(related))
     565
     566        # Adding accessors with different managers
     567        for racc in remote_accessors:
     568            setattr(cls, "%s__%s" % (related_accessor_name, racc[0]), ForeignRelatedObjectsDescriptor(related, racc[1]))
    554569
    555570    def formfield(self, **kwargs):
    556571        defaults = {'form_class': forms.ModelChoiceField, 'queryset': self.rel.to._default_manager.all()}
     
    723738        # m2m relations to self do not have a ManyRelatedObjectsDescriptor,
    724739        # as it would be redundant - unless the field is non-symmetrical.
    725740        if related.model != related.parent_model or not self.rel.symmetrical:
    726             # Add the descriptor for the m2m relation
    727             setattr(cls, related.get_accessor_name(), ManyRelatedObjectsDescriptor(related))
     741            related_accessor_name = related.get_accessor_name()
     742            remote_accessors = related.get_remote_accessors()
     743
     744            # Add the descriptor for the m2m relation, using the default manager
     745            # AND keeping backwards compatibility
     746            setattr(cls, related_accessor_name, ManyRelatedObjectsDescriptor(related))
     747
     748            # Addin accessors with different managers
     749            for racc in remote_accessors:
     750                setattr(cls, "%s__%s" % (related_accessor_name, racc[0]), ManyRelatedObjectsDescriptor(related, racc[1]))
    728751
    729752        # Set up the accessors for the column names on the m2m table
    730753        self.m2m_column_name = curry(self._get_m2m_column_name, related)
  • django/db/models/related.py

    === modified file 'django/db/models/related.py'
     
    1919        self.name = '%s:%s' % (self.opts.app_label, self.opts.module_name)
    2020        self.var_name = self.opts.object_name.lower()
    2121
     22    def get_remote_accessors(self):
     23        d = []
     24        from django.db.models.manager import ManagerDescriptor
     25        for name, attr in self.model.__dict__.items():
     26            if isinstance(attr, ManagerDescriptor):
     27                d.append((name, attr.manager))
     28        return d
     29
    2230    def flatten_data(self, follow, obj=None):
    2331        new_data = {}
    2432        rel_instances = self.get_list(obj)
Back to Top