Ticket #7052: t7052-surrogate-key.diff
File t7052-surrogate-key.diff, 26.9 KB (added by , 15 years ago) |
---|
-
django/contrib/auth/models.py
diff -r f266dfb70b06 django/contrib/auth/models.py
a b 47 47 class SiteProfileNotAvailable(Exception): 48 48 pass 49 49 50 class 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 50 58 class Permission(models.Model): 51 59 """The permissions system provides a way to assign permissions to specific users and groups of users. 52 60 … … 63 71 name = models.CharField(_('name'), max_length=50) 64 72 content_type = models.ForeignKey(ContentType) 65 73 codename = models.CharField(_('codename'), max_length=100) 74 objects = PermissionManager() 66 75 67 76 class Meta: 68 77 verbose_name = _('permission') … … 76 85 unicode(self.content_type), 77 86 unicode(self.name)) 78 87 88 def surrogate_key(self): 89 return '%s|%s' % (self.codename, self.content_type.surrogate_key()) 90 79 91 class Group(models.Model): 80 92 """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. 81 93 -
django/contrib/contenttypes/models.py
diff -r f266dfb70b06 django/contrib/contenttypes/models.py
a b 8 8 # This cache is shared by all the get_for_* methods. 9 9 _cache = {} 10 10 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 11 19 def get_for_model(self, model): 12 20 """ 13 21 Returns the ContentType object for a given model, creating the … … 93 101 so code that calls this method should catch it. 94 102 """ 95 103 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 47 47 def handle_fk_field(self, obj, field): 48 48 related = getattr(obj, field.name) 49 49 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() 53 52 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) 56 59 self._current[field.name] = smart_unicode(related, strings_only=True) 57 60 58 61 def handle_m2m_field(self, obj, field): 59 62 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) 61 68 for related in getattr(obj, field.name).iterator()] 62 69 63 70 def getvalue(self): … … 86 93 87 94 # Handle M2M relations 88 95 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 90 100 m2m_data[field.name] = [m2m_convert(smart_unicode(pk)) for pk in field_value] 91 101 92 102 # Handle FK fields 93 103 elif field.rel and isinstance(field.rel, models.ManyToOneRel): 94 104 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) 96 109 else: 97 110 data[field.attname] = None 98 111 -
django/core/serializers/xml_serializer.py
diff -r f266dfb70b06 django/core/serializers/xml_serializer.py
a b 81 81 self._start_relational_field(field) 82 82 related = getattr(obj, field.name) 83 83 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() 87 86 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) 90 93 self.xml.characters(smart_unicode(related)) 91 94 else: 92 95 self.xml.addQuickElement("None") … … 100 103 """ 101 104 if field.rel.through._meta.auto_created: 102 105 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' 103 112 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))}) 105 114 self.xml.endElement("field") 106 115 107 116 def _start_relational_field(self, field): … … 187 196 if node.getElementsByTagName('None'): 188 197 return None 189 198 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) 192 204 193 205 def _handle_m2m_field_node(self, node, field): 194 206 """ 195 207 Handle a <field> node for a ManyToManyField. 196 208 """ 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)) 199 216 for c in node.getElementsByTagName("object")] 200 217 201 218 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 "Prince"</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 8 8 ``FIXTURE_DIRS`` setting. 9 9 """ 10 10 11 from django.contrib.auth.models import Permission 12 from django.contrib.contenttypes import generic 13 from django.contrib.contenttypes.models import ContentType 11 14 from django.db import models 12 15 from django.conf import settings 13 16 … … 31 34 class Meta: 32 35 ordering = ('-pub_date', 'headline') 33 36 37 class 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 47 class 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 58 class 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 34 66 __test__ = {'API_TESTS': """ 35 67 >>> from django.core import management 36 68 >>> from django.db.models import get_app … … 90 122 >>> Article.objects.all() 91 123 [<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>] 92 124 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 93 145 # Load a fixture that doesn't exist 94 146 >>> management.call_command('loaddata', 'unknown.json', verbosity=0) 95 147 96 148 # object list is unaffected 97 149 >>> Article.objects.all() 98 150 [<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> 99 160 """} 100 161 101 162 # Database flushing does not work on MySQL with the default storage engine … … 159 220 >>> management.call_command('loaddata', 'fixture5', verbosity=0) # doctest: +ELLIPSIS 160 221 Multiple fixtures named 'fixture5' in '...fixtures'. Aborting. 161 222 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> 162 241 """ 163 242 164 243 from 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 13 13 specimens = models.Manager() 14 14 15 15 def __unicode__(self): 16 return self. common_name16 return self.name 17 17 18 18 def animal_pre_save_check(signal, sender, instance, **kwargs): 19 19 "A signal that is used to check the type of data loaded from fixtures" … … 69 69 class Widget(models.Model): 70 70 name = models.CharField(max_length=255) 71 71 72 class Meta: 73 ordering = ('name',) 74 75 def __unicode__(self): 76 return self.name 77 72 78 class WidgetProxy(Widget): 73 79 class Meta: 74 80 proxy = True 75 81 82 # Check for forward references in FKs and M2Ms with surrogate keys 83 84 class TestManager(models.Manager): 85 def get_by_surrogate(self, key): 86 return self.get(name=key) 87 88 class 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 101 class 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 114 class 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 76 122 __test__ = {'API_TESTS':""" 77 123 >>> from django.core import management 78 124 … … 192 238 >>> management.call_command('dumpdata', 'fixtures_regress', format='json') 193 239 [{"pk": 1, "model": "fixtures_regress.widget", "fields": {"name": "grommet"}}] 194 240 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 195 252 """}