Ticket #13252: 13252-natural-key-serializing-r14995.diff
File 13252-natural-key-serializing-r14995.diff, 39.7 KB (added by , 14 years ago) |
---|
-
django/core/serializers/json.py
21 21 self.options.pop('stream', None) 22 22 self.options.pop('fields', None) 23 23 self.options.pop('use_natural_keys', None) 24 self.options.pop('use_natural_foreign_keys', None) 25 self.options.pop('use_natural_primary_keys', None) 24 26 simplejson.dump(self.objects, self.stream, cls=DjangoJSONEncoder, **self.options) 25 27 26 28 def getvalue(self): -
django/core/serializers/xml_serializer.py
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 } 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) 53 51 54 self.xml.startElement("object", attrs)55 56 52 def end_object(self, obj): 57 53 """ 58 54 Called after handling all fields for an object. … … 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 … … 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() … … 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 172 data = {} 173 if node.hasAttribute('pk'): 174 data[Model._meta.pk.attname] = Model._meta.pk.to_python( 175 node.getAttribute('pk')) 181 176 182 data = {Model._meta.pk.attname : Model._meta.pk.to_python(pk)}183 184 177 # Also start building a dict of m2m data (this is saved as 185 178 # {m2m_accessor_attribute : [list_of_related_objects]}) 186 179 m2m_data = {} … … 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 """ -
django/core/serializers/base.py
34 34 self.stream = options.get("stream", StringIO()) 35 35 self.selected_fields = options.get("fields") 36 36 self.use_natural_keys = options.get("use_natural_keys", False) 37 if self.use_natural_keys: 38 # raise pending deprecation warning. 39 pass 40 self.use_natural_foreign_keys = options.get("use_natural_foreign_keys", False) or self.use_natural_keys 41 self.use_natural_primary_keys = options.get("use_natural_primary_keys", False) 37 42 38 43 self.start_serialization() 39 44 for obj in queryset: … … 170 175 # prevent a second (possibly accidental) call to save() from saving 171 176 # the m2m data twice. 172 177 self.m2m_data = None 178 179 def build_instance(Model, data, db): 180 """ 181 Build a model instance. 182 183 If the model instance doesn't have a primary key and the model supports 184 natural keys, try to retrieve it from the database. 185 """ 186 obj = Model(**data) 187 if obj.pk is None and hasattr(Model, 'natural_key') and\ 188 hasattr(Model._default_manager, 'get_by_natural_key'): 189 pk = obj.natural_key() 190 try: 191 obj.pk = Model._default_manager.db_manager(db)\ 192 .get_by_natural_key(*pk).pk 193 except Model.DoesNotExist: 194 pass 195 return obj -
django/core/serializers/pyyaml.py
41 41 self.options.pop('stream', None) 42 42 self.options.pop('fields', None) 43 43 self.options.pop('use_natural_keys', None) 44 self.options.pop('use_natural_foreign_keys', None) 45 self.options.pop('use_natural_primary_keys', None) 44 46 yaml.dump(self.objects, self.stream, Dumper=DjangoSafeDumper, **self.options) 45 47 46 48 def getvalue(self): -
django/core/serializers/python.py
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): … … 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: … … 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) … … 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 … … 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) 131 140 141 yield base.DeserializedObject(obj, m2m_data) 142 132 143 def _get_model(model_identifier): 133 144 """ 134 145 Helper to look up a model from an "app_label.module_name" string. -
django/core/management/commands/dumpdata.py
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 ) … … 37 41 excludes = options.get('exclude',[]) 38 42 show_traceback = options.get('traceback', False) 39 43 use_natural_keys = options.get('use_natural_keys', False) 44 if use_natural_keys: 45 # raise pending deprecation warning. 46 pass 47 use_natural_foreign_keys = options.get('use_natural_foreign_keys', False) or use_natural_keys 48 use_natural_primary_keys = options.get('use_natural_primary_keys', False) 40 49 use_base_manager = options.get('use_base_manager', False) 41 50 42 51 excluded_apps = set() … … 111 120 112 121 try: 113 122 return serializers.serialize(format, objects, indent=indent, 114 use_natural_keys=use_natural_keys) 123 use_natural_foreign_keys=use_natural_foreign_keys, 124 use_natural_primary_keys=use_natural_primary_keys) 115 125 except Exception, e: 116 126 if show_traceback: 117 127 raise -
tests/modeltests/fixtures/tests.py
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() … … 147 149 # By default, you get raw keys on dumpdata 148 150 self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [3, 1]}}]') 149 151 150 # But you can get natural keys if you ask for them and they are available151 self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_ keys=True)152 # But you can get natural foreign keys if you ask for them and they are available 153 self._dumpdata_assert(['fixtures.book'], '[{"pk": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_foreign_keys=True) 152 154 155 # You can also omit the primary keys for models that we can get later with natural keys. 156 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) 157 153 158 # Dump the current contents of the database as a JSON fixture 154 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-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": 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": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_ keys=True)159 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-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": 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": 1, "model": "fixtures.book", "fields": {"name": "Music for all ages", "authors": [["Artist formerly known as \\"Prince\\""], ["Django Reinhardt"]]}}]', natural_foreign_keys=True) 155 160 156 161 # Dump the current contents of the database as an XML fixture 157 162 self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> 158 <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"><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="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)163 <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"><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="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) 159 164 160 165 def test_dumpdata_with_excludes(self): 161 166 # Load fixture1 which has a site, two articles, and a category … … 286 291 ]) 287 292 288 293 # Dump the current contents of the database as a JSON fixture 289 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-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}}, {"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"}}]', natural_ keys=True)294 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-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}}, {"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"}}]', natural_foreign_keys=True) 290 295 291 296 # Dump the current contents of the database as an XML fixture 292 297 self._dumpdata_assert(['fixtures'], """<?xml version="1.0" encoding="utf-8"?> 293 <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"><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></django-objects>""", format='xml', natural_ keys=True)298 <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"><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></django-objects>""", format='xml', natural_foreign_keys=True) 294 299 295 300 class FixtureTransactionTests(TransactionTestCase): 296 301 def _dumpdata_assert(self, args, output, format='json'): -
tests/regressiontests/serializers_regress/tests.py
414 414 self.assertEqual(string_data, stream.getvalue()) 415 415 stream.close() 416 416 417 def naturalKeyTest(format, self): 418 book1 = {'isbn13': '978-1590597255', 'title': 'The Definitive Guide to ' 419 'Django: Web Development Done Right'} 420 book2 = {'isbn13':'978-1590599969', 'title': 'Practical Django Projects'} 421 422 # Create the books. 423 adrian = Book.objects.create(**book1) 424 james = Book.objects.create(**book2) 425 426 # Serialize the books. 427 string_data = serializers.serialize(format, Book.objects.all(), indent=2, 428 use_natural_foreign_keys=True, 429 use_natural_primary_keys=True) 430 431 # Delete one book (to prove that the natural key generation will only 432 # restore the primary keys of books found in the database via the 433 # get_natural_key manager method). 434 james.delete() 435 436 # Deserialize and test. 437 books = list(serializers.deserialize(format, string_data)) 438 self.assertEqual(len(books), 2) 439 self.assertEqual(books[0].object.title, book1['title']) 440 self.assertEqual(books[0].object.pk, adrian.pk) 441 self.assertEqual(books[1].object.title, book2['title']) 442 self.assertEqual(books[1].object.pk, None) 443 417 444 for format in serializers.get_serializer_formats(): 418 445 setattr(SerializerTests, 'test_' + format + '_serializer', curry(serializerTest, format)) 419 446 setattr(SerializerTests, 'test_' + format + '_serializer_fields', curry(fieldsTest, format)) 447 setattr(SerializerTests, 'test_' + format + '_serializer_natural_keys', curry(naturalKeyTest, format)) 420 448 if format != 'python': 421 449 setattr(SerializerTests, 'test_' + format + '_serializer_stream', curry(streamTest, format)) -
tests/regressiontests/serializers_regress/models.py
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/fixtures_regress/tests.py
450 450 'fixtures_regress.store', 451 451 verbosity=0, 452 452 format='json', 453 use_natural_keys=True, 453 use_natural_foreign_keys=True, 454 use_natural_primary_keys=True, 454 455 stdout=stdout, 455 456 ) 456 457 self.assertEqual( 457 458 stdout.getvalue(), 458 """[{" 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"]}}]"""459 """[{"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"]}}]""" 459 460 ) 460 461 461 462 def test_dependency_sorting(self): -
docs/topics/serialization.txt
307 307 fields will be effectively unique, you can still use those fields 308 308 as a natural key. 309 309 310 .. versionadded:: 1.3 311 312 Deserialization of objects with no primary key will always check whether the 313 model's manager has a ``get_by_natural_key()`` method and if so, use it to 314 populate the deserialized object's primary key. 315 310 316 Serialization of natural keys 311 317 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 312 318 … … 329 335 330 336 That method should always return a natural key tuple -- in this 331 337 example, ``(first name, last name)``. Then, when you call 332 ``serializers.serialize()``, you provide a ``use_natural_keys=True``333 argument::338 ``serializers.serialize()``, you provide ``use_natural_foreign_keys=True`` 339 or ``use_natural_primary_keys=True`` arguments:: 334 340 335 >>> serializers.serialize('json', [book1, book2], indent=2, use_natural_ keys=True)341 >>> serializers.serialize('json', [book1, book2], indent=2, use_natural_foreign_keys=True, use_natural_primary_keys=True) 336 342 337 When ``use_natural_ keys=True`` is specified, Django will use the338 ``natural_key()`` method to serialize any reference to objects of the339 type that defines the method.343 When ``use_natural_foreign_keys=True`` is specified, Django will use the 344 ``natural_key()`` method to serialize any foreign key reference to objects 345 of the type that defines the method. 340 346 347 When ``use_natural_primary_keys=True``is specified, Django will not provide the 348 primary key in the serialized data of this object since it can be calculated 349 during deserialization:: 350 351 ... 352 { 353 "model": "store.person", 354 "fields": { 355 "first_name": "Douglas", 356 "last_name": "Adams", 357 "birth_date": "1952-03-11", 358 } 359 } 360 ... 361 362 This can be useful when you need to load serialized data into an existing 363 database and you cannot guarantee that the serialized primary key value is not 364 already in use, and do not need to ensure that deserialized objects retain the 365 same primary keys. 366 341 367 If you are using :djadmin:`dumpdata` to generate serialized data, you 342 use the `--natural` command line flag to generate natural keys. 368 use the `--natural-foreign` and `--natural-primary` command line flags to 369 generate natural keys. 343 370 344 371 .. note:: 345 372 … … 353 380 natural keys during serialization, but *not* be able to load those 354 381 key values, just don't define the ``get_by_natural_key()`` method. 355 382 383 .. versionchanged:: 1.3 384 385 Previously there was only a ``use_natural_keys`` argument for 386 ``serializers.serialize()`` and the `-n` or `--natural` command line flags. 387 These have been deprecated in favor of the ``use_natural_foreign_keys`` and 388 ``use_natural_primary_keys`` arguments, and the corresponding 389 `--natural-foreign` and `--natural-primary` command line flags. 390 391 The original argument and command line flags remain for backwards 392 compatibility, and map to the new ``use_natural_foreign_keys`` argument and 393 `--natural-foreign` command line flag. 394 356 395 Dependencies during serialization 357 396 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 358 397