Index: django/db/models/base.py
===================================================================
--- django/db/models/base.py	(revision 11593)
+++ django/db/models/base.py	(working copy)
@@ -378,6 +378,53 @@
 
     pk = property(_get_pk_val, _set_pk_val)
 
+    def dump_related(self):
+        """
+        Returns a Python object that is the serialization for this Model.
+
+        By default, this method just returns the primary key for this Model.
+
+        If 'Meta.dump_relation' is a tuple of field names, then this
+        method returns a dictionary of lookup fields for a QuerySet.
+        The tuple in 'dump_relation' should also appear in
+        'Meta.unique_together', so that only one object can be fetched
+        based on this lookup.
+        """
+        dump_relation = getattr(self._meta, 'dump_relation', [])
+        if dump_relation:
+            return dict([(field_name, getattr(self, field_name))
+                         for field_name in dump_relation])
+        return self._get_pk_val()
+
+    def load_related(cls, value):
+        """
+        Returns the primary key for this Model, given a certain 'value'.
+
+        Use this in deserialization to handle objects that are created
+        automatically (e.g. auth.Permissions or contenttypes.ContentType).
+
+        'value' can be:
+            - None,
+            - a primary key itself, in string or integer form,
+            - a query dictionary, as generated by dump_related() above.
+        """
+        if value is None:
+            return None
+        if hasattr(value, 'iteritems'):
+            # Case to handle query dictionaries
+            lookup = {}
+            for field_name, field_value in value.iteritems():
+                field_name = str(field_name)
+                if hasattr(field_value, 'iteritems'):
+                    # Turn subqueries into primary keys
+                    field = cls._meta.get_field(field_name)
+                    field_value = field.rel.to.load_related(field_value)
+                lookup[field_name] = field_value
+            return cls._default_manager.get(**lookup)._get_pk_val()
+        # Simple case for primary keys
+        return cls._meta.pk.to_python(value)
+    load_related = classmethod(load_related)
+
     def serializable_value(self, field_name):
         """
         Returns the value of the field name for this instance. If the field is
Index: django/db/models/options.py
===================================================================
--- django/db/models/options.py	(revision 11593)
+++ django/db/models/options.py	(working copy)
@@ -19,7 +19,7 @@
 get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
 
 DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
-                 'unique_together', 'permissions', 'get_latest_by',
+                 'unique_together', 'dump_relation', 'permissions', 'get_latest_by',
                  'order_with_respect_to', 'app_label', 'db_tablespace',
                  'abstract', 'managed', 'proxy')
 
@@ -32,6 +32,7 @@
         self.db_table = ''
         self.ordering = []
         self.unique_together =  []
+        self.dump_relation = []
         self.permissions =  []
         self.object_name, self.app_label = None, app_label
         self.get_latest_by = None
Index: django/core/serializers/xml_serializer.py
===================================================================
--- django/core/serializers/xml_serializer.py	(revision 11593)
+++ django/core/serializers/xml_serializer.py	(working copy)
@@ -73,6 +73,19 @@
 
         self.xml.endElement("field")
 
+    def _handle_related(self, related, depth):
+        if hasattr(related, 'iteritems'):
+            for name, value in related.iteritems():
+                self.indent(depth)
+                self.xml.startElement("lookup", attrs={"name" : name})
+                self._handle_related(value, depth+1)
+                self.xml.endElement("lookup")
+            if related:
+                self.indent(depth - 1)
+        else:
+            self.xml.characters(smart_unicode(related))
+        
+
     def handle_fk_field(self, obj, field):
         """
         Called to handle a ForeignKey (we need to treat them slightly
@@ -83,11 +96,10 @@
         if related is not None:
             if field.rel.field_name == related._meta.pk.name:
                 # Related to remote object via primary key
-                related = related._get_pk_val()
+                self._handle_related(related.dump_related(), depth=3)
             else:
                 # Related to remote object via other field
-                related = getattr(related, field.rel.field_name)
-            self.xml.characters(smart_unicode(related))
+                self.xml.characters(smart_unicode(getattr(related, field.rel.field_name)))
         else:
             self.xml.addQuickElement("None")
         self.xml.endElement("field")
@@ -101,7 +113,15 @@
         if field.creates_table:
             self._start_relational_field(field)
             for relobj in getattr(obj, field.name).iterator():
-                self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
+                related = relobj.dump_related()
+                self.indent(3)
+                if hasattr(related, 'iteritems'):
+                    self.xml.startElement("object", {})
+                    self._handle_related(related, depth=4)
+                    self.xml.endElement("object")
+                else:
+                    self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
+            self.indent(2)
             self.xml.endElement("field")
 
     def _start_relational_field(self, field):
@@ -179,24 +199,60 @@
         # Return a DeserializedObject so that the m2m data has a place to live.
         return base.DeserializedObject(Model(**data), m2m_data)
 
+    def _handle_lookup_node(self, node):
+        # There are <lookup> nodes inside `node`
+        value = ""
+        lookup = {}
+        for n in node.childNodes:
+            if n.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE):
+                value += n.data.strip()
+            elif n.nodeName == "lookup":
+                lookup[str(n.getAttribute("name"))] = self._handle_lookup_node(n)
+            else:
+                raise base.DeserializationError("Unexpected <%s> node" % n.nodeName)
+        if value and lookup:
+            raise base.DeserializationError("Unexpected primary key inside <lookup> node")
+        return lookup or value
+
+    def _handle_object_node(self, node, field, m2m):
+        lookup = self._handle_lookup_node(node)
+        if m2m:
+            # Get the "pk" attribute from the <object> nodes
+            pk = node.getAttribute("pk")
+        elif not hasattr(lookup, 'iteritems'):
+            # `node` should only contain TextNode
+            pk = getInnerText(node).strip()
+        else:
+            # 'node' contains a lookup dictionary
+            pk = False
+        if not pk and not lookup:
+            if m2m:
+                raise base.DeserializationError("<object> node is missing the 'pk' attribute")
+            else:
+                raise base.DeserializationError("Must have either primary key or <lookup> nodes")
+        if m2m and pk:
+            return pk
+        elif pk:
+            return field.rel.to._meta.get_field(field.rel.field_name).to_python(pk)
+        else:
+            return field.rel.to.load_related(lookup)
+
     def _handle_fk_field_node(self, node, field):
         """
         Handle a <field> node for a ForeignKey
         """
         # Check if there is a child node named 'None', returning None if so.
