Django

Code

Changeset 3734

Show
Ignore:
Timestamp:
09/07/06 08:29:56 (2 years ago)
Author:
russellm
Message:

Fixes #2653 -- Modified related field utility methods to return None as the related name for symmetrical m2m fields on self. Updated validators and unit tests to account for the new behavior.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • django/trunk/django/core/management.py

    r3676 r3734  
    904904            rel_name = RelatedObject(f.rel.to, cls, f).get_accessor_name() 
    905905            rel_query_name = f.related_query_name() 
    906             for r in rel_opts.fields: 
    907                 if r.name == rel_name: 
    908                     e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
    909                 if r.name == rel_query_name: 
    910                     e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
    911             for r in rel_opts.many_to_many: 
    912                 if r.name == rel_name: 
    913                     e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
    914                 if r.name == rel_query_name: 
    915                     e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
    916             for r in rel_opts.get_all_related_many_to_many_objects(): 
    917                 if r.field is not f: 
     906            # If rel_name is none, there is no reverse accessor. 
     907            # (This only occurs for symmetrical m2m relations to self).  
     908            # If this is the case, there are no clashes to check for this field, as 
     909            # there are no reverse descriptors for this field. 
     910            if rel_name is not None: 
     911                for r in rel_opts.fields: 
     912                    if r.name == rel_name: 
     913                        e.add(opts, "Accessor for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
     914                    if r.name == rel_query_name: 
     915                        e.add(opts, "Reverse query name for m2m field '%s' clashes with field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
     916                for r in rel_opts.many_to_many: 
     917                    if r.name == rel_name: 
     918                        e.add(opts, "Accessor for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
     919                    if r.name == rel_query_name: 
     920                        e.add(opts, "Reverse query name for m2m field '%s' clashes with m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.name, f.name)) 
     921                for r in rel_opts.get_all_related_many_to_many_objects(): 
     922                    if r.field is not f: 
     923                        if r.get_accessor_name() == rel_name: 
     924                            e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
     925                        if r.get_accessor_name() == rel_query_name: 
     926                            e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
     927                for r in rel_opts.get_all_related_objects(): 
    918928                    if r.get_accessor_name() == rel_name: 
    919                         e.add(opts, "Accessor for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
     929                        e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
    920930                    if r.get_accessor_name() == rel_query_name: 
    921                         e.add(opts, "Reverse query name for m2m field '%s' clashes with related m2m field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
    922             for r in rel_opts.get_all_related_objects(): 
    923                 if r.get_accessor_name() == rel_name: 
    924                     e.add(opts, "Accessor for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
    925                 if r.get_accessor_name() == rel_query_name: 
    926                     e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
     931                        e.add(opts, "Reverse query name for m2m field '%s' clashes with related field '%s.%s'. Add a related_name argument to the definition for '%s'." % (f.name, rel_opts.object_name, r.get_accessor_name(), f.name)) 
    927932 
    928933        # Check admin attribute. 
  • django/trunk/django/db/models/related.py

    r3246 r3734  
    132132        # but this can be overridden with the "related_name" option. 
    133133        if self.field.rel.multiple: 
     134            # If this is a symmetrical m2m relation on self, there is no reverse accessor. 
     135            if getattr(self.field.rel, 'symmetrical', False) and self.model == self.parent_model: 
     136                return None 
    134137            return self.field.rel.related_name or (self.opts.object_name.lower() + '_set') 
    135138        else: 
  • django/trunk/tests/modeltests/invalid_models/models.py

    r3661 r3734  
    6969    foreign_2 = models.ForeignKey("SelfClashForeign", related_name='src_safe') 
    7070 
     71class ValidM2M(models.Model): 
     72    src_safe = models.CharField(maxlength=10) 
     73    validm2m = models.CharField(maxlength=10) 
     74 
     75    # M2M fields are symmetrical by default. Symmetrical M2M fields 
     76    # on self don't require a related accessor, so many potential 
     77    # clashes are avoided. 
     78    validm2m_set = models.ManyToManyField("ValidM2M") 
     79     
     80    m2m_1 = models.ManyToManyField("ValidM2M", related_name='id') 
     81    m2m_2 = models.ManyToManyField("ValidM2M", related_name='src_safe') 
     82 
     83    m2m_3 = models.ManyToManyField('self') 
     84    m2m_4 = models.ManyToManyField('self') 
     85 
    7186class SelfClashM2M(models.Model): 
    7287    src_safe = models.CharField(maxlength=10) 
    7388    selfclashm2m = models.CharField(maxlength=10) 
    7489 
    75     selfclashm2m_set = models.ManyToManyField("SelfClashM2M") 
    76     m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id') 
    77     m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe') 
     90    # Non-symmetrical M2M fields _do_ have related accessors, so  
     91    # there is potential for clashes. 
     92    selfclashm2m_set = models.ManyToManyField("SelfClashM2M", symmetrical=False) 
     93     
     94    m2m_1 = models.ManyToManyField("SelfClashM2M", related_name='id', symmetrical=False) 
     95    m2m_2 = models.ManyToManyField("SelfClashM2M", related_name='src_safe', symmetrical=False) 
    7896 
    79  
     97    m2m_3 = models.ManyToManyField('self', symmetrical=False) 
     98    m2m_4 = models.ManyToManyField('self', symmetrical=False) 
    8099 
    81100model_errors = """invalid_models.fielderrors: "charfield": CharFields require a "maxlength" attribute. 
     
    148167invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. 
    149168invalid_models.selfclashm2m: Reverse query name for m2m field 'selfclashm2m_set' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'selfclashm2m_set'. 
     169invalid_models.selfclashm2m: Accessor for m2m field 'selfclashm2m_set' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'selfclashm2m_set'. 
    150170invalid_models.selfclashm2m: Accessor for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. 
    151171invalid_models.selfclashm2m: Accessor for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. 
    152172invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_1' clashes with field 'SelfClashM2M.id'. Add a related_name argument to the definition for 'm2m_1'. 
    153173invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_2' clashes with field 'SelfClashM2M.src_safe'. Add a related_name argument to the definition for 'm2m_2'. 
     174invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. 
     175invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. 
     176invalid_models.selfclashm2m: Accessor for m2m field 'm2m_3' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_3'. 
     177invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. 
     178invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. 
     179invalid_models.selfclashm2m: Accessor for m2m field 'm2m_4' clashes with related m2m field 'SelfClashM2M.selfclashm2m_set'. Add a related_name argument to the definition for 'm2m_4'. 
     180invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_3' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_3'. 
     181invalid_models.selfclashm2m: Reverse query name for m2m field 'm2m_4' clashes with field 'SelfClashM2M.selfclashm2m'. Add a related_name argument to the definition for 'm2m_4'. 
    154182""" 
    155