Ticket #13252: 13252-natural-key-serializing-r17262.diff
File 13252-natural-key-serializing-r17262.diff, 39.7 KB (added by , 13 years ago) |
---|
-
django/core/management/commands/dumpdata.py
diff --git a/django/core/management/commands/dumpdata.py b/django/core/management/commands/dumpdata.py index 1622929..db0a5bc 100644
a b class Command(BaseCommand): 19 19 help='An appname or appname.ModelName to exclude (use multiple --exclude to exclude multiple apps/models).'), 20 20 make_option('-n', '--natural', action='store_true', dest='use_natural_keys', default=False, 21 21 help='Use natural keys if they are available.'), 22 make_option('--natural-foreign', action='store_true', dest='use_natural_foreign_keys', default=False, 23 help='Use natural foreign keys if they are available.'), 24 make_option('--natural-primary', action='store_true', dest='use_natural_primary_keys', default=False, 25 help='Use natural primary keys if they are available.'), 22 26 make_option('-a', '--all', action='store_true', dest='use_base_manager', default=False, 23 27 help="Use Django's base manager to dump all models stored in the database, including those that would otherwise be filtered or modified by a custom manager."), 24 28 ) … … class Command(BaseCommand): 36 40 excludes = options.get('exclude') 37 41 show_traceback = options.get('traceback') 38 42 use_natural_keys = options.get('use_natural_keys') 43 if use_natural_keys: 44 # raise pending deprecation warning. 45 pass 46 use_natural_foreign_keys = options.get('use_natural_foreign_keys') or use_natural_keys 47 use_natural_primary_keys = options.get('use_natural_primary_keys') 39 48 use_base_manager = options.get('use_base_manager') 40 49 41 50 excluded_apps = set() … … class Command(BaseCommand): 110 119 111 120 try: 112 121 return serializers.serialize(format, objects, indent=indent, 113 use_natural_keys=use_natural_keys) 122 use_natural_foreign_keys=use_natural_foreign_keys, 123 use_natural_primary_keys=use_natural_primary_keys) 114 124 except Exception, e: 115 125 if show_traceback: 116 126 raise -
django/core/serializers/base.py
diff --git a/django/core/serializers/base.py b/django/core/serializers/base.py index c7e6226..3b769e3 100644
a b class Serializer(object): 37 37 self.stream = options.pop("stream", StringIO()) 38 38 self.selected_fields = options.pop("fields", None) 39 39 self.use_natural_keys = options.pop("use_natural_keys", False) 40 if self.use_natural_keys: 41 # raise pending deprecation warning. 42 pass 43 self.use_natural_foreign_keys = options.pop('use_natural_foreign_keys', False) 44 self.use_natural_primary_keys = options.pop('use_natural_primary_keys', False) 40 45 41 46 self.start_serialization() 42 47 for obj in queryset: … … class DeserializedObject(object): 167 172 # prevent a second (possibly accidental) call to save() from saving 168 173 # the m2m data twice. 169 174 self.m2m_data = None 175 176 def build_instance(Model, data, db): 177 """ 178 Build a model instance. 179 180 If the model instance doesn't have a primary key and the model supports 181 natural keys, try to retrieve it from the database. 182 """ 183 obj = Model(**data) 184 if obj.pk is None and hasattr(Model, 'natural_key') and\ 185 hasattr(Model._default_manager, 'get_by_natural_key'): 186 pk = obj.natural_key() 187 try: 188 obj.pk = Model._default_manager.db_manager(db)\ 189 .get_by_natural_key(*pk).pk 190 except Model.DoesNotExist: 191 pass 192 return obj -
django/core/serializers/python.py
diff --git a/django/core/serializers/python.py b/django/core/serializers/python.py index a68ea21..7b839f0 100644
a b class Serializer(base.Serializer): 27 27 self._current = {} 28 28 29 29 def end_object(self, obj): 30 self.objects.append({ 31 "model" : smart_unicode(obj._meta), 32 "pk" : smart_unicode(obj._get_pk_val(), strings_only=True), 33 "fields" : self._current 34 }) 30 if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'): 31 data = { 32 "model": smart_unicode(obj._meta), 33 "pk": smart_unicode(obj._get_pk_val(), strings_only=True), 34 "fields": self._current, 35 } 36 else: 37 data = { 38 "model": smart_unicode(obj._meta), 39 "fields": self._current 40 } 41 self.objects.append(data) 35 42 self._current = None 36 43 37 44 def handle_field(self, obj, field): … … class Serializer(base.Serializer): 47 54 def handle_fk_field(self, obj, field): 48 55 related = getattr(obj, field.name) 49 56 if related is not None: 50 if self.use_natural_ keys and hasattr(related, 'natural_key'):57 if self.use_natural_foreign_keys and hasattr(related, 'natural_key'): 51 58 related = related.natural_key() 52 59 else: 53 60 if field.rel.field_name == related._meta.pk.name: … … class Serializer(base.Serializer): 60 67 61 68 def handle_m2m_field(self, obj, field): 62 69 if field.rel.through._meta.auto_created: 63 if self.use_natural_ keys and hasattr(field.rel.to, 'natural_key'):70 if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'): 64 71 m2m_value = lambda value: value.natural_key() 65 72 else: 66 73 m2m_value = lambda value: smart_unicode(value._get_pk_val(), strings_only=True) … … def Deserializer(object_list, **options): 82 89 for d in object_list: 83 90 # Look up the model and starting build a dict of data for it. 84 91 Model = _get_model(d["model"]) 85 data = {Model._meta.pk.attname : Model._meta.pk.to_python(d["pk"])} 92 data = {} 93 if 'pk' in d: 94 data[Model._meta.pk.attname] = Model._meta.pk.to_python(d['pk']) 86 95 m2m_data = {} 87 96 88 97 # Handle each field … … def Deserializer(object_list, **options): 127 136 else: 128 137 data[field.name] = field.to_python(field_value) 129 138 130 yield base.DeserializedObject(Model(**data), m2m_data) 139 obj = base.build_instance(Model, data, db) 140 141 yield base.DeserializedObject(obj, m2m_data) 131 142 132 143 def _get_model(model_identifier): 133 144 """ -
django/core/serializers/xml_serializer.py
diff --git a/django/core/serializers/xml_serializer.py b/django/core/serializers/xml_serializer.py index bcf5631..22205d9 100644
a b class Serializer(base.Serializer): 42 42 raise base.SerializationError("Non-model object (%s) encountered during serialization" % type(obj)) 43 43 44 44 self.indent(1) 45 obj_pk = obj._get_pk_val() 46 if obj_pk is None: 47 attrs = {"model": smart_unicode(obj._meta),} 48 else: 49 attrs = { 50 "pk": smart_unicode(obj._get_pk_val()), 51 "model": smart_unicode(obj._meta), 52 } 53 54 self.xml.startElement("object", attrs) 45 object_data = {"model": smart_unicode(obj._meta)} 46 if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'): 47 obj_pk = obj._get_pk_val() 48 if obj_pk is not None: 49 object_data['pk'] = smart_unicode(obj_pk) 50 self.xml.startElement("object", object_data) 55 51 56 52 def end_object(self, obj): 57 53 """ … … class Serializer(base.Serializer): 87 83 self._start_relational_field(field) 88 84 related = getattr(obj, field.name) 89 85 if related is not None: 90 if self.use_natural_ keys and hasattr(related, 'natural_key'):86 if self.use_natural_foreign_keys and hasattr(related, 'natural_key'): 91 87 # If related object has a natural key, use it 92 88 related = related.natural_key() 93 89 # Iterable natural keys are rolled out as subelements … … class Serializer(base.Serializer): 115 111 """ 116 112 if field.rel.through._meta.auto_created: 117 113 self._start_relational_field(field) 118 if self.use_natural_ keys and hasattr(field.rel.to, 'natural_key'):114 if self.use_natural_foreign_keys and hasattr(field.rel.to, 'natural_key'): 119 115 # If the objects in the m2m have a natural key, use it 120 116 def handle_m2m(value): 121 117 natural = value.natural_key() … … class Deserializer(base.Deserializer): 173 169 Model = self._get_model_from_node(node, "model") 174 170 175 171 # Start building a data dictionary from the object. 176 # If the node is missing the pk set it to None 177 if node.hasAttribute("pk"): 178 pk = node.getAttribute("pk") 179 else: 180 pk = None 181 182 data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)} 172 data = {} 173 if node.hasAttribute('pk'): 174 data[Model._meta.pk.attname] = Model._meta.pk.to_python( 175 node.getAttribute('pk')) 183 176 184 177 # Also start building a dict of m2m data (this is saved as 185 178 # {m2m_accessor_attribute : [list_of_related_objects]}) … … class Deserializer(base.Deserializer): 210 203 value = field.to_python(getInnerText(field_node).strip()) 211 204 data[field.name] = value 212 205 206 obj = base.build_instance(Model, data, self.db) 207 213 208 # Return a DeserializedObject so that the m2m data has a place to live. 214 return base.DeserializedObject( Model(**data), m2m_data)209 return base.DeserializedObject(obj, m2m_data) 215 210 216 211 def _handle_fk_field_node(self, node, field): 217 212 """ -
docs/topics/serialization.txt
diff --git a/docs/topics/serialization.txt b/docs/topics/serialization.txt index e6a94ca..25d998c 100644
a b into the primary key of an actual ``Person`` object. 313 313 fields will be effectively unique, you can still use those fields 314 314 as a natural key. 315 315 316 .. versionadded:: 1.4 317 318 Deserialization of objects with no primary key will always check whether the 319 model's manager has a ``get_by_natural_key()`` method and if so, use it to 320 populate the deserialized object's primary key. 321 316 322 Serialization of natural keys 317 323 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 318 324 … … Firstly, you need to add another method -- this time to the model itself:: 335 341 336 342 That method should always return a natural key tuple -- in this 337 343 example, ``(first name, last name)``. Then, when you call 338 ``serializers.serialize()``, you provide a ``use_natural_keys=True`` 339 argument:: 340 341 >>> serializers.serialize('json', [book1, book2], indent=2, use_natural_keys=True) 342 343 When ``use_natural_keys=True`` is specified, Django will use the 344 ``natural_key()`` method to serialize any reference to objects of the 345 type that defines the method. 344 ``serializers.serialize()``, you provide ``use_natural_foreign_keys=True`` 345 or ``use_natural_primary_keys=True`` arguments:: 346 347 >>> serializers.serialize('json', [book1, book2], indent=2, use_natural_foreign_keys=True, use_natural_primary_keys=True) 348 349 When ``use_natural_foreign_keys=True`` is specified, Django will use the 350 ``natural_key()`` method to serialize any foreign key reference to objects 351 of the type that defines the method. 352 353 When ``use_natural_primary_keys=True``is specified, Django will not provide the 354 primary key in the serialized data of this object since it can be calculated 355 during deserialization:: 356 357 ... 358 { 359 "model": "store.person", 360 "fields": { 361 "first_name": "Douglas", 362 "last_name": "Adams", 363 "birth_date": "1952-03-11", 364 } 365 } 366 ... 367 368 This can be useful when you need to load serialized data into an existing 369 database and you cannot guarantee that the serialized primary key value is not 370 already in use, and do not need to ensure that deserialized objects retain the 371 same primary keys. 346 372 347 373 If you are using :djadmin:`dumpdata` to generate serialized data, you 348 use the `--natural` command line flag to generate natural keys. 374 use the `--natural-foreign` and `--natural-primary` command line flags to 375 generate natural keys. 349 376 350 377 .. note:: 351 378 … … use the `--natural` command line flag to generate natural keys. 359 386 natural keys during serialization, but *not* be able to load those 360 387 key values, just don't define the ``get_by_natural_key()`` method. 361 388 389 .. versionchanged:: 1.4 390 391 Previously there was only a ``use_natural_keys`` argument for 392 ``serializers.serialize()`` and the `-n` or `--natural` command line flags. 393 These have been deprecated in favor of the ``use_natural_foreign_keys`` and 394 ``use_natural_primary_keys`` arguments, and the corresponding 395 `--natural-foreign` and `--natural-primary` command line flags. 396 397 The original argument and command line flags remain for backwards 398 compatibility, and map to the new ``use_natural_foreign_keys`` argument and 399 `--natural-foreign` command line flag. 400 362 401 Dependencies during serialization 363 402 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 364 403 -
tests/modeltests/fixtures/tests.py
diff --git a/tests/modeltests/fixtures/tests.py b/tests/modeltests/fixtures/tests.py index d22010d..7d4d62f 100644
a b class TestCaseFixtureLoadingTests(TestCase): 24 24 25 25 class FixtureLoadingTests(TestCase): 26 26 27 def _dumpdata_assert(self, args, output, format='json', natural_keys=False, 27 def _dumpdata_assert(self, args, output, format='json', 28 natural_foreign_keys=False, natural_primary_keys=False, 28 29 use_base_manager=False, exclude_list=[]): 29 30 new_io = StringIO.StringIO() 30 31 management.call_command('dumpdata', *args, **{'format':format, 31 32 'stdout':new_io, 32 33 'stderr':new_io, 33 'use_natural_keys':natural_keys, 34 'use_natural_foreign_keys':natural_foreign_keys, 35 'use_natural_primary_keys':natural_primary_keys, 34 36 'use_base_manager':use_base_manager, 35 37 'exclude': exclude_list}) 36 38 command_output = new_io.getvalue().strip() … … class FixtureLoadingTests(TestCase): 146 148 self._dumpdata_assert(['fixtures.book'], '[{"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [3, 1]}}]') 147 149 148 150 # But you can get natural keys if you ask for them and they are available 149 self._dumpdata_assert(['fixtures.book'], '[{"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_keys=True) 151 self._dumpdata_assert(['fixtures.book'], '[{"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_foreign_keys=True) 152 153 # You can also omit the primary keys for models that we can get later with natural keys. 154 self._dumpdata_assert(['fixtures.person'], '[{"fields": {"name": "Artist formerly known as \\"Prince\\""}, "model": "fixtures.person"}, {"fields": {"name": "Django Reinhardt"}, "model": "fixtures.person"}, {"fields": {"name": "Stephane Grappelli"}, "model": "fixtures.person"}]', natural_primary_keys=True) 150 155 151 156 # Dump the current contents of the database as a JSON fixture 152 self._dumpdata_assert(['fixtures'], '[{"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-16T16:00:00"}}, {"pk": 4, "model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": "2006-06-16T15:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is great!", "pub_date": "2006-06-16T11: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": 3, "model": "fixtures.person", "fields": {"name": "Artist formerly known as \\"Prince\\""}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 1, "model": "fixtures.visa", "fields": {"person": ["Django Reinhardt"], "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"person": ["Stephane Grappelli"], "permissions": [["add_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"person": ["Artist formerly known as \\"Prince\\""], "permissions": [["change_user", "auth", "user"]]}}, {"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_ keys=True)157 self._dumpdata_assert(['fixtures'], '[{"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-16T16:00:00"}}, {"pk": 4, "model": "fixtures.article", "fields": {"headline": "Django conquers world!", "pub_date": "2006-06-16T15:00:00"}}, {"pk": 3, "model": "fixtures.article", "fields": {"headline": "Copyright is fine the way it is", "pub_date": "2006-06-16T14:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker on TV is great!", "pub_date": "2006-06-16T11: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": 3, "model": "fixtures.person", "fields": {"name": "Artist formerly known as \\"Prince\\""}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 1, "model": "fixtures.visa", "fields": {"person": ["Django Reinhardt"], "permissions": [["add_user", "auth", "user"], ["change_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 2, "model": "fixtures.visa", "fields": {"person": ["Stephane Grappelli"], "permissions": [["add_user", "auth", "user"], ["delete_user", "auth", "user"]]}}, {"pk": 3, "model": "fixtures.visa", "fields": {"person": ["Artist formerly known as \\"Prince\\""], "permissions": [["change_user", "auth", "user"]]}}, {"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}, {"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_foreign_keys=True) 153 158 154 159 # Dump the current contents of the database as an XML fixture 155 160 self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> 156 <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-16T16: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-16T15: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-16T14: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-16T11: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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Artist formerly known as "Prince"</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="1" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Django Reinhardt</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="2" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Stephane Grappelli</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="3" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Artist formerly known as "Prince"</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="10" model="fixtures.book"><field type="CharField" name="name">Achieving self-awareness of Python programs</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"></field></object><object pk="1" model="fixtures.book"><field type="CharField" name="name">Music for all ages</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"><object><natural>Artist formerly known as "Prince"</natural></object><object><natural>Django Reinhardt</natural></object></field></object></django-objects>""", format='xml', natural_ keys=True)161 <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-16T16: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-16T15: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-16T14: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-16T11: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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">4</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Artist formerly known as "Prince"</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="1" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Django Reinhardt</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="2" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Stephane Grappelli</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>add_user</natural><natural>auth</natural><natural>user</natural></object><object><natural>delete_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="3" model="fixtures.visa"><field to="fixtures.person" name="person" rel="ManyToOneRel"><natural>Artist formerly known as "Prince"</natural></field><field to="auth.permission" name="permissions" rel="ManyToManyRel"><object><natural>change_user</natural><natural>auth</natural><natural>user</natural></object></field></object><object pk="10" model="fixtures.book"><field type="CharField" name="name">Achieving self-awareness of Python programs</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"></field></object><object pk="1" model="fixtures.book"><field type="CharField" name="name">Music for all ages</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"><object><natural>Artist formerly known as "Prince"</natural></object><object><natural>Django Reinhardt</natural></object></field></object></django-objects>""", format='xml', natural_foreign_keys=True) 157 162 158 163 def test_dumpdata_with_excludes(self): 159 164 # Load fixture1 which has a site, two articles, and a category … … class FixtureLoadingTests(TestCase): 292 297 ]) 293 298 294 299 # Dump the current contents of the database as a JSON fixture 295 self._dumpdata_assert(['fixtures'], '[{"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-16T13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12: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}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Prince"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}]', natural_ keys=True)300 self._dumpdata_assert(['fixtures'], '[{"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-16T13:00:00"}}, {"pk": 2, "model": "fixtures.article", "fields": {"headline": "Poker has no place on ESPN", "pub_date": "2006-06-16T12: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}}, {"pk": 1, "model": "fixtures.person", "fields": {"name": "Django Reinhardt"}}, {"pk": 3, "model": "fixtures.person", "fields": {"name": "Prince"}}, {"pk": 2, "model": "fixtures.person", "fields": {"name": "Stephane Grappelli"}}, {"pk": 10, "model": "fixtures.book", "fields": {"name": "Achieving self-awareness of Python programs", "authors": []}}]', natural_foreign_keys=True) 296 301 297 302 # Dump the current contents of the database as an XML fixture 298 303 self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> 299 <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-16T13: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-16T12: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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Prince</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="10" model="fixtures.book"><field type="CharField" name="name">Achieving self-awareness of Python programs</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"></field></object></django-objects>""", format='xml', natural_ keys=True)304 <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-16T13: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-16T12: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"><natural>fixtures</natural><natural>article</natural></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"><natural>fixtures</natural><natural>article</natural></field><field type="PositiveIntegerField" name="tagged_id">3</field></object><object pk="1" model="fixtures.person"><field type="CharField" name="name">Django Reinhardt</field></object><object pk="3" model="fixtures.person"><field type="CharField" name="name">Prince</field></object><object pk="2" model="fixtures.person"><field type="CharField" name="name">Stephane Grappelli</field></object><object pk="10" model="fixtures.book"><field type="CharField" name="name">Achieving self-awareness of Python programs</field><field to="fixtures.person" name="authors" rel="ManyToManyRel"></field></object></django-objects>""", format='xml', natural_foreign_keys=True) 300 305 301 306 class FixtureTransactionTests(TransactionTestCase): 302 307 def _dumpdata_assert(self, args, output, format='json'): -
tests/regressiontests/fixtures_regress/tests.py
diff --git a/tests/regressiontests/fixtures_regress/tests.py b/tests/regressiontests/fixtures_regress/tests.py index 5b8dc66..8101cd9 100644
a b class NaturalKeyFixtureTests(TestCase): 499 499 'fixtures_regress.store', 500 500 verbosity=0, 501 501 format='json', 502 use_natural_keys=True, 502 use_natural_foreign_keys=True, 503 use_natural_primary_keys=True, 503 504 stdout=stdout, 504 505 ) 505 506 self.assertEqual( 506 507 stdout.getvalue(), 507 """[{" pk": 2, "model": "fixtures_regress.store", "fields": {"name": "Amazon"}}, {"pk": 3, "model": "fixtures_regress.store", "fields": {"name": "Borders"}}, {"pk": 4, "model": "fixtures_regress.person", "fields": {"name": "Neal Stephenson"}}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]"""508 """[{"fields": {"name": "Amazon"}, "model": "fixtures_regress.store"}, {"fields": {"name": "Borders"}, "model": "fixtures_regress.store"}, {"fields": {"name": "Neal Stephenson"}, "model": "fixtures_regress.person"}, {"pk": 1, "model": "fixtures_regress.book", "fields": {"stores": [["Amazon"], ["Borders"]], "name": "Cryptonomicon", "author": ["Neal Stephenson"]}}]""" 508 509 ) 509 510 510 511 def test_dependency_sorting(self): -
tests/regressiontests/serializers_regress/models.py
diff --git a/tests/regressiontests/serializers_regress/models.py b/tests/regressiontests/serializers_regress/models.py index b3ae1fe..780c0cd 100644
a b class LengthModel(models.Model): 264 264 265 265 def __len__(self): 266 266 return self.data 267 268 #Tests for natural keys. 269 class BookManager(models.Manager): 270 def get_by_natural_key(self, isbn13): 271 return self.get(isbn13=isbn13) 272 273 class Book(models.Model): 274 isbn13 = models.CharField(max_length=14) 275 title = models.CharField(max_length=100) 276 277 objects = BookManager() 278 279 def natural_key(self): 280 return (self.isbn13,) -
tests/regressiontests/serializers_regress/tests.py
diff --git a/tests/regressiontests/serializers_regress/tests.py b/tests/regressiontests/serializers_regress/tests.py index 9c9022d..6653d92 100644
a b from .models import (BooleanData, CharData, DateData, DateTimeData, EmailData, 35 35 PositiveSmallIntegerPKData, SlugPKData, SmallPKData, USStatePKData, 36 36 AutoNowDateTimeData, ModifyingSaveData, InheritAbstractModel, 37 37 ExplicitInheritBaseModel, InheritBaseModel, BigIntegerData, LengthModel, 38 Tag, ComplexModel )38 Tag, ComplexModel, Book) 39 39 40 40 # A set of functions that can be used to recreate 41 41 # test data objects of various kinds. … … def streamTest(format, self): 450 450 self.assertEqual(string_data, stream.getvalue()) 451 451 stream.close() 452 452 453 def naturalKeyTest(format, self): 454 book1 = {'isbn13': '978-1590597255', 'title': 'The Definitive Guide to ' 455 'Django: Web Development Done Right'} 456 book2 = {'isbn13':'978-1590599969', 'title': 'Practical Django Projects'} 457 458 # Create the books. 459 adrian = Book.objects.create(**book1) 460 james = Book.objects.create(**book2) 461 462 # Serialize the books. 463 string_data = serializers.serialize(format, Book.objects.all(), indent=2, 464 use_natural_foreign_keys=True, 465 use_natural_primary_keys=True) 466 467 # Delete one book (to prove that the natural key generation will only 468 # restore the primary keys of books found in the database via the 469 # get_natural_key manager method). 470 james.delete() 471 472 # Deserialize and test. 473 books = list(serializers.deserialize(format, string_data)) 474 self.assertEqual(len(books), 2) 475 self.assertEqual(books[0].object.title, book1['title']) 476 self.assertEqual(books[0].object.pk, adrian.pk) 477 self.assertEqual(books[1].object.title, book2['title']) 478 self.assertEqual(books[1].object.pk, None) 479 453 480 for format in serializers.get_serializer_formats(): 454 481 setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format)) 455 482 setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format)) 483 setattr(SerializerTests, 'test_' + format + '_serializer_natural_keys', curry(naturalKeyTest, format)) 456 484 if format != 'python': 457 485 setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format))