mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			271 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			271 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import decimal
 | |
| import json
 | |
| import re
 | |
| 
 | |
| from django.core import serializers
 | |
| from django.core.serializers.base import DeserializationError
 | |
| from django.db import models
 | |
| from django.test import TestCase, TransactionTestCase
 | |
| from django.test.utils import isolate_apps
 | |
| 
 | |
| from .models import Score
 | |
| from .tests import SerializersTestBase, SerializersTransactionTestBase
 | |
| 
 | |
| 
 | |
| class JsonlSerializerTestCase(SerializersTestBase, TestCase):
 | |
|     serializer_name = "jsonl"
 | |
|     pkless_str = [
 | |
|         '{"pk": null,"model": "serializers.category","fields": {"name": "Reference"}}',
 | |
|         '{"model": "serializers.category","fields": {"name": "Non-fiction"}}',
 | |
|     ]
 | |
|     pkless_str = "\n".join([s.replace("\n", "") for s in pkless_str])
 | |
| 
 | |
|     mapping_ordering_str = (
 | |
|         '{"model": "serializers.article","pk": %(article_pk)s,'
 | |
|         '"fields": {'
 | |
|         '"author": %(author_pk)s,'
 | |
|         '"headline": "Poker has no place on ESPN",'
 | |
|         '"pub_date": "2006-06-16T11:00:00",'
 | |
|         '"categories": [%(first_category_pk)s,%(second_category_pk)s],'
 | |
|         '"meta_data": []}}\n'
 | |
|     )
 | |
| 
 | |
|     @staticmethod
 | |
|     def _validate_output(serial_str):
 | |
|         try:
 | |
|             for line in serial_str.split("\n"):
 | |
|                 if line:
 | |
|                     json.loads(line)
 | |
|         except Exception:
 | |
|             return False
 | |
|         else:
 | |
|             return True
 | |
| 
 | |
|     @staticmethod
 | |
|     def _get_pk_values(serial_str):
 | |
|         serial_list = [json.loads(line) for line in serial_str.split("\n") if line]
 | |
|         return [obj_dict["pk"] for obj_dict in serial_list]
 | |
| 
 | |
|     @staticmethod
 | |
|     def _get_field_values(serial_str, field_name):
 | |
|         serial_list = [json.loads(line) for line in serial_str.split("\n") if line]
 | |
|         return [
 | |
|             obj_dict["fields"][field_name]
 | |
|             for obj_dict in serial_list
 | |
|             if field_name in obj_dict["fields"]
 | |
|         ]
 | |
| 
 | |
|     def test_no_indentation(self):
 | |
|         s = serializers.jsonl.Serializer()
 | |
|         json_data = s.serialize([Score(score=5.0), Score(score=6.0)], indent=2)
 | |
|         for line in json_data.splitlines():
 | |
|             self.assertIsNone(re.search(r".+,\s*$", line))
 | |
| 
 | |
|     @isolate_apps("serializers")
 | |
|     def test_custom_encoder(self):
 | |
|         class ScoreDecimal(models.Model):
 | |
|             score = models.DecimalField()
 | |
| 
 | |
|         class CustomJSONEncoder(json.JSONEncoder):
 | |
|             def default(self, o):
 | |
|                 if isinstance(o, decimal.Decimal):
 | |
|                     return str(o)
 | |
|                 return super().default(o)
 | |
| 
 | |
|         s = serializers.jsonl.Serializer()
 | |
|         json_data = s.serialize(
 | |
|             [ScoreDecimal(score=decimal.Decimal(1.0))],
 | |
|             cls=CustomJSONEncoder,
 | |
|         )
 | |
|         self.assertIn('"fields": {"score": "1"}', json_data)
 | |
| 
 | |
|     def test_json_deserializer_exception(self):
 | |
|         with self.assertRaises(DeserializationError):
 | |
|             for obj in serializers.deserialize("jsonl", """[{"pk":1}"""):
 | |
