﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
14226	Bug in dumpdata dependency calculation involving ManyToManyFields	aneil	Rainer Koirikivi	"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."	Bug	closed	Core (Serialization)	1.2	Normal	fixed	easy-pickings		Accepted	1	0	0	0	0	0
