parts/django/tests/modeltests/serializers/tests.py
changeset 69 c6bca38c1cbf
equal deleted inserted replaced
68:5ff1fc726848 69:c6bca38c1cbf
       
     1 # -*- coding: utf-8 -*-
       
     2 from datetime import datetime
       
     3 from StringIO import StringIO
       
     4 from xml.dom import minidom
       
     5 
       
     6 from django.core import serializers
       
     7 from django.db import transaction
       
     8 from django.test import TestCase, TransactionTestCase, Approximate
       
     9 from django.utils import simplejson
       
    10 
       
    11 from models import Category, Author, Article, AuthorProfile, Actor, \
       
    12                                     Movie, Score, Player, Team
       
    13 
       
    14 class SerializersTestBase(object):
       
    15     @staticmethod
       
    16     def _comparison_value(value):
       
    17         return value
       
    18 
       
    19     def setUp(self):
       
    20         sports = Category.objects.create(name="Sports")
       
    21         music = Category.objects.create(name="Music")
       
    22         op_ed = Category.objects.create(name="Op-Ed")
       
    23 
       
    24         self.joe = Author.objects.create(name="Joe")
       
    25         self.jane = Author.objects.create(name="Jane")
       
    26 
       
    27         self.a1 = Article(
       
    28             author=self.jane,
       
    29             headline="Poker has no place on ESPN",
       
    30             pub_date=datetime(2006, 6, 16, 11, 00)
       
    31         )
       
    32         self.a1.save()
       
    33         self.a1.categories = [sports, op_ed]
       
    34 
       
    35         self.a2 = Article(
       
    36             author=self.joe,
       
    37             headline="Time to reform copyright",
       
    38             pub_date=datetime(2006, 6, 16, 13, 00, 11, 345)
       
    39         )
       
    40         self.a2.save()
       
    41         self.a2.categories = [music, op_ed]
       
    42 
       
    43     def test_serialize(self):
       
    44         """Tests that basic serialization works."""
       
    45         serial_str = serializers.serialize(self.serializer_name,
       
    46                                            Article.objects.all())
       
    47         self.assertTrue(self._validate_output(serial_str))
       
    48 
       
    49     def test_serializer_roundtrip(self):
       
    50         """Tests that serialized content can be deserialized."""
       
    51         serial_str = serializers.serialize(self.serializer_name,
       
    52                                            Article.objects.all())
       
    53         models = list(serializers.deserialize(self.serializer_name, serial_str))
       
    54         self.assertEqual(len(models), 2)
       
    55 
       
    56     def test_altering_serialized_output(self):
       
    57         """
       
    58         Tests the ability to create new objects by
       
    59         modifying serialized content.
       
    60         """
       
    61         old_headline = "Poker has no place on ESPN"
       
    62         new_headline = "Poker has no place on television"
       
    63         serial_str = serializers.serialize(self.serializer_name,
       
    64                                            Article.objects.all())
       
    65         serial_str = serial_str.replace(old_headline, new_headline)
       
    66         models = list(serializers.deserialize(self.serializer_name, serial_str))
       
    67 
       
    68         # Prior to saving, old headline is in place
       
    69         self.assertTrue(Article.objects.filter(headline=old_headline))
       
    70         self.assertFalse(Article.objects.filter(headline=new_headline))
       
    71 
       
    72         for model in models:
       
    73             model.save()
       
    74 
       
    75         # After saving, new headline is in place
       
    76         self.assertTrue(Article.objects.filter(headline=new_headline))
       
    77         self.assertFalse(Article.objects.filter(headline=old_headline))
       
    78 
       
    79     def test_one_to_one_as_pk(self):
       
    80         """
       
    81         Tests that if you use your own primary key field
       
    82         (such as a OneToOneField), it doesn't appear in the
       
    83         serialized field list - it replaces the pk identifier.
       
    84         """
       
    85         profile = AuthorProfile(author=self.joe,
       
    86                                 date_of_birth=datetime(1970,1,1))
       
    87         profile.save()
       
    88         serial_str = serializers.serialize(self.serializer_name,
       
    89                                            AuthorProfile.objects.all())
       
    90         self.assertFalse(self._get_field_values(serial_str, 'author'))
       
    91 
       
    92         for obj in serializers.deserialize(self.serializer_name, serial_str):
       
    93             self.assertEqual(obj.object.pk, self._comparison_value(self.joe.pk))
       
    94 
       
    95     def test_serialize_field_subset(self):
       
    96         """Tests that output can be restricted to a subset of fields"""
       
    97         valid_fields = ('headline','pub_date')
       
    98         invalid_fields = ("author", "categories")
       
    99         serial_str = serializers.serialize(self.serializer_name,
       
   100                                     Article.objects.all(),
       
   101                                     fields=valid_fields)
       
   102         for field_name in invalid_fields:
       
   103             self.assertFalse(self._get_field_values(serial_str, field_name))
       
   104 
       
   105         for field_name in valid_fields:
       
   106             self.assertTrue(self._get_field_values(serial_str, field_name))
       
   107 
       
   108     def test_serialize_unicode(self):
       
   109         """Tests that unicode makes the roundtrip intact"""
       
   110         actor_name = u"Za\u017c\u00f3\u0142\u0107"
       
   111         movie_title = u'G\u0119\u015bl\u0105 ja\u017a\u0144'
       
   112         ac = Actor(name=actor_name)
       
   113         mv = Movie(title=movie_title, actor=ac)
       
   114         ac.save()
       
   115         mv.save()
       
   116 
       
   117         serial_str = serializers.serialize(self.serializer_name, [mv])
       
   118         self.assertEqual(self._get_field_values(serial_str, "title")[0], movie_title)
       
   119         self.assertEqual(self._get_field_values(serial_str, "actor")[0], actor_name)
       
   120 
       
   121         obj_list = list(serializers.deserialize(self.serializer_name, serial_str))
       
   122         mv_obj = obj_list[0].object
       
   123         self.assertEqual(mv_obj.title, movie_title)
       
   124 
       
   125     def test_serialize_with_null_pk(self):
       
   126         """
       
   127         Tests that serialized data with no primary key results
       
   128         in a model instance with no id
       
   129         """
       
   130         category = Category(name="Reference")
       
   131         serial_str = serializers.serialize(self.serializer_name, [category])
       
   132         pk_value = self._get_pk_values(serial_str)[0]
       
   133         self.assertFalse(pk_value)
       
   134 
       
   135         cat_obj = list(serializers.deserialize(self.serializer_name,
       
   136                                                serial_str))[0].object
       
   137         self.assertEqual(cat_obj.id, None)
       
   138 
       
   139     def test_float_serialization(self):
       
   140         """Tests that float values serialize and deserialize intact"""
       
   141         sc = Score(score=3.4)
       
   142         sc.save()
       
   143         serial_str = serializers.serialize(self.serializer_name, [sc])
       
   144         deserial_objs = list(serializers.deserialize(self.serializer_name,
       
   145                                                 serial_str))
       
   146         self.assertEqual(deserial_objs[0].object.score, Approximate(3.4, places=1))
       
   147 
       
   148     def test_custom_field_serialization(self):
       
   149         """Tests that custom fields serialize and deserialize intact"""
       
   150         team_str = "Spartak Moskva"
       
   151         player = Player()
       
   152         player.name = "Soslan Djanaev"
       
   153         player.rank = 1
       
   154         player.team = Team(team_str)
       
   155         player.save()
       
   156         serial_str = serializers.serialize(self.serializer_name,
       
   157                                            Player.objects.all())
       
   158         team = self._get_field_values(serial_str, "team")
       
   159         self.assertTrue(team)
       
   160         self.assertEqual(team[0], team_str)
       
   161 
       
   162         deserial_objs = list(serializers.deserialize(self.serializer_name, serial_str))
       
   163         self.assertEqual(deserial_objs[0].object.team.to_string(),
       
   164                          player.team.to_string())
       
   165 
       
   166     def test_pre_1000ad_date(self):
       
   167         """Tests that year values before 1000AD are properly formatted"""
       
   168         # Regression for #12524 -- dates before 1000AD get prefixed
       
   169         # 0's on the year
       
   170         a = Article.objects.create(
       
   171         author = self.jane,
       
   172         headline = "Nobody remembers the early years",
       
   173         pub_date = datetime(1, 2, 3, 4, 5, 6))
       
   174 
       
   175         serial_str = serializers.serialize(self.serializer_name, [a])
       
   176         date_values = self._get_field_values(serial_str, "pub_date")
       
   177         self.assertEquals(date_values[0], "0001-02-03 04:05:06")
       
   178 
       
   179     def test_pkless_serialized_strings(self):
       
   180         """
       
   181         Tests that serialized strings without PKs
       
   182         can be turned into models
       
   183         """
       
   184         deserial_objs = list(serializers.deserialize(self.serializer_name,
       
   185                                                      self.pkless_str))
       
   186         for obj in deserial_objs:
       
   187             self.assertFalse(obj.object.id)
       
   188             obj.save()
       
   189         self.assertEqual(Category.objects.all().count(), 4)
       
   190 
       
   191 
       
   192 class SerializersTransactionTestBase(object):
       
   193     def test_forward_refs(self):
       
   194         """
       
   195         Tests that objects ids can be referenced before they are
       
   196         defined in the serialization data.
       
   197         """
       
   198         # The deserialization process needs to be contained
       
   199         # within a transaction in order to test forward reference
       
   200         # handling.
       
   201         transaction.enter_transaction_management()
       
   202         transaction.managed(True)
       
   203         objs = serializers.deserialize(self.serializer_name, self.fwd_ref_str)
       
   204         for obj in objs:
       
   205             obj.save()
       
   206         transaction.commit()
       
   207         transaction.leave_transaction_management()
       
   208 
       
   209         for model_cls in (Category, Author, Article):
       
   210             self.assertEqual(model_cls.objects.all().count(), 1)
       
   211         art_obj = Article.objects.all()[0]
       
   212         self.assertEqual(art_obj.categories.all().count(), 1)
       
   213         self.assertEqual(art_obj.author.name, "Agnes")
       
   214 
       
   215 
       
   216 class XmlSerializerTestCase(SerializersTestBase, TestCase):
       
   217     serializer_name = "xml"
       
   218     pkless_str = """<?xml version="1.0" encoding="utf-8"?>
       
   219 <django-objects version="1.0">
       
   220     <object model="serializers.category">
       
   221         <field type="CharField" name="name">Reference</field>
       
   222     </object>
       
   223 </django-objects>"""
       
   224 
       
   225     @staticmethod
       
   226     def _comparison_value(value):
       
   227         # The XML serializer handles everything as strings, so comparisons
       
   228         # need to be performed on the stringified value
       
   229         return unicode(value)
       
   230 
       
   231     @staticmethod
       
   232     def _validate_output(serial_str):
       
   233         try:
       
   234             minidom.parseString(serial_str)
       
   235         except Exception:
       
   236             return False
       
   237         else:
       
   238             return True
       
   239 
       
   240     @staticmethod
       
   241     def _get_pk_values(serial_str):
       
   242         ret_list = []
       
   243         dom = minidom.parseString(serial_str)
       
   244         fields = dom.getElementsByTagName("object")
       
   245         for field in fields:
       
   246             ret_list.append(field.getAttribute("pk"))
       
   247         return ret_list
       
   248 
       
   249     @staticmethod
       
   250     def _get_field_values(serial_str, field_name):
       
   251         ret_list = []
       
   252         dom = minidom.parseString(serial_str)
       
   253         fields = dom.getElementsByTagName("field")
       
   254         for field in fields:
       
   255             if field.getAttribute("name") == field_name:
       
   256                 temp = []
       
   257                 for child in field.childNodes:
       
   258                     temp.append(child.nodeValue)
       
   259                 ret_list.append("".join(temp))
       
   260         return ret_list
       
   261 
       
   262 class XmlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
       
   263     serializer_name = "xml"
       
   264     fwd_ref_str = """<?xml version="1.0" encoding="utf-8"?>
       
   265 <django-objects version="1.0">
       
   266     <object pk="1" model="serializers.article">
       
   267         <field to="serializers.author" name="author" rel="ManyToOneRel">1</field>
       
   268         <field type="CharField" name="headline">Forward references pose no problem</field>
       
   269         <field type="DateTimeField" name="pub_date">2006-06-16 15:00:00</field>
       
   270         <field to="serializers.category" name="categories" rel="ManyToManyRel">
       
   271             <object pk="1"></object>
       
   272         </field>
       
   273     </object>
       
   274     <object pk="1" model="serializers.author">
       
   275         <field type="CharField" name="name">Agnes</field>
       
   276     </object>
       
   277     <object pk="1" model="serializers.category">
       
   278         <field type="CharField" name="name">Reference</field></object>
       
   279 </django-objects>"""
       
   280 
       
   281 
       
   282 class JsonSerializerTestCase(SerializersTestBase, TestCase):
       
   283     serializer_name = "json"
       
   284     pkless_str = """[{"pk": null, "model": "serializers.category", "fields": {"name": "Reference"}}]"""
       
   285 
       
   286     @staticmethod
       
   287     def _validate_output(serial_str):
       
   288         try:
       
   289             simplejson.loads(serial_str)
       
   290         except Exception:
       
   291             return False
       
   292         else:
       
   293             return True
       
   294 
       
   295     @staticmethod
       
   296     def _get_pk_values(serial_str):
       
   297         ret_list = []
       
   298         serial_list = simplejson.loads(serial_str)
       
   299         for obj_dict in serial_list:
       
   300             ret_list.append(obj_dict["pk"])
       
   301         return ret_list
       
   302 
       
   303     @staticmethod
       
   304     def _get_field_values(serial_str, field_name):
       
   305         ret_list = []
       
   306         serial_list = simplejson.loads(serial_str)
       
   307         for obj_dict in serial_list:
       
   308             if field_name in obj_dict["fields"]:
       
   309                 ret_list.append(obj_dict["fields"][field_name])
       
   310         return ret_list
       
   311 
       
   312 class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
       
   313     serializer_name = "json"
       
   314     fwd_ref_str = """[
       
   315     {
       
   316         "pk": 1,
       
   317         "model": "serializers.article",
       
   318         "fields": {
       
   319             "headline": "Forward references pose no problem",
       
   320             "pub_date": "2006-06-16 15:00:00",
       
   321             "categories": [1],
       
   322             "author": 1
       
   323         }
       
   324     },
       
   325     {
       
   326         "pk": 1,
       
   327         "model": "serializers.category",
       
   328         "fields": {
       
   329             "name": "Reference"
       
   330         }
       
   331     },
       
   332     {
       
   333         "pk": 1,
       
   334         "model": "serializers.author",
       
   335         "fields": {
       
   336             "name": "Agnes"
       
   337         }
       
   338     }]"""
       
   339 
       
   340 try:
       
   341     import yaml
       
   342 except ImportError:
       
   343     pass
       
   344 else:
       
   345     class YamlSerializerTestCase(SerializersTestBase, TestCase):
       
   346         serializer_name = "yaml"
       
   347         fwd_ref_str = """- fields:
       
   348     headline: Forward references pose no problem
       
   349     pub_date: 2006-06-16 15:00:00
       
   350     categories: [1]
       
   351     author: 1
       
   352   pk: 1
       
   353   model: serializers.article
       
   354 - fields:
       
   355     name: Reference
       
   356   pk: 1
       
   357   model: serializers.category
       
   358 - fields:
       
   359     name: Agnes
       
   360   pk: 1
       
   361   model: serializers.author"""
       
   362 
       
   363         pkless_str = """- fields:
       
   364     name: Reference
       
   365   pk: null
       
   366   model: serializers.category"""
       
   367 
       
   368         @staticmethod
       
   369         def _validate_output(serial_str):
       
   370             try:
       
   371                 yaml.load(StringIO(serial_str))
       
   372             except Exception:
       
   373                 return False
       
   374             else:
       
   375                 return True
       
   376 
       
   377         @staticmethod
       
   378         def _get_pk_values(serial_str):
       
   379             ret_list = []
       
   380             stream = StringIO(serial_str)
       
   381             for obj_dict in yaml.load(stream):
       
   382                 ret_list.append(obj_dict["pk"])
       
   383             return ret_list
       
   384 
       
   385         @staticmethod
       
   386         def _get_field_values(serial_str, field_name):
       
   387             ret_list = []
       
   388             stream = StringIO(serial_str)
       
   389             for obj_dict in yaml.load(stream):
       
   390                 if "fields" in obj_dict and field_name in obj_dict["fields"]:
       
   391                     field_value = obj_dict["fields"][field_name]
       
   392                     # yaml.load will return non-string objects for some
       
   393                     # of the fields we are interested in, this ensures that
       
   394                     # everything comes back as a string
       
   395                     if isinstance(field_value, basestring):
       
   396                         ret_list.append(field_value)
       
   397                     else:
       
   398                         ret_list.append(str(field_value))
       
   399             return ret_list
       
   400 
       
   401     class YamlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
       
   402         serializer_name = "yaml"
       
   403         fwd_ref_str = """- fields:
       
   404     headline: Forward references pose no problem
       
   405     pub_date: 2006-06-16 15:00:00
       
   406     categories: [1]
       
   407     author: 1
       
   408   pk: 1
       
   409   model: serializers.article
       
   410 - fields:
       
   411     name: Reference
       
   412   pk: 1
       
   413   model: serializers.category
       
   414 - fields:
       
   415     name: Agnes
       
   416   pk: 1
       
   417   model: serializers.author"""