-        if node.getElementsByTagName('None'):
+        if node.getElementsByTagName("None"):
             return None
-        else:
-            return field.rel.to._meta.get_field(field.rel.field_name).to_python(
-                       getInnerText(node).strip())
+        return self._handle_object_node(node, field, m2m=False)
 
     def _handle_m2m_field_node(self, node, field):
         """
         Handle a <field> node for a ManyToManyField.
         """
-        return [field.rel.to._meta.pk.to_python(
-                    c.getAttribute("pk"))
-                    for c in node.getElementsByTagName("object")]
+        return [self._handle_object_node(c, field, m2m=True)
+                for c in node.getElementsByTagName("object")]
+        return result
 
     def _get_model_from_node(self, node, attr):
         """
Index: django/core/serializers/python.py
===================================================================
--- django/core/serializers/python.py	(revision 11593)
+++ django/core/serializers/python.py	(working copy)
@@ -9,6 +9,9 @@
 from django.db import models
 from django.utils.encoding import smart_unicode, is_protected_type
 
+class RelationDepthExceeded(RuntimeError):
+    pass
+
 class Serializer(base.Serializer):
     """
     Serializes a QuerySet to basic Python objects.
@@ -44,20 +47,39 @@
         else:
             self._current[field.name] = field.value_to_string(obj)
 
+    def _handle_related(cls, related, depth, maxdepth):
+        if depth > maxdepth:
+            raise RelationDepthExceeded()
+        if hasattr(related, 'dump_related'):
+            related = related.dump_related()
+            if hasattr(related, 'iteritems'):
+                return dict([(k, cls._handle_related(v, depth+1, maxdepth))
+                             for k, v in related.iteritems()])
+        return smart_unicode(related, strings_only=True)
+    _handle_related = classmethod(_handle_related)
+
+    def handle_related(cls, related, maxdepth=10):
+        try:
+            return cls._handle_related(related, depth=0, maxdepth=maxdepth)
+        except RelationDepthExceeded:
+            raise RelationDepthExceeded("%s has a circular dump dependency" %
+                                        related)
+    handle_related = classmethod(handle_related)
+
     def handle_fk_field(self, obj, field):
         related = getattr(obj, field.name)
         if related is not None:
             if field.rel.field_name == related._meta.pk.name:
                 # Related to remote object via primary key
