Ticket #7052: t7052-surrogate-key.diff

File t7052-surrogate-key.diff, 26.9 KB (added by russellm, 6 years ago)

First draft of a surrogate key based solution

  • django/contrib/auth/models.py

    diff -r f266dfb70b06 django/contrib/auth/models.py
    a b  
    4747class SiteProfileNotAvailable(Exception):
    4848    pass
    4949
     50class PermissionManager(models.Manager):
     51    def get_by_surrogate(self, key):
     52        codename, ct_key = key.split('|',1)
     53        return self.get(
     54            codename=codename,
     55            content_type=ContentType.objects.get_by_surrogate(ct_key)
     56        )
     57
    5058class Permission(models.Model):
    5159    """The permissions system provides a way to assign permissions to specific users and groups of users.
    5260
     
    6371    name = models.CharField(_('name'), max_length=50)
    6472    content_type = models.ForeignKey(ContentType)
    6573    codename = models.CharField(_('codename'), max_length=100)
     74    objects = PermissionManager()
    6675
    6776    class Meta:
    6877        verbose_name = _('permission')
     
    7685            unicode(self.content_type),
    7786            unicode(self.name))
    7887
     88    def surrogate_key(self):
     89        return '%s|%s' % (self.codename, self.content_type.surrogate_key())
     90
    7991class Group(models.Model):
    8092    """Groups are a generic way of categorizing users to apply permissions, or some other label, to those users. A user can belong to any number of groups.
    8193
  • django/contrib/contenttypes/models.py

    diff -r f266dfb70b06 django/contrib/contenttypes/models.py
    a b  
    88    # This cache is shared by all the get_for_* methods.
    99    _cache = {}
    1010
     11    def get_by_surrogate(self, key):
     12        try:
     13            app_label, model = key.split(':')
     14            ct = self.__class__._cache[(app_label, model)]
     15        except KeyError:
     16            ct = self.get(app_label=app_label, model=model)
     17        return ct
     18
    1119    def get_for_model(self, model):
    1220        """
    1321        Returns the ContentType object for a given model, creating the
     
    93101        so code that calls this method should catch it.
    94102        """
    95103        return self.model_class()._default_manager.get(**kwargs)
     104
     105    def surrogate_key(self):
     106        return "%s:%s" % (self.app_label, self.model)
  • django/core/serializers/python.py

    diff -r f266dfb70b06 django/core/serializers/python.py
    a b  
    4747    def handle_fk_field(self, obj, field):
    4848        related = getattr(obj, field.name)
    4949        if related is not None:
    50             if field.rel.field_name == related._meta.pk.name:
    51                 # Related to remote object via primary key
    52                 related = related._get_pk_val()
     50            if hasattr(related, 'surrogate_key'):
     51                related = related.surrogate_key()
    5352            else:
    54                 # Related to remote object via other field
    55                 related = getattr(related, field.rel.field_name)
     53                if field.rel.field_name == related._meta.pk.name:
     54                    # Related to remote object via primary key
     55                    related = related._get_pk_val()
     56                else:
     57                    # Related to remote object via other field
     58                    related = getattr(related, field.rel.field_name)
    5659        self._current[field.name] = smart_unicode(related, strings_only=True)
    5760
    5861    def handle_m2m_field(self, obj, field):
    5962        if field.rel.through._meta.auto_created:
    60             self._current[field.name] = [smart_unicode(related._get_pk_val(), strings_only=True)
     63            if hasattr(field.rel.to, 'surrogate_key'):
     64                m2m_value = lambda value: value.surrogate_key()
     65            else:
     66                m2m_value = lambda value: value._get_pk_val()
     67            self._current[field.name] = [smart_unicode(m2m_value(related), strings_only=True)
    6168                               for related in getattr(obj, field.name).iterator()]
    6269
    6370    def getvalue(self):
     
    8693
    8794            # Handle M2M relations
    8895            if field.rel and isinstance(field.rel, models.ManyToManyRel):
    89                 m2m_convert = field.rel.to._meta.pk.to_python
     96                if hasattr(field.rel.to._default_manager, 'get_by_surrogate'):
     97                    m2m_convert = lambda value: field.rel.to._default_manager.get_by_surrogate(value).pk
     98                else:
     99                    m2m_convert = field.rel.to._meta.pk.to_python
    90100                m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value]
    91101
    92102            # Handle FK fields
    93103            elif field.rel and isinstance(field.rel, models.ManyToOneRel):
    94104                if field_value is not None:
    95                     data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
     105                    if hasattr(field.rel.to._default_manager, 'get_by_surrogate'):
     106                        data[field.attname] = field.rel.to._default_manager.get_by_surrogate(field_value).pk
     107                    else:
     108                        data[field.attname] = field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
    96109                else:
    97110                    data[field.attname] = None
    98111
  • django/core/serializers/xml_serializer.py

    diff -r f266dfb70b06 django/core/serializers/xml_serializer.py
    a b  
    8181        self._start_relational_field(field)
    8282        related = getattr(obj, field.name)
    8383        if related is not None:
    84             if field.rel.field_name == related._meta.pk.name:
    85                 # Related to remote object via primary key
    86                 related = related._get_pk_val()
     84            if hasattr(related, 'surrogate_key'):
     85                related = related.surrogate_key()
    8786            else:
    88                 # Related to remote object via other field
    89                 related = getattr(related, field.rel.field_name)
     87                if field.rel.field_name == related._meta.pk.name:
     88                    # Related to remote object via primary key
     89                    related = related._get_pk_val()
     90                else:
     91                    # Related to remote object via other field
     92                    related = getattr(related, field.rel.field_name)
    9093            self.xml.characters(smart_unicode(related))
    9194        else:
    9295            self.xml.addQuickElement("None")
     
    100103        """
    101104        if field.rel.through._meta.auto_created:
    102105            self._start_relational_field(field)
     106            if hasattr(field.rel.to, 'surrogate_key'):
     107                m2m_value = lambda value: value.surrogate_key()
     108                attr_name = 'surrogate'
     109            else:
     110                m2m_value = lambda value: value._get_pk_val()
     111                attr_name = 'pk'
    103112            for relobj in getattr(obj, field.name).iterator():
    104                 self.xml.addQuickElement("object", attrs={"pk" : smart_unicode(relobj._get_pk_val())})
     113                self.xml.addQuickElement("object", attrs={attr_name : smart_unicode(m2m_value(relobj))})
    105114            self.xml.endElement("field")
    106115
    107116    def _start_relational_field(self, field):
     
    187196        if node.getElementsByTagName('None'):
    188197            return None
    189198        else:
    190             return field.rel.to._meta.get_field(field.rel.field_name).to_python(
    191                        getInnerText(node).strip())
     199            field_value = getInnerText(node).strip()
     200            if hasattr(field.rel.to._default_manager, 'get_by_surrogate'):
     201                return field.rel.to._default_manager.get_by_surrogate(field_value).pk
     202            else:
     203                return field.rel.to._meta.get_field(field.rel.field_name).to_python(field_value)
    192204
    193205    def _handle_m2m_field_node(self, node, field):
    194206        """
    195207        Handle a <field> node for a ManyToManyField.
    196208        """
    197         return [field.rel.to._meta.pk.to_python(
    198                     c.getAttribute("pk"))
     209        if hasattr(field.rel.to._default_manager, 'get_by_surrogate'):
     210            m2m_convert = lambda value: field.rel.to._default_manager.get_by_surrogate(value).pk
     211            attr_name = 'surrogate'
     212        else:
     213            m2m_convert = field.rel.to._meta.pk.to_python
     214            attr_name = 'pk'
     215        return [m2m_convert(c.getAttribute(attr_name))
    199216                    for c in node.getElementsByTagName("object")]
    200217
    201218    def _get_model_from_node(self, node, attr):
  • new file tests/modeltests/fixtures/fixtures/fixture6.json

    diff -r f266dfb70b06 tests/modeltests/fixtures/fixtures/fixture6.json
    - +  
     1[
     2    {
     3        "pk": "1",
     4        "model": "fixtures.tag",
     5        "fields": {
     6            "name": "copyright",
     7            "tagged_type": "fixtures:article",
     8            "tagged_id": "3"
     9        }
     10    },
     11    {
     12        "pk": "2",
     13        "model": "fixtures.tag",
     14        "fields": {
     15            "name": "law",
     16            "tagged_type": "fixtures:article",
     17            "tagged_id": "3"
     18        }
     19    }
     20]
  • new file tests/modeltests/fixtures/fixtures/fixture7.xml

    diff -r f266dfb70b06 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            fixtures:article
     7        </field>
     8        <field type="PositiveIntegerField" name="tagged_id">3</field>
     9    </object>
     10    <object pk="3" model="fixtures.tag">
     11        <field type="CharField" name="name">django</field>
     12        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
     13            fixtures:article
     14        </field>
     15        <field type="PositiveIntegerField" name="tagged_id">4</field>
     16    </object>
     17    <object pk="4" model="fixtures.tag">
     18        <field type="CharField" name="name">world domination</field>
     19        <field to="contenttypes.contenttype" name="tagged_type" rel="ManyToOneRel">
     20            fixtures:article
     21        </field>
     22        <field type="PositiveIntegerField" name="tagged_id">4</field>
     23    </object>
     24</django-objects>
  • new file tests/modeltests/fixtures/fixtures/fixture8.json

    diff -r f266dfb70b06 tests/modeltests/fixtures/fixtures/fixture8.json
    - +  
     1[
     2    {
     3        "pk": "1",
     4        "model": "fixtures.visa",
     5        "fields": {
     6            "name": "Django Reinhardt",
     7            "permissions": [
     8                "add_user|auth:user",
     9                "change_user|auth:user",
     10                "delete_user|auth:user"
     11            ]
     12        }
     13    },
     14    {
     15        "pk": "2",
     16        "model": "fixtures.visa",
     17        "fields": {
     18            "name": "Stephane Grappelli",
     19            "permissions": [
     20                "add_user|auth:user"
     21            ]
     22        }
     23    },
     24        {
     25        "pk": "3",
     26        "model": "fixtures.visa",
     27        "fields": {
     28            "name": "Prince",
     29            "permissions": []
     30        }
     31    }
     32]
  • new file tests/modeltests/fixtures/fixtures/fixture9.xml

    diff -r f266dfb70b06 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 surrogate="add_user|auth:user"></object>
     7          <object surrogate="delete_user|auth:user"></object>
     8      </field>
     9    </object>
     10    <object pk="3" model="fixtures.visa">
     11      <field type="CharField" name="name">Artist formerly known as &quot;Prince&quot;</field>
     12      <field to="auth.permission" name="permissions" rel="ManyToManyRel"></field>
     13    </object>
     14</django-objects>
  • tests/modeltests/fixtures/models.py

    diff -r f266dfb70b06 tests/modeltests/fixtures/models.py
    a b  
    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": "fixtures:article", "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": "fixtures:article", "name": "legal", "tagged_id": 3}}, {"pk": 3, "model": "fixtures.tag", "fields": {"tagged_type": "fixtures:article", "name": "django", "tagged_id": 4}}, {"pk": 4, "model": "fixtures.tag", "fields": {"tagged_type": "fixtures:article", "name": "world domination", "tagged_id": 4}}, {"pk": 1, "model": "fixtures.visa", "fields": {"name": "Django Reinhardt", "permissions": ["add_user|auth:user", "change_user|auth:user", "delete_user|auth:user"]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"name": "Stephane Grappelli", "permissions": ["add_user|auth:user", "delete_user|auth:user"]}}, {"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">fixtures:article</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">fixtures:article</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">fixtures:article</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">fixtures:article</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 surrogate="add_user|auth:user"></object><object surrogate="change_user|auth:user"></object><object surrogate="delete_user|auth:user"></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 surrogate="add_user|auth:user"></object><object surrogate="delete_user|auth:user"></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": "fixtures:article", "name": "copyright", "tagged_id": 3}}, {"pk": 2, "model": "fixtures.tag", "fields": {"tagged_type": "fixtures:article", "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">fixtures:article</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">fixtures:article</field><field type="PositiveIntegerField" name="tagged_id">3</field></object></django-objects>
    162241"""
    163242
    164243from django.test import TestCase
  • new file tests/regressiontests/fixtures_regress/fixtures/forward_ref_lookup.json

    diff -r f266dfb70b06 tests/regressiontests/fixtures_regress/fixtures/forward_ref_lookup.json
    - +  
     1[
     2    {
     3        "pk": 1,
     4        "model": "fixtures_regress.book",
     5        "fields": {
     6            "name": "Cryptonomicon",
     7            "author": "Neal Stephenson",
     8            "stores": ["Amazon", "Borders"]
     9        }
     10    },
     11    {
     12        "pk": "2",
     13        "model": "fixtures_regress.store",
     14        "fields": {
     15            "name": "Amazon"
     16        }
     17    },
     18    {
     19        "pk": "3",
     20        "model": "fixtures_regress.store",
     21        "fields": {
     22            "name": "Borders"
     23        }
     24    },
     25    {
     26        "pk": "4",
     27        "model": "fixtures_regress.person",
     28        "fields": {
     29            "name": "Neal Stephenson"
     30        }
     31    }
     32]
     33 No newline at end of file
  • tests/regressiontests/fixtures_regress/models.py

    diff -r f266dfb70b06 tests/regressiontests/fixtures_regress/models.py
    a b  
    1313    specimens = models.Manager()
    1414
    1515    def __unicode__(self):
    16         return self.common_name
     16        return self.name
    1717
    1818def animal_pre_save_check(signal, sender, instance, **kwargs):
    1919    "A signal that is used to check the type of data loaded from fixtures"
     
    6969class Widget(models.Model):
    7070    name = models.CharField(max_length=255)
    7171
     72    class Meta:
     73        ordering = ('name',)
     74
     75    def __unicode__(self):
     76        return self.name
     77
    7278class WidgetProxy(Widget):
    7379    class Meta:
    7480        proxy = True
    7581
     82# Check for forward references in FKs and M2Ms with surrogate keys
     83
     84class TestManager(models.Manager):
     85    def get_by_surrogate(self, key):
     86        return self.get(name=key)
     87
     88class Store(models.Model):
     89    objects = TestManager()
     90    name = models.CharField(max_length=255)
     91
     92    class Meta:
     93        ordering = ('name',)
     94
     95    def __unicode__(self):
     96        return self.name
     97
     98    def surrogate_key():
     99        return self.name
     100
     101class Person(models.Model):
     102    objects = TestManager()
     103    name = models.CharField(max_length=255)
     104
     105    class Meta:
     106        ordering = ('name',)
     107
     108    def __unicode__(self):
     109        return self.name
     110
     111    def surrogate_key():
     112        return self.name
     113
     114class Book(models.Model):
     115    name = models.CharField(max_length=255)
     116    author = models.ForeignKey(Person)
     117    stores = models.ManyToManyField(Store)
     118
     119    class Meta:
     120        ordering = ('name',)
     121
    76122__test__ = {'API_TESTS':"""
    77123>>> from django.core import management
    78124
     
    192238>>> management.call_command('dumpdata', 'fixtures_regress', format='json')
    193239[{"pk": 1, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}]
    194240
     241###############################################
     242# Check that a fixture can contain forward references
     243>>> management.call_command('loaddata', 'forward_ref_lookup', verbosity=0)
     244
     245>>> b = Book.objects.get(name="Cryptonomicon")
     246>>> b.author
     247<Person: Neal Stephenson>
     248
     249>>> b.stores.all()
     250[<Store: Amazon>, <Store: Borders>]
     251
    195252"""}
Back to Top