|                 pass
 | |
| 
 | |
|     def test_helpful_error_message_invalid_pk(self):
 | |
|         """
 | |
|         If there is an invalid primary key, the error message contains the
 | |
|         model associated with it.
 | |
|         """
 | |
|         test_string = (
 | |
|             '{"pk": "badpk","model": "serializers.player",'
 | |
|             '"fields": {"name": "Bob","rank": 1,"team": "Team"}}'
 | |
|         )
 | |
|         with self.assertRaisesMessage(
 | |
|             DeserializationError, "(serializers.player:pk=badpk)"
 | |
|         ):
 | |
|             list(serializers.deserialize("jsonl", test_string))
 | |
| 
 | |
|     def test_helpful_error_message_invalid_field(self):
 | |
|         """
 | |
|         If there is an invalid field value, the error message contains the
 | |
|         model associated with it.
 | |
|         """
 | |
|         test_string = (
 | |
|             '{"pk": "1","model": "serializers.player",'
 | |
|             '"fields": {"name": "Bob","rank": "invalidint","team": "Team"}}'
 | |
|         )
 | |
|         expected = "(serializers.player:pk=1) field_value was 'invalidint'"
 | |
|         with self.assertRaisesMessage(DeserializationError, expected):
 | |
|             list(serializers.deserialize("jsonl", test_string))
 | |
| 
 | |
|     def test_helpful_error_message_for_foreign_keys(self):
 | |
|         """
 | |
|         Invalid foreign keys with a natural key throws a helpful error message,
 | |
|         such as what the failing key is.
 | |
|         """
 | |
|         test_string = (
 | |
|             '{"pk": 1, "model": "serializers.category",'
 | |
|             '"fields": {'
 | |
|             '"name": "Unknown foreign key",'
 | |
|             '"meta_data": ["doesnotexist","metadata"]}}'
 | |
|         )
 | |
|         key = ["doesnotexist", "metadata"]
 | |
|         expected = "(serializers.category:pk=1) field_value was '%r'" % key
 | |
|         with self.assertRaisesMessage(DeserializationError, expected):
 | |
|             list(serializers.deserialize("jsonl", test_string))
 | |
| 
 | |
|     def test_helpful_error_message_for_many2many_non_natural(self):
 | |
|         """
 | |
|         Invalid many-to-many keys throws a helpful error message.
 | |
|         """
 | |
|         test_strings = [
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.article",
 | |
|                 "fields": {
 | |
|                     "author": 1,
 | |
|                     "headline": "Unknown many to many",
 | |
|                     "pub_date": "2014-09-15T10:35:00",
 | |
|                     "categories": [1, "doesnotexist"]
 | |
|                 }
 | |
|             }""",
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.author",
 | |
|                 "fields": {"name": "Agnes"}
 | |
|             }""",
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.category",
 | |
|                 "fields": {"name": "Reference"}
 | |
|             }""",
 | |
|         ]
 | |
|         test_string = "\n".join([s.replace("\n", "") for s in test_strings])
 | |
|         expected = "(serializers.article:pk=1) field_value was 'doesnotexist'"
 | |
|         with self.assertRaisesMessage(DeserializationError, expected):
 | |
|             list(serializers.deserialize("jsonl", test_string))
 | |
| 
 | |
|     def test_helpful_error_message_for_many2many_natural1(self):
 | |
|         """
 | |
|         Invalid many-to-many keys throws a helpful error message where one of a
 | |
|         list of natural keys is invalid.
 | |
|         """
 | |
|         test_strings = [
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.categorymetadata",
 | |
|                 "fields": {"kind": "author","name": "meta1","value": "Agnes"}
 | |
|             }""",
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.article",
 | |