-                related = related._get_pk_val()
+                related = self.handle_related(related)
             else:
                 # Related to remote object via other field
-                related = getattr(related, field.rel.field_name)
-        self._current[field.name] = smart_unicode(related, strings_only=True)
+                related = smart_unicode(getattr(related, field.rel.field_name), strings_only=True)
+        self._current[field.name] = related
 
     def handle_m2m_field(self, obj, field):
         if field.creates_table:
-            self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
+            self._current[field.name] = [self.handle_related(related)
                                for related in getattr(obj, field.name).iterator()]
 
     def getvalue(self):
@@ -86,15 +108,17 @@
 
             # Handle M2M relations
             if field.rel and isinstance(field.rel, models.ManyToManyRel):
-                m2m_convert = field.rel.to._meta.pk.to_python
-                m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
+                m2m_convert = field.rel.to.load_related
+                m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
 
             # Handle FK fields
             elif field.rel and isinstance(field.rel, models.ManyToOneRel):
-                if field_value is not None:
+                if field_value is None:
+                    data[field.attname] = None
+                elif field.rel.field_name == field.rel.to._meta.pk.name:
+                    data[field.attname] = field.rel.to.load_related(field_value)
+                else:
                     data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
-                else:
-                    data[field.attname] = None
 
             # Handle all other fields
             else:
Index: django/contrib/contenttypes/models.py
===================================================================
--- django/contrib/contenttypes/models.py	(revision 11593)
+++ django/contrib/contenttypes/models.py	(working copy)
@@ -76,10 +76,20 @@
         db_table = 'django_content_type'
         ordering = ('name',)
         unique_together = (('app_label', 'model'),)
+        dump_relation = unique_together[0]
 
     def __unicode__(self):
         return self.name
 
+    def load_related(cls, value):
+        try:
+            app_label = value['app_label']
+            model = value['model']
+        except (KeyError, TypeError):
+            return super(ContentType, cls).load_related(value)
+        return cls.objects.get_for_model(models.get_model(app_label, model))._get_pk_val()
+    load_related = classmethod(load_related)
+
     def model_class(self):
         "Returns the Python model class for this type of content."
         from django.db import models
Index: django/contrib/auth/models.py
===================================================================
--- django/contrib/auth/models.py	(revision 11593)
+++ django/contrib/auth/models.py	(working copy)
@@ -68,6 +68,7 @@
         verbose_name = _('permission')
         verbose_name_plural = _('permissions')
         unique_together = (('content_type', 'codename'),)
+        dump_relation = unique_together[0]
         ordering = ('content_type__app_label', 'codename')
 
     def __unicode__(self):
