Ticket #14549: #14549-intermediary_m2m_disambiguation.diff

File #14549-intermediary_m2m_disambiguation.diff, 6.0 KB (added by German M. Bravo, 13 years ago)
  • django/db/models/fields/related.py

     
    998998        if kwargs['rel'].through is not None:
    999999            assert self.db_table is None, "Cannot specify a db_table if an intermediary model is used."
    10001000
     1001        self.source_fk_name = kwargs.pop('source_fk_name', None)
     1002        self.target_fk_name = kwargs.pop('target_fk_name', None)
     1003
    10011004        Field.__init__(self, **kwargs)
    10021005
    10031006        msg = _('Hold down "Control", or "Command" on a Mac, to select more than one.')
     
    10231026            return getattr(self, cache_attr)
    10241027        for f in self.rel.through._meta.fields:
    10251028            if hasattr(f,'rel') and f.rel and f.rel.to == related.model:
    1026                 setattr(self, cache_attr, getattr(f, attr))
    1027                 return getattr(self, cache_attr)
     1029                if not self.source_fk_name or self.source_fk_name == f.name:
     1030                    setattr(self, cache_attr, getattr(f, attr))
     1031                    return getattr(self, cache_attr)
    10281032
    10291033    def _get_m2m_reverse_attr(self, related, attr):
    10301034        "Function that can be curried to provide the related accessor or DB column name for the m2m table"
     
    10341038        found = False
    10351039        for f in self.rel.through._meta.fields:
    10361040            if hasattr(f,'rel') and f.rel and f.rel.to == related.parent_model:
    1037                 if related.model == related.parent_model:
     1041                if not self.target_fk_name and related.model == related.parent_model:
    10381042                    # If this is an m2m-intermediate to self,
    10391043                    # the first foreign key you find will be
    10401044                    # the source column. Keep searching for
     
    10441048                        break
    10451049                    else:
    10461050                        found = True
    1047                 else:
     1051                elif not self.target_fk_name or self.target_fk_name == f.name:
    10481052                    setattr(self, cache_attr, getattr(f, attr))
    10491053                    break
    10501054        return getattr(self, cache_attr)
  • django/core/management/validation.py

     
    160160                                )
    161161                            )
    162162                    else:
    163                         if rel_to == from_model:
     163                        if rel_to == from_model and (not getattr(f, 'source_fk_name', None) or f.source_fk_name == inter_field.name):
    164164                            if seen_from:
    165165                                e.add(opts, "Intermediary model %s has more "
    166166                                    "than one foreign key to %s, which is "
    167                                     "ambiguous and is not permitted." % (
     167                                    "ambiguous and is not permitted. Add an source_fk_name "
     168                                    "argument to the definition for %s." % (
    168169                                        f.rel.through._meta.object_name,
    169                                          from_model._meta.object_name
     170                                         from_model._meta.object_name,
     171                                         f.name
    170172                                     )
    171173                                 )
    172174                            else:
    173175                                seen_from = True
    174                         elif rel_to == to_model:
     176                        elif rel_to == to_model and (not getattr(f, 'target_fk_name', None) or f.target_fk_name == inter_field.name):
    175177                            if seen_to:
    176178                                e.add(opts, "Intermediary model %s has more "
    177                                     "than one foreign key to %s, which is "
    178                                     "ambiguous and is not permitted." % (
     179                                    "than one foreign key to %s. Add a target_fk_name "
     180                                    "argument to the definition for %s." % (
    179181                                        f.rel.through._meta.object_name,
    180                                         rel_to._meta.object_name
     182                                        rel_to._meta.object_name,
     183                                        f.name
    181184                                    )
    182185                                )
    183186                            else:
  • docs/topics/db/models.txt

     
    433433
    434434There are a few restrictions on the intermediate model:
    435435
    436     * Your intermediate model must contain one - and *only* one - foreign key
    437       to the target model (this would be ``Person`` in our example). If you
    438       have more than one foreign key, a validation error will be raised.
     436    * To automatically detect the target foreign key, your intermediate model
     437      must contain one - and *only* one - foreign key to the target model (this
     438      would be ``Person`` in our example). If you have more than one foreign
     439      key, you will need to specify the field name by specifying a
     440      :attr:`~django.db.models.ManyToManyField.target_fk_name`.
    439441
    440     * Your intermediate model must contain one - and *only* one - foreign key
    441       to the source model (this would be ``Group`` in our example). If you
    442       have more than one foreign key, a validation error will be raised.
     442    * To automatically detect the source foreign key, your intermediate model
     443      must contain one - and *only* one - foreign key to the source model (this
     444      would be ``Group`` in our example). If you have more than one foreign key,
     445      you will need to specify the field name by specifying a
     446      :attr:`~django.db.models.ManyToManyField.source_fk_name`.
    443447
    444448    * The only exception to this is a model which has a many-to-many
    445449      relationship to itself, through an intermediary model. In this
Back to Top