|                 "fields": {
 | |
|                     "author": 1,
 | |
|                     "headline": "Unknown many to many",
 | |
|                     "pub_date": "2014-09-15T10:35:00",
 | |
|                     "meta_data": [
 | |
|                         ["author", "meta1"],
 | |
|                         ["doesnotexist", "meta1"],
 | |
|                         ["author", "meta1"]
 | |
|                     ]
 | |
|                 }
 | |
|             }""",
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.author",
 | |
|                 "fields": {"name": "Agnes"}
 | |
|             }""",
 | |
|         ]
 | |
|         test_string = "\n".join([s.replace("\n", "") for s in test_strings])
 | |
|         key = ["doesnotexist", "meta1"]
 | |
|         expected = "(serializers.article:pk=1) field_value was '%r'" % key
 | |
|         with self.assertRaisesMessage(DeserializationError, expected):
 | |
|             for obj in serializers.deserialize("jsonl", test_string):
 | |
|                 obj.save()
 | |
| 
 | |
|     def test_helpful_error_message_for_many2many_natural2(self):
 | |
|         """
 | |
|         Invalid many-to-many keys throws a helpful error message where a
 | |
|         natural many-to-many key has only a single value.
 | |
|         """
 | |
|         test_strings = [
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.article",
 | |
|                 "fields": {
 | |
|                     "author": 1,
 | |
|                     "headline": "Unknown many to many",
 | |
|                     "pub_date": "2014-09-15T10:35:00",
 | |
|                     "meta_data": [1, "doesnotexist"]
 | |
|                 }
 | |
|             }""",
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.categorymetadata",
 | |
|                 "fields": {"kind": "author","name": "meta1","value": "Agnes"}
 | |
|             }""",
 | |
|             """{
 | |
|                 "pk": 1,
 | |
|                 "model": "serializers.author",
 | |
|                 "fields": {"name": "Agnes"}
 | |
|             }""",
 | |
|         ]
 | |
|         test_string = "\n".join([s.replace("\n", "") for s in test_strings])
 | |
|         expected = "(serializers.article:pk=1) field_value was 'doesnotexist'"
 | |
|         with self.assertRaisesMessage(DeserializationError, expected):
 | |
|             for obj in serializers.deserialize("jsonl", test_string, ignore=False):
 | |
|                 obj.save()
 | |
| 
 | |
|     def test_helpful_error_message_for_many2many_not_iterable(self):
 | |
|         """
 | |
|         Not iterable many-to-many field value throws a helpful error message.
 | |
|         """
 | |
|         test_string = (
 | |
|             '{"pk": 1,"model": "serializers.m2mdata","fields": {"data": null}}'
 | |
|         )
 | |
|         expected = "(serializers.m2mdata:pk=1) field_value was 'None'"
 | |
|         with self.assertRaisesMessage(DeserializationError, expected):
 | |
|             next(serializers.deserialize("jsonl", test_string, ignore=False))
 | |
| 
 | |
| 
 | |
| class JsonSerializerTransactionTestCase(
 | |
|     SerializersTransactionTestBase, TransactionTestCase
 | |
| ):
 | |
|     serializer_name = "jsonl"
 | |
|     fwd_ref_str = [
 | |
|         """{
 | |
|             "pk": 1,
 | |
|             "model": "serializers.article",
 | |
|             "fields": {
 | |
|                 "headline": "Forward references pose no problem",
 | |
|                 "pub_date": "2006-06-16T15:00:00",
 | |
|                 "categories": [1],
 | |
|                 "author": 1
 | |
|             }
 | |
|         }""",
 | |
|         """{
 | |
|             "pk": 1,
 | |
|             "model": "serializers.category",
 | |
|             "fields": {"name": "Reference"}
 | |
|         }""",
 | |
|         """{
 | |
|             "pk": 1,
 | |
|             "model": "serializers.author",
 | |
|             "fields": {"name": "Agnes"}
 | |
|         }""",
 | |
|     ]
 | |
|     fwd_ref_str = "\n".join([s.replace("\n", "") for s in fwd_ref_str])
 |