Index: tests/modeltests/fixtures/fixtures/fixture6.json
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture6.json	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture6.json	(revision 0)
@@ -0,0 +1,26 @@
+[
+    {
+        "pk": "1", 
+        "model": "fixtures.tag", 
+        "fields": {
+            "name": "copyright",
+            "tagged_type": {
+                "app_label": "fixtures",
+                "model": "article"
+            },
+            "tagged_id": "3"
+        }
+    }, 
+    {
+        "pk": "2", 
+        "model": "fixtures.tag", 
+        "fields": {
+            "name": "law",
+            "tagged_type": {
+                "app_label": "fixtures",
+                "model": "article"
+            },
+            "tagged_id": "3"
+        }
+    }
+]
Index: tests/modeltests/fixtures/fixtures/fixture8.json
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture8.json	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture8.json	(revision 0)
@@ -0,0 +1,56 @@
+[
+    {
+	"pk": "1",
+	"model": "fixtures.visa",
+	"fields": {
+	    "name": "Django Reinhardt",
+	    "permissions": [
+		{
+		    "codename": "add_user",
+		    "content_type": {
+			"model": "user",
+			"app_label": "auth"
+		    }
+		},
+		{
+		    "codename": "change_user",
+		    "content_type": {
+			"model": "user",
+			"app_label": "auth"
+		    }
+		},
+		{
+		    "codename": "delete_user",
+		    "content_type": {
+			"model": "user",
+			"app_label": "auth"
+		    }
+		}
+	    ]
+	}
+    },
+    {
+	"pk": "2",
+	"model": "fixtures.visa",
+	"fields": {
+	    "name": "Stephane Grappelli",
+	    "permissions": [
+		{
+		    "codename": "add_user",
+		    "content_type": {
+			"model": "user",
+			"app_label": "auth"
+		    }
+		}
+	    ]
+	}
+    },
+    {
+	"pk": "3",
+	"model": "fixtures.visa",
+	"fields": {
+	    "name": "Prince",
+	    "permissions": []
+	}
+    }
+]
Index: tests/modeltests/fixtures/fixtures/fixture7.xml
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture7.xml	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture7.xml	(revision 0)
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+    <object pk="2" model="fixtures.tag">
+        <field type="CharField" name="name">legal</field>
+        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
+            <lookup name="app_label">fixtures</lookup>
+            <lookup name="model">article</lookup>
+        </field>
+        <field type="PositiveIntegerField" name="tagged_id">3</field>
+    </object>
+    <object pk="3" model="fixtures.tag">
+        <field type="CharField" name="name">django</field>
+        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
+            <lookup name="app_label">fixtures</lookup>
+            <lookup name="model">article</lookup>
+        </field>
+        <field type="PositiveIntegerField" name="tagged_id">4</field>
+    </object>
+    <object pk="4" model="fixtures.tag">
+        <field type="CharField" name="name">world domination</field>
+        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
+            <lookup name="app_label">fixtures</lookup>
+            <lookup name="model">article</lookup>
+        </field>
+        <field type="PositiveIntegerField" name="tagged_id">4</field>
+    </object>
+</django-objects>
Index: tests/modeltests/fixtures/fixtures/fixture9.xml
===================================================================
--- tests/modeltests/fixtures/fixtures/fixture9.xml	(revision 0)
+++ tests/modeltests/fixtures/fixtures/fixture9.xml	(revision 0)
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0">
+    <object pk="2" model="fixtures.visa">
+      <field type="CharField" name="name">Stephane Grappelli</field>
+      <field to="auth.permission" name="permissions" rel="ManyToManyRel">
+          <object>
+              <lookup name="codename">add_user</lookup>
+              <lookup name="content_type">
+                  <lookup name="model">user</lookup>
+                  <lookup name="app_label">auth</lookup>
+              </lookup>
+          </object>
+          <object>
+              <lookup name="codename">delete_user</lookup>
+              <lookup name="content_type">
+                  <lookup name="model">user</lookup>
+                  <lookup name="app_label">auth</lookup>
+              </lookup>
+          </object>
+      </field>
+    </object>
+    <object pk="3" model="fixtures.visa">
+      <field type="CharField" name="name">Artist formerly known as &quot;Prince&quot;</field>
+      <field to="auth.permission" name="permissions" rel="ManyToManyRel"></field>
+    </object>
+</django-objects>
Index: tests/modeltests/fixtures/models.py
===================================================================
--- tests/modeltests/fixtures/models.py	(revision 11593)
+++ tests/modeltests/fixtures/models.py	(working copy)
@@ -8,6 +8,9 @@
 ``FIXTURE_DIRS`` setting.
 """
 
+from django.contrib.auth.models import Permission
+from django.contrib.contenttypes import generic
+from django.contrib.contenttypes.models import ContentType
 from django.db import models
 from django.conf import settings
 
@@ -31,6 +34,35 @@
     class Meta:
         ordering = ('-pub_date', 'headline')
 
+class Blog(models.Model):
+    name = models.CharField(max_length=100)
+    featured = models.ForeignKey(Article, related_name='fixtures_featured_set')
+    articles = models.ManyToManyField(Article, blank=True,
+                                      related_name='fixtures_articles_set')
+
+    def __unicode__(self):
+        return self.name
+    
+
+class Tag(models.Model):
+    name = models.CharField(max_length=100)
+    tagged_type = models.ForeignKey(ContentType, related_name="fixtures_tag_set")
+    tagged_id = models.PositiveIntegerField(default=0)
+    tagged = generic.GenericForeignKey(ct_field='tagged_type',
+                                       fk_field='tagged_id')
+
+    def __unicode__(self):
+        return '<%s: %s> tagged "%s"' % (self.tagged.__class__.__name__,
+                                         self.tagged, self.name)
+
+class Visa(models.Model):
+    name = models.CharField(max_length=100)
+    permissions = models.ManyToManyField(Permission, blank=True)
+
+    def __unicode__(self):
+        return '%s %s' % (self.name,
+                          ', '.join(p.name for p in self.permissions.all()))
+
 __test__ = {'API_TESTS': """
 >>> from django.core import management
 >>> from django.db.models import get_app
