#14226: Bug in dumpdata dependency calculation involving ManyToManyFields
---------------------------+------------------------------------------------
 Reporter:  aneil          |       Owner:  nobody    
   Status:  new            |   Milestone:            
Component:  Serialization  |     Version:  1.2       
 Keywords:                 |       Stage:  Unreviewed
Has_patch:  0              |  
---------------------------+------------------------------------------------
 The manage.py dumpdata command incorrectly interprets !ManyToMany
 relationships as dependencies of the model that declares them (rather than
 the other way around).

 In the example below are 5 models - User, Tag and Posting, where both User
 and Posting have M2M relationships to Tag via !UserTag and !PostingTag,
 respectively.  This should be serializable.

 Here are the actual dependencies:
 {{{
 User:  None
 Tag: None
 Posting:  User
 PostingTag: Posting, Tag
 UserTag:   User, Tag
 }}}
 However, dumpdata fails with this error:
 Error: Can't resolve dependencies for main.Posting, main.!PostingTag,
 main.Tag, main.User, main.!UserTag in serialized app list.

 {{{
 from django.db.models import
 Model,CharField,ForeignKey,ManyToManyField,TextField,DateTimeField
 class User(Model):
     username  = CharField(max_length=20)
     password = CharField(max_length=20)
     topics = ManyToManyField("Tag",through="UserTag")

     def natural_key(self):
         return (self.username,)

 class Posting(Model):
     user = ForeignKey(User)
     text = TextField()
     time = DateTimeField()

     def natural_key(self):
         return (self.user.username,self.time)

     natural_key.dependencies=['main.User']

 class Tag(Model):
     name      = CharField(max_length=20)
     postings = ManyToManyField(Posting,through="PostingTag")

     def natural_key(self):
         return (self.name,)

 class PostingTag(Model):
     tag = ForeignKey(Tag)
     posting = ForeignKey(Posting)

     def natural_key(self):
         return (self.tag.natural_key(),self.posting.natural_key())

 class UserTag(Model):
     user = ForeignKey(User)
     tag = ForeignKey(Tag)

     def natural_key(self):
         return (self.tag.natural_key(),self.user.natural_key())
 }}}

 The reason this occurs is invalid logic in
 django/core/management/commands/dumpdata.py in lines 152-155.  Here is the
 relevant code & context:

 {{{
 145            # Now add a dependency for any FK or M2M relation with
 146           # a model that defines a natural key
 147            for field in model._meta.fields:
 148                if hasattr(field.rel, 'to'):
 149                    rel_model = field.rel.to
 150                    if hasattr(rel_model, 'natural_key'):
 151                        deps.append(rel_model)
 152            for field in model._meta.many_to_many:
 153                rel_model = field.rel.to
 154                if hasattr(rel_model, 'natural_key'):
 155                    deps.append(rel_model)
 156            model_dependencies.append((model, deps))
 }}}

 Lines 152-155 treat M2M relations like FK relations.  This is incorrect.
 A Model named by an FK is a dependency, however, the model named by an M2M
 is not.

 The fix requires adding the M2M *table* to the model_list, and processing
 its dependencies accordingly.

 I've attached a simple test project that demonstrates the problem.

-- 
Ticket URL: <http://code.djangoproject.com/ticket/14226>
Django <http://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-upda...@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to