Ticket #7052: lookup-dictionaries-for-fixtures-django-1.1.diff

File lookup-dictionaries-for-fixtures-django-1.1.diff, 35.4 KB (added by robmadole@…, 15 years ago)

Same patch as juan@…, just fixed for 1.1 release

  • django/db/models/base.py

     
    378378
    379379    pk = property(_get_pk_val, _set_pk_val)
    380380
     381    def dump_related(self):
     382        """
     383        Returns a Python object that is the serialization for this Model.
     384
     385        By default, this method just returns the primary key for this Model.
     386
     387        If 'Meta.dump_relation' is a tuple of field names, then this
     388        method returns a dictionary of lookup fields for a QuerySet.
     389        The tuple in 'dump_relation' should also appear in
     390        'Meta.unique_together', so that only one object can be fetched
     391        based on this lookup.
     392        """
     393        dump_relation = getattr(self._meta, 'dump_relation', [])
     394        if dump_relation:
     395            return dict([(field_name, getattr(self, field_name))
     396                         for field_name in dump_relation])
     397        return self._get_pk_val()
     398
     399    def load_related(cls, value):
     400        """
     401        Returns the primary key for this Model, given a certain 'value'.
     402
     403        Use this in deserialization to handle objects that are created
     404        automatically (e.g. auth.Permissions or contenttypes.ContentType).
     405
     406        'value' can be:
     407            - None,
     408            - a primary key itself, in string or integer form,
     409            - a query dictionary, as generated by dump_related() above.
     410        """
     411        if value is None:
     412            return None
     413        if hasattr(value, 'iteritems'):
     414            # Case to handle query dictionaries
     415            lookup = {}
     416            for field_name, field_value in value.iteritems():
     417                field_name = str(field_name)
     418                if hasattr(field_value, 'iteritems'):
     419                    # Turn subqueries into primary keys
     420                    field = cls._meta.get_field(field_name)
     421                    field_value = field.rel.to.load_related(field_value)
     422                lookup[field_name] = field_value
     423            return cls._default_manager.get(**lookup)._get_pk_val()
     424        # Simple case for primary keys
     425        return cls._meta.pk.to_python(value)
     426    load_related = classmethod(load_related)
     427
    381428    def serializable_value(self, field_name):
    382429        """
    383430        Returns the value of the field name for this instance. If the field is
  • django/db/models/options.py

     
    1919get_verbose_name = lambda class_name: re.sub('(((?<=[a-z])[A-Z])|([A-Z](?![A-Z]|$)))', ' \\1', class_name).lower().strip()
    2020
    2121DEFAULT_NAMES = ('verbose_name', 'db_table', 'ordering',
    22                  'unique_together', 'permissions', 'get_latest_by',
     22                 'unique_together', 'dump_relation', 'permissions', 'get_latest_by',
    2323                 'order_with_respect_to', 'app_label', 'db_tablespace',
    2424                 'abstract', 'managed', 'proxy')
    2525
     
    3232        self.db_table = ''
    3333        self.ordering = []
    3434        self.unique_together =  []
     35        self.dump_relation = []
    3536        self.permissions =  []
    3637        self.object_name, self.app_label = None, app_label
    3738        self.get_latest_by = None
  • django/core/serializers/xml_serializer.py

     
    7373
    7474        self.xml.endElement("field")
    7575
     76    def _handle_related(self, related, depth):
     77        if hasattr(related, 'iteritems'):
     78            for name, value in related.iteritems():
     79                self.indent(depth)
     80                self.xml.startElement("lookup", attrs={"name" : name})
     81                self._handle_related(value, depth+1)
     82                self.xml.endElement("lookup")
     83            if related:
     84                self.indent(depth - 1)
     85        else:
     86            self.xml.characters(smart_unicode(related))
     87       
     88
    7689    def handle_fk_field(self, obj, field):
    7790        """
    7891        Called to handle a ForeignKey (we need to treat them slightly
     
    8396        if related is not None:
    8497            if field.rel.field_name == related._meta.pk.name:
    8598                # Related to remote object via primary key
    86                 related = related._get_pk_val()
     99                self._handle_related(related.dump_related(), depth=3)
    87100            else:
    88101                # Related to remote object via other field
    89                 related = getattr(related, field.rel.field_name)
    90             self.xml.characters(smart_unicode(related))
     102                self.xml.characters(smart_unicode(getattr(related, field.rel.field_name)))
    91103        else:
    92104            self.xml.addQuickElement("None")
    93105        self.xml.endElement("field")
     
    101113        if field.creates_table:
    102114            self._start_relational_field(field)
    103115            for relobj in getattr(obj, field.name).iterator():
    104                 self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
     116                related = relobj.dump_related()
     117                self.indent(3)
     118                if hasattr(related, 'iteritems'):
     119                    self.xml.startElement("object", {})
     120                    self._handle_related(related, depth=4)
     121                    self.xml.endElement("object")
     122                else:
     123                    self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
     124            self.indent(2)
    105125            self.xml.endElement("field")
    106126
    107127    def _start_relational_field(self, field):
     
    179199        # Return a DeserializedObject so that the m2m data has a place to live.
    180200        return base.DeserializedObject(Model(**data), m2m_data)
    181201
     202    def _handle_lookup_node(self, node):
     203        # There are <lookup> nodes inside `node`
     204        value = ""
     205        lookup = {}
     206        for n in node.childNodes:
     207            if n.nodeType in (node.TEXT_NODE, node.CDATA_SECTION_NODE):
     208                value += n.data.strip()
     209            elif n.nodeName == "lookup":
     210                lookup[str(n.getAttribute("name"))] = self._handle_lookup_node(n)
     211            else:
     212                raise base.DeserializationError("Unexpected <%s> node" % n.nodeName)
     213        if value and lookup:
     214            raise base.DeserializationError("Unexpected primary key inside <lookup> node")
     215        return lookup or value
     216
     217    def _handle_object_node(self, node, field, m2m):
     218        lookup = self._handle_lookup_node(node)
     219        if m2m:
     220            # Get the "pk" attribute from the <object> nodes
     221            pk = node.getAttribute("pk")
     222        elif not hasattr(lookup, 'iteritems'):
     223            # `node` should only contain TextNode
     224            pk = getInnerText(node).strip()
     225        else:
     226            # 'node' contains a lookup dictionary
     227            pk = False
     228        if not pk and not lookup:
     229            if m2m:
     230                raise base.DeserializationError("<object> node is missing the 'pk' attribute")
     231            else:
     232                raise base.DeserializationError("Must have either primary key or <lookup> nodes")
     233        if m2m and pk:
     234            return pk
     235        elif pk:
     236            return field.rel.to._meta.get_field(field.rel.field_name).to_python(pk)
     237        else:
     238            return field.rel.to.load_related(lookup)
     239
    182240    def _handle_fk_field_node(self, node, field):
    183241        """
    184242        Handle a <field> node for a ForeignKey
    185243        """
    186244        # Check if there is a child node named 'None', returning None if so.
    187         if node.getElementsByTagName('None'):
     245        if node.getElementsByTagName("None"):
    188246            return None
    189         else:
    190             return field.rel.to._meta.get_field(field.rel.field_name).to_python(
    191                        getInnerText(node).strip())
     247        return self._handle_object_node(node, field, m2m=False)
    192248
    193249    def _handle_m2m_field_node(self, node, field):
    194250        """
    195251        Handle a <field> node for a ManyToManyField.
    196252        """
    197         return [field.rel.to._meta.pk.to_python(
    198                     c.getAttribute("pk"))
    199                     for c in node.getElementsByTagName("object")]
     253        return [self._handle_object_node(c, field, m2m=True)
     254                for c in node.getElementsByTagName("object")]
     255        return result
    200256
    201257    def _get_model_from_node(self, node, attr):
    202258        """
  • django/core/serializers/python.py

     
    99from django.db import models
    1010from django.utils.encoding import smart_unicode, is_protected_type
    1111
     12class RelationDepthExceeded(RuntimeError):
     13    pass
     14
    1215class Serializer(base.Serializer):
    1316    """
    1417    Serializes a QuerySet to basic Python objects.
     
    4447        else:
    4548            self._current[field.name] = field.value_to_string(obj)
    4649
     50    def _handle_related(cls, related, depth, maxdepth):
     51        if depth > maxdepth:
     52            raise RelationDepthExceeded()
     53        if hasattr(related, 'dump_related'):
     54            related = related.dump_related()
     55            if hasattr(related, 'iteritems'):
     56                return dict([(k, cls._handle_related(v, depth+1, maxdepth))
     57                             for k, v in related.iteritems()])
     58        return smart_unicode(related, strings_only=True)
     59    _handle_related = classmethod(_handle_related)
     60
     61    def handle_related(cls, related, maxdepth=10):
     62        try:
     63            return cls._handle_related(related, depth=0, maxdepth=maxdepth)
     64        except RelationDepthExceeded:
     65            raise RelationDepthExceeded("%s has a circular dump dependency" %
     66                                        related)
     67    handle_related = classmethod(handle_related)
     68
    4769    def handle_fk_field(self, obj, field):
    4870        related = getattr(obj, field.name)
    4971        if related is not None:
    5072            if field.rel.field_name == related._meta.pk.name:
    5173                # Related to remote object via primary key
    52                 related = related._get_pk_val()
     74                related = self.handle_related(related)
    5375            else:
    5476                # Related to remote object via other field
    55                 related = getattr(related, field.rel.field_name)
    56         self._current[field.name] = smart_unicode(related, strings_only=True)
     77                related = smart_unicode(getattr(related, field.rel.field_name), strings_only=True)
     78        self._current[field.name] = related
    5779
    5880    def handle_m2m_field(self, obj, field):
    5981        if field.creates_table:
    60             self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
     82            self._current[field.name] = [self.handle_related(related)
    6183                               for related in getattr(obj, field.name).iterator()]
    6284
    6385    def getvalue(self):
     
    86108
    87109            # Handle M2M relations
    88110            if field.rel and isinstance(field.rel, models.ManyToManyRel):
    89                 m2m_convert = field.rel.to._meta.pk.to_python
    90                 m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
     111                m2m_convert = field.rel.to.load_related
     112                m2m_data[field.name] = [m2m_convert(pk) for pk in field_value]
    91113
    92114            # Handle FK fields
    93115            elif field.rel and isinstance(field.rel, models.ManyToOneRel):
    94                 if field_value is not None:
     116                if field_value is None:
     117                    data[field.attname] = None
     118                elif field.rel.field_name == field.rel.to._meta.pk.name:
     119                    data[field.attname] = field.rel.to.load_related(field_value)
     120                else:
    95121                    data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
    96                 else:
    97                     data[field.attname] = None
    98122
    99123            # Handle all other fields
    100124            else:
  • django/contrib/contenttypes/models.py

     
    7676        db_table = 'django_content_type'
    7777        ordering = ('name',)
    7878        unique_together = (('app_label', 'model'),)
     79        dump_relation = unique_together[0]
    7980
    8081    def __unicode__(self):
    8182        return self.name
    8283
     84    def load_related(cls, value):
     85        try:
     86            app_label = value['app_label']
     87            model = value['model']
     88        except (KeyError, TypeError):
     89            return super(ContentType, cls).load_related(value)
     90        return cls.objects.get_for_model(models.get_model(app_label, model))._get_pk_val()
     91    load_related = classmethod(load_related)
     92
    8393    def model_class(self):
    8494        "Returns the Python model class for this type of content."
    8595        from django.db import models
  • django/contrib/auth/models.py

     
    6868        verbose_name = _('permission')
    6969        verbose_name_plural = _('permissions')
    7070        unique_together = (('content_type', 'codename'),)
     71        dump_relation = unique_together[0]
    7172        ordering = ('content_type__app_label', 'codename')
    7273
    7374    def __unicode__(self):
  • tests/modeltests/fixtures/fixtures/fixture6.json

     
     1[
     2    {
     3        "pk": "1",
     4        "model": "fixtures.tag",
     5        "fields": {
     6            "name": "copyright",
     7            "tagged_type": {
     8                "app_label": "fixtures",
     9                "model": "article"
     10            },
     11            "tagged_id": "3"
     12        }
     13    },
     14    {
     15        "pk": "2",
     16        "model": "fixtures.tag",
     17        "fields": {
     18            "name": "law",
     19            "tagged_type": {
     20                "app_label": "fixtures",
     21                "model": "article"
     22            },
     23            "tagged_id": "3"
     24        }
     25    }
     26]
  • tests/modeltests/fixtures/fixtures/fixture8.json

     
     1[
     2    {
     3        "pk": "1",
     4        "model": "fixtures.visa",
     5        "fields": {
     6            "name": "Django Reinhardt",
     7            "permissions": [
     8                {
     9                    "codename": "add_user",
     10                    "content_type": {
     11                        "model": "user",
     12                        "app_label": "auth"
     13                    }
     14                },
     15                {
     16                    "codename": "change_user",
     17                    "content_type": {
     18                        "model": "user",
     19                        "app_label": "auth"
     20                    }
     21                },
     22                {
     23                    "codename": "delete_user",
     24                    "content_type": {
     25                        "model": "user",
     26                        "app_label": "auth"
     27                    }
     28                }
     29            ]
     30        }
     31    },
     32    {
     33        "pk": "2",
     34        "model": "fixtures.visa",
     35        "fields": {
     36            "name": "Stephane Grappelli",
     37            "permissions": [
     38                {
     39                    "codename": "add_user",
     40                    "content_type": {
     41                        "model": "user",
     42                        "app_label": "auth"
     43                    }
     44                }
     45            ]
     46        }
     47    },
     48    {
     49        "pk": "3",
     50        "model": "fixtures.visa",
     51        "fields": {
     52            "name": "Prince",
     53            "permissions": []
     54        }
     55    }
     56]
  • tests/modeltests/fixtures/fixtures/fixture7.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<django-objects version="1.0">
     3    <object pk="2" model="fixtures.tag">
     4        <field type="CharField" name="name">legal</field>
     5        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
     6            <lookup name="app_label">fixtures</lookup>
     7            <lookup name="model">article</lookup>
     8        </field>
     9        <field type="PositiveIntegerField" name="tagged_id">3</field>
     10    </object>
     11    <object pk="3" model="fixtures.tag">
     12        <field type="CharField" name="name">django</field>
     13        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
     14            <lookup name="app_label">fixtures</lookup>
     15            <lookup name="model">article</lookup>
     16        </field>
     17        <field type="PositiveIntegerField" name="tagged_id">4</field>
     18    </object>
     19    <object pk="4" model="fixtures.tag">
     20        <field type="CharField" name="name">world domination</field>
     21        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
     22            <lookup name="app_label">fixtures</lookup>
     23            <lookup name="model">article</lookup>
     24        </field>
     25        <field type="PositiveIntegerField" name="tagged_id">4</field>
     26    </object>
     27</django-objects>
  • tests/modeltests/fixtures/fixtures/fixture9.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<django-objects version="1.0">
     3    <object pk="2" model="fixtures.visa">
     4      <field type="CharField" name="name">Stephane Grappelli</field>
     5      <field to="auth.permission" name="permissions" rel="ManyToManyRel">
     6          <object>
     7              <lookup name="codename">add_user</lookup>
     8              <lookup name="content_type">
     9                  <lookup name="model">user</lookup>
     10                  <lookup name="app_label">auth</lookup>
     11              </lookup>
     12          </object>
     13          <object>
     14              <lookup name="codename">delete_user</lookup>
     15              <lookup name="content_type">
     16                  <lookup name="model">user</lookup>
     17                  <lookup name="app_label">auth</lookup>
     18              </lookup>
     19          </object>
     20      </field>
     21    </object>
     22    <object pk="3" model="fixtures.visa">
     23      <field type="CharField" name="name">Artist formerly known as &quot;Prince&quot;</field>
     24      <field to="auth.permission" name="permissions" rel="ManyToManyRel"></field>
     25    </object>
     26</django-objects>
  • tests/modeltests/fixtures/models.py

     
    88``FIXTURE_DIRS`` setting.
    99"""
    1010
     11from django.contrib.auth.models import Permission
     12from django.contrib.contenttypes import generic
     13from django.contrib.contenttypes.models import ContentType
    1114from django.db import models
    1215from django.conf import settings
    1316
     
    3134    class Meta:
    3235        ordering = ('-pub_date', 'headline')
    3336
     37class Blog(models.Model):
     38    name = models.CharField(max_length=100)
     39    featured = models.ForeignKey(Article, related_name='fixtures_featured_set')
     40    articles = models.ManyToManyField(Article, blank=True,
     41                                      related_name='fixtures_articles_set')
     42
     43    def __unicode__(self):
     44        return self.name
     45   
     46
     47class Tag(models.Model):
     48    name = models.CharField(max_length=100)
     49    tagged_type = models.ForeignKey(ContentType, related_name="fixtures_tag_set")
     50    tagged_id = models.PositiveIntegerField(default=0)
     51    tagged = generic.GenericForeignKey(ct_field='tagged_type',
     52                                       fk_field='tagged_id')
     53
     54    def __unicode__(self):
     55        return '<%s: %s> tagged "%s"' % (self.tagged.__class__.__name__,
     56                                         self.tagged, self.name)
     57
     58class Visa(models.Model):
     59    name = models.CharField(max_length=100)
     60    permissions = models.ManyToManyField(Permission, blank=True)
     61
     62    def __unicode__(self):
     63        return '%s %s' % (self.name,
     64                          ', '.join(p.name for p in self.permissions.all()))
     65
    3466__test__ = {'API_TESTS': """
    3567>>> from django.core import management
    3668>>> from django.db.models import get_app
     
    90122>>> Article.objects.all()
    91123[<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>]
    92124
     125# Load fixture 6, JSON file with dynamic ContentType fields. Testing ManyToOne.
     126>>> management.call_command('loaddata', 'fixture6.json', verbosity=0)
     127>>> Tag.objects.all()
     128[<Tag: <Article: Copyright is fine the way it is> tagged "copyright">, <Tag: <Article: Copyright is fine the way it is> tagged "law">]
     129
     130# Load fixture 7, XML file with dynamic ContentType fields. Testing ManyToOne.
     131>>> management.call_command('loaddata', 'fixture7.xml', verbosity=0)
     132>>> Tag.objects.all()
     133[<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">]
     134
     135# Load fixture 8, JSON file with dynamic Permission fields. Testing ManyToMany.
     136>>> management.call_command('loaddata', 'fixture8.json', verbosity=0)
     137>>> Visa.objects.all()
     138[<Visa: Django Reinhardt Can add user, Can change user, Can delete user>, <Visa: Stephane Grappelli Can add user>, <Visa: Prince >]
     139
     140# Load fixture 9, XML file with dynamic Permission fields. Testing ManyToMany.
     141>>> management.call_command('loaddata', 'fixture9.xml', verbosity=0)
     142>>> Visa.objects.all()
     143[<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" >]
     144
    93145# Load a fixture that doesn't exist
    94146>>> management.call_command('loaddata', 'unknown.json', verbosity=0)
    95147
    96148# object list is unaffected
    97149>>> Article.objects.all()
    98150[<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>]
     151
     152# Dump the current contents of the database as a JSON fixture
     153>>> management.call_command('dumpdata', 'fixtures', format='json')
     154[{"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": []}}]
     155
     156# Dump the current contents of the database as an XML fixture
     157>>> management.call_command('dumpdata', 'fixtures', format='xml')
     158<?xml version="1.0" encoding="utf-8"?>
     159<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>
    99160"""}
    100161
    101162# Database flushing does not work on MySQL with the default storage engine
     
    159220>>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS
    160221Multiple fixtures named 'fixture5' in '...fixtures'. Aborting.
    161222
     223>>> management.call_command('flush', verbosity=0, interactive=False)
     224
     225# Load back in fixture 1, we need the articles from it
     226>>> management.call_command('loaddata', 'fixture1', verbosity=0)
     227
     228# Try to load fixture 6 using format discovery
     229>>> management.call_command('loaddata', 'fixture6', verbosity=0)
     230>>> Tag.objects.all()
     231[<Tag: <Article: Time to reform copyright> tagged "copyright">, <Tag: <Article: Time to reform copyright> tagged "law">]
     232
     233# Dump the current contents of the database as a JSON fixture
     234>>> management.call_command('dumpdata', 'fixtures', format='json')
     235[{"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}}]
     236
     237# Dump the current contents of the database as an XML fixture
     238>>> management.call_command('dumpdata', 'fixtures', format='xml')
     239<?xml version="1.0" encoding="utf-8"?>
     240<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>
    162241"""
    163242
    164243from django.test import TestCase
  • docs/topics/db/queries.txt

     
    817817    # THIS WILL RAISE A FieldError
    818818    >>> Entry.objects.update(headline=F('blog__name'))
    819819
     820.. _related-objects:
     821
    820822Related objects
    821823===============
    822824
  • docs/ref/models/instances.txt

     
    413413More details on named URL patterns are in the :ref:`URL dispatch documentation
    414414<topics-http-urls>`.
    415415
     416.. _lookup-dictionary:
     417
     418Serializing and deserializing auto-created objects
     419==================================================
     420
     421.. versionadded:: development
     422
     423In certain circumstances, a model needs to create objects based on
     424other models in an application. For instance, whenever a
     425:class:`~django.db.models.Model` is defined, Django will eventually
     426create corresponding :class:`~django.contrib.auth.models.Permission`
     427objects.
     428
     429Models with a :ref:`forward relationship<related-objects>` to
     430automatically created objects, such as ``Permission``, need help when
     431serializing and deserializing these references. This happens whenever
     432you create or load a fixture. Since ``Permission`` objects can be
     433created in any order, they cannot be reliably referenced by their
     434primary keys during serialization. Instead, they are referenced by a
     435lookup dictionary.
     436
     437``dump_relation``
     438-----------------
     439
     440When writing a class that will be referenced by a lookup dictionary,
     441you should specify :attr:`Options.dump_relation`.  For more
     442information, see the :ref:`model option reference<ref-models-options>`.
     443
     444Methods for handling custom relations
     445-------------------------------------
     446
     447If :attr:`dump_related` is too inflexible for a particular model, you
     448can override the following methods to serialize and deserialize custom
     449lookup dictionaries.
     450
     451.. method:: Model.dump_related()
     452
     453Defines a ``dump_related()`` method to tell Django how to build a lookup
     454dictionary for this model. For example::
     455
     456    def dump_related(self):
     457        return {'year': self.year, 'month': self.month, 'day': self.day}
     458
     459Django uses this when serializing objects, which typically happens when
     460:djadmin:`dumpdata<dumpdata>` is run.
     461
     462.. method:: Model.load_related(value)
     463
     464Defines a ``load_related()`` method to tell Django how to find the
     465primary key for this model, when deserializing. It returns the primary
     466key associated with ``value``, which was created by
     467:meth:`Model.dump_related()`. For example::
     468
     469    def load_related(cls, value):
     470        year, month, day = value.year, value.month, value.day
     471        return cls.objects.get(year=year, month=month, day=day).id
     472    load_related = classmethod(load_related)
     473
     474Django uses this method when deserializing objects which have
     475:class:`~django.db.models.ForeignKey`,
     476:class:`~django.db.models.ManyToManyField`, or
     477:class:`~django.db.models.OneToOneField` relationships to objects that
     478were created automatically, such as
     479:class:`~django.contrib.auth.models.Permission` or
     480:class:`~django.contrib.contenttypes.models.ContentType` objects. This
     481typically happens when :djadmin:`loaddata<loaddata>` is run.
     482
    416483Extra instance methods
    417484======================
    418485
  • docs/ref/models/options.txt

     
    6060The name of the database tablespace to use for the model. If the backend doesn't
    6161support tablespaces, this option is ignored.
    6262
     63``dump_relation``
     64-----------------
     65
     66.. attribute:: Options.dump_relation
     67
     68.. versionadded:: development
     69
     70Set of field names that, taken together, that define a :ref:`lookup
     71dictionary<lookup-dictionary>` for serialization::
     72
     73    dump_relation = ("driver", "restaurant")
     74
     75It's used by :meth:`Model.dump_related()` to build a lookup dictionary
     76when serializing a reference to this model.
     77
     78Since these fields are used to fetch a single object, they should also
     79appear in :attr:`~Options.unique_together`.
     80
    6381``get_latest_by``
    6482-----------------
    6583
Back to Top