@@ -90,12 +122,41 @@
 >>> Article.objects.all()
 [<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
 
+# Load fixture 6, JSON file with dynamic ContentType fields. Testing ManyToOne.
+>>> management.call_command('loaddata', 'fixture6.json', verbosity=0)
+>>> Tag.objects.all()
+[<Tag: <Article: Copyright is fine the way it is> tagged "copyright">, <Tag: <Article: Copyright is fine the way it is> tagged "law">]
+
+# Load fixture 7, XML file with dynamic ContentType fields. Testing ManyToOne.
+>>> management.call_command('loaddata', 'fixture7.xml', verbosity=0)
+>>> Tag.objects.all()
+[<Tag: <Article: Copyright is fine the way it is> tagged "copyright">, <Tag: <Article: Copyright is fine the way it is> tagged "legal">, <Tag: <Article: Django conquers world!> tagged "django">, <Tag: <Article: Django conquers world!> tagged "world domination">]
+
+# Load fixture 8, JSON file with dynamic Permission fields. Testing ManyToMany.
+>>> management.call_command('loaddata', 'fixture8.json', verbosity=0)
+>>> Visa.objects.all()
+[<Visa: Django Reinhardt Can add user, Can change user, Can delete user>, <Visa: Stephane Grappelli Can add user>, <Visa: Prince >]
+
+# Load fixture 9, XML file with dynamic Permission fields. Testing ManyToMany.
+>>> management.call_command('loaddata', 'fixture9.xml', verbosity=0)
+>>> Visa.objects.all()
+[<Visa: Django Reinhardt Can add user, Can change user, Can delete user>, <Visa: Stephane Grappelli Can add user, Can delete user>, <Visa: Artist formerly known as "Prince" >]
+
 # Load a fixture that doesn't exist
 >>> management.call_command('loaddata', 'unknown.json', verbosity=0)
 
 # object list is unaffected
 >>> Article.objects.all()
 [<Article: XML identified as leading cause of cancer>, <Article: Django conquers world!>, <Article: Copyright is fine the way it is>, <Article: Poker on TV is great!>, <Article: Python program becomes self aware>]
+
+# Dump the current contents of the database as a JSON fixture
+>>> management.call_command('dumpdata', 'fixtures', format='json')
+[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 5, "model": "fixtures.article", "fields": {"headline": "XML identified as leading cause of cancer", "pub_date": "2006-06-16 16:00:00"}}, {"pk": 4, "model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": "2006-06-16 15:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16 14:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is great!", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": {"model": "article", "app_label": "fixtures"}, "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": {"model": "article", "app_label": "fixtures"}, "name": "legal", "tagged_id": 3}}, {"pk": 3, "model": "fixtures.tag", "fields": {"tagged_type": {"model": "article", "app_label": "fixtures"}, "name": "django", "tagged_id": 4}}, {"pk": 4, "model": "fixtures.tag", "fields": {"tagged_type": {"model": "article", "app_label": "fixtures"}, "name": "world domination", "tagged_id": 4}}, {"pk": 1, "model": "fixtures.visa", "fields": {"name": "Django Reinhardt", "permissions": [{"codename": "add_user", "content_type": {"model": "user", "app_label": "auth"}}, {"codename": "change_user", "content_type": {"model": "user", "app_label": "auth"}}, {"codename": "delete_user", "content_type": {"model": "user", "app_label": "auth"}}]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"name": "Stephane Grappelli", "permissions": [{"codename": "add_user", "content_type": {"model": "user", "app_label": "auth"}}, {"codename": "delete_user", "content_type": {"model": "user", "app_label": "auth"}}]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"name": "Artist formerly known as \\"Prince\\"", "permissions": []}}]
+
+# Dump the current contents of the database as an XML fixture
+>>> management.call_command('dumpdata', 'fixtures', format='xml')
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="5" model="fixtures.article"><field type="CharField" name="headline">XML identified as leading cause of cancer</field><field type="DateTimeField" name="pub_date">2006-06-16 16:00:00</field></object><object pk="4" model="fixtures.article"><field type="CharField" name="headline">Django conquers world!</field><field type="DateTimeField" name="pub_date">2006-06-16 15:00:00</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Copyright is fine the way it is</field><field type="DateTimeField" name="pub_date">2006-06-16 14:00:00</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker on TV is great!</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.article"><field type="CharField" name="headline">Python program becomes self aware</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><lookup name="model">article</lookup><lookup name="app_label">fixtures</lookup></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">legal</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><lookup name="model">article</lookup><lookup name="app_label">fixtures</lookup></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="3" model="fixtures.tag"><field type="CharField" name="name">django</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><lookup name="model">article</lookup><lookup name="app_label">fixtures</lookup></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="4" model="fixtures.tag"><field type="CharField" name="name">world domination</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><lookup name="model">article</lookup><lookup name="app_label">fixtures</lookup></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="1" model="fixtures.visa"><field type="CharField" name="name">Django Reinhardt</field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><lookup name="codename">add_user</lookup><lookup name="content_type">user</lookup></object><object><lookup name="codename">change_user</lookup><lookup name="content_type">user</lookup></object><object><lookup name="codename">delete_user</lookup><lookup name="content_type">user</lookup></object></field></object><object pk="2" model="fixtures.visa"><field type="CharField" name="name">Stephane Grappelli</field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><lookup name="codename">add_user</lookup><lookup name="content_type">user</lookup></object><object><lookup name="codename">delete_user</lookup><lookup name="content_type">user</lookup></object></field></object><object pk="3" model="fixtures.visa"><field type="CharField" name="name">Artist formerly known as "Prince"</field><field to="auth.permission" name="permissions" rel="ManyToManyRel"></field></object></django-objects>
 """}
 
 # Database flushing does not work on MySQL with the default storage engine
@@ -159,6 +220,24 @@
 >>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS
 Multiple fixtures named 'fixture5' in '...fixtures'. Aborting.
 
+>>> management.call_command('flush', verbosity=0, interactive=False)
+
+# Load back in fixture 1, we need the articles from it
+>>> management.call_command('loaddata', 'fixture1', verbosity=0)
+
+# Try to load fixture 6 using format discovery
+>>> management.call_command('loaddata', 'fixture6', verbosity=0)
+>>> Tag.objects.all()
+[<Tag: <Article: Time to reform copyright> tagged "copyright">, <Tag: <Article: Time to reform copyright> tagged "law">]
+
+# Dump the current contents of the database as a JSON fixture
+>>> management.call_command('dumpdata', 'fixtures', format='json')
+[{"pk": 1, "model": "fixtures.category", "fields": {"description": "Latest news stories", "title": "News Stories"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Time to reform copyright", "pub_date": "2006-06-16 13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16 12:00:00"}}, {"pk": 1, "model": "fixtures.article", "fields": {"headline": "Python program becomes self aware", "pub_date": "2006-06-16 11:00:00"}}, {"pk": 1, "model": "fixtures.tag", "fields": {"tagged_type": {"model": "article", "app_label": "fixtures"}, "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": {"model": "article", "app_label": "fixtures"}, "name": "law", "tagged_id": 3}}]
+
+# Dump the current contents of the database as an XML fixture
+>>> management.call_command('dumpdata', 'fixtures', format='xml')
+<?xml version="1.0" encoding="utf-8"?>
+<django-objects version="1.0"><object pk="1" model="fixtures.category"><field type="CharField" name="title">News Stories</field><field type="TextField" name="description">Latest news stories</field></object><object pk="3" model="fixtures.article"><field type="CharField" name="headline">Time to reform copyright</field><field type="DateTimeField" name="pub_date">2006-06-16 13:00:00</field></object><object pk="2" model="fixtures.article"><field type="CharField" name="headline">Poker has no place on ESPN</field><field type="DateTimeField" name="pub_date">2006-06-16 12:00:00</field></object><object pk="1" model="fixtures.article"><field type="CharField" name="headline">Python program becomes self aware</field><field type="DateTimeField" name="pub_date">2006-06-16 11:00:00</field></object><object pk="1" model="fixtures.tag"><field type="CharField" name="name">copyright</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><lookup name="model">article</lookup><lookup name="app_label">fixtures</lookup></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="2" model="fixtures.tag"><field type="CharField" name="name">law</field><field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel"><lookup name="model">article</lookup><lookup name="app_label">fixtures</lookup></field><field type="PositiveIntegerField" name="tagged_id">3</field></object></django-objects>
 """
 
 from django.test import TestCase
Index: docs/topics/db/queries.txt
===================================================================
--- docs/topics/db/queries.txt	(revision 11593)
+++ docs/topics/db/queries.txt	(working copy)
@@ -817,6 +817,8 @@
     # THIS WILL RAISE A FieldError
     >>> Entry.objects.update(headline=F('blog__name'))
 
+.. _related-objects:
+
 Related objects
 ===============
 
Index: docs/ref/models/instances.txt
===================================================================
--- docs/ref/models/instances.txt	(revision 11593)
+++ docs/ref/models/instances.txt	(working copy)
@@ -413,6 +413,73 @@
 More details on named URL patterns are in the :ref:`URL dispatch documentation
 <topics-http-urls>`.
 
+.. _lookup-dictionary:
+
+Serializing and deserializing auto-created objects
+==================================================
+
+.. versionadded:: development
+
+In certain circumstances, a model needs to create objects based on
+other models in an application. For instance, whenever a
+:class:`~django.db.models.Model` is defined, Django will eventually
+create corresponding :class:`~django.contrib.auth.models.Permission`
+objects.
+
+Models with a :ref:`forward relationship<related-objects>` to
+automatically created objects, such as ``Permission``, need help when
+serializing and deserializing these references. This happens whenever
+you create or load a fixture. Since ``Permission`` objects can be
+created in any order, they cannot be reliably referenced by their
+primary keys during serialization. Instead, they are referenced by a
+lookup dictionary.
+
+``dump_relation``
+-----------------
+
+When writing a class that will be referenced by a lookup dictionary,
+you should specify :attr:`Options.dump_relation`.  For more
+information, see the :ref:`model option reference<ref-models-options>`.
+
+Methods for handling custom relations
+-------------------------------------
+
+If :attr:`dump_related` is too inflexible for a particular model, you
+can override the following methods to serialize and deserialize custom
+lookup dictionaries.
+
+.. method:: Model.dump_related()
+
+Defines a ``dump_related()`` method to tell Django how to build a lookup
+dictionary for this model. For example::
+
+    def dump_related(self):
+        return {'year': self.year, 'month': self.month, 'day': self.day}
+
+Django uses this when serializing objects, which typically happens when
+:djadmin:`dumpdata<dumpdata>` is run.
+
+.. method:: Model.load_related(value)
+
+Defines a ``load_related()`` method to tell Django how to find the
+primary key for this model, when deserializing. It returns the primary
+key associated with ``value``, which was created by
+:meth:`Model.dump_related()`. For example::
+
+    def load_related(cls, value):
+        year, month, day = value.year, value.month, value.day
+	return cls.objects.get(year=year, month=month, day=day).id
+    load_related = classmethod(load_related)
+
+Django uses this method when deserializing objects which have
+:class:`~django.db.models.ForeignKey`,
+:class:`~django.db.models.ManyToManyField`, or
+:class:`~django.db.models.OneToOneField` relationships to objects that
+were created automatically, such as
+:class:`~django.contrib.auth.models.Permission` or
+:class:`~django.contrib.contenttypes.models.ContentType` objects. This
+typically happens when :djadmin:`loaddata<loaddata>` is run.
+
 Extra instance methods
 ======================
 
Index: docs/ref/models/options.txt
===================================================================
--- docs/ref/models/options.txt	(revision 11593)
+++ docs/ref/models/options.txt	(working copy)
@@ -60,6 +60,24 @@
 The name of the database tablespace to use for the model. If the backend doesn't
 support tablespaces, this option is ignored.
 
+``dump_relation``
+-----------------
+
+.. attribute:: Options.dump_relation
+
+.. versionadded:: development
+
+Set of field names that, taken together, that define a :ref:`lookup
+dictionary<lookup-dictionary>` for serialization::
+
+    dump_relation = ("driver", "restaurant")
+
+It's used by :meth:`Model.dump_related()` to build a lookup dictionary
+when serializing a reference to this model.
+
+Since these fields are used to fetch a single object, they should also
+appear in :attr:`~Options.unique_together`.
+
 ``get_latest_by``
 -----------------
 
