You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

python.py 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. """
  2. A Python "serializer". Doesn't do much serializing per se -- just converts to
  3. and from basic Python data types (lists, dicts, strings, etc.). Useful as a basis for
  4. other serializers.
  5. """
  6. from collections import OrderedDict
  7. from django.apps import apps
  8. from django.core.serializers import base
  9. from django.db import DEFAULT_DB_ALIAS, models
  10. from django.utils.encoding import is_protected_type
  11. class Serializer(base.Serializer):
  12. """
  13. Serialize a QuerySet to basic Python objects.
  14. """
  15. internal_use_only = True
  16. def start_serialization(self):
  17. self._current = None
  18. self.objects = []
  19. def end_serialization(self):
  20. pass
  21. def start_object(self, obj):
  22. self._current = OrderedDict()
  23. def end_object(self, obj):
  24. self.objects.append(self.get_dump_object(obj))
  25. self._current = None
  26. def get_dump_object(self, obj):
  27. data = OrderedDict([('model', str(obj._meta))])
  28. if not self.use_natural_primary_keys or not hasattr(obj, 'natural_key'):
  29. data["pk"] = self._value_from_field(obj, obj._meta.pk)
  30. data['fields'] = self._current
  31. return data
  32. def _value_from_field(self, obj, field):
  33. value = field.value_from_object(obj)
  34. # Protected types (i.e., primitives like None, numbers, dates,
  35. # and Decimals) are passed through as is. All other values are
  36. # converted to string first.
  37. return value if is_protected_type(value) else field.value_to_string(obj)
  38. def handle_field(self, obj, field):
  39. self._current[field.name] = self._value_from_field(obj, field)
  40. def handle_fk_field(self, obj, field):
  41. if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
  42. related = getattr(obj, field.name)
  43. if related:
  44. value = related.natural_key()
  45. else:
  46. value = None
  47. else:
  48. value = self._value_from_field(obj, field)
  49. self._current[field.name] = value
  50. def handle_m2m_field(self, obj, field):
  51. if field.remote_field.through._meta.auto_created:
  52. if self.use_natural_foreign_keys and hasattr(field.remote_field.model, 'natural_key'):
  53. def m2m_value(value):
  54. return value.natural_key()
  55. else:
  56. def m2m_value(value):
  57. return self._value_from_field(value, value._meta.pk)
  58. self._current[field.name] = [
  59. m2m_value(related) for related in getattr(obj, field.name).iterator()
  60. ]
  61. def getvalue(self):
  62. return self.objects
  63. def Deserializer(object_list, *, using=DEFAULT_DB_ALIAS, ignorenonexistent=False, **options):
  64. """
  65. Deserialize simple Python objects back into Django ORM instances.
  66. It's expected that you pass the Python objects themselves (instead of a
  67. stream or a string) to the constructor
  68. """
  69. handle_forward_references = options.pop('handle_forward_references', False)
  70. field_names_cache = {} # Model: <list of field_names>
  71. for d in object_list:
  72. # Look up the model and starting build a dict of data for it.
  73. try:
  74. Model = _get_model(d["model"])
  75. except base.DeserializationError:
  76. if ignorenonexistent:
  77. continue
  78. else:
  79. raise
  80. data = {}
  81. if 'pk' in d:
  82. try:
  83. data[Model._meta.pk.attname] = Model._meta.pk.to_python(d.get('pk'))
  84. except Exception as e:
  85. raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), None)
  86. m2m_data = {}
  87. deferred_fields = {}
  88. if Model not in field_names_cache:
  89. field_names_cache[Model] = {f.name for f in Model._meta.get_fields()}
  90. field_names = field_names_cache[Model]
  91. # Handle each field
  92. for (field_name, field_value) in d["fields"].items():
  93. if ignorenonexistent and field_name not in field_names:
  94. # skip fields no longer on model
  95. continue
  96. field = Model._meta.get_field(field_name)
  97. # Handle M2M relations
  98. if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
  99. try:
  100. values = base.deserialize_m2m_values(field, field_value, using, handle_forward_references)
  101. except base.M2MDeserializationError as e:
  102. raise base.DeserializationError.WithData(e.original_exc, d['model'], d.get('pk'), e.pk)
  103. if values == base.DEFER_FIELD:
  104. deferred_fields[field] = field_value
  105. else:
  106. m2m_data[field.name] = values
  107. # Handle FK fields
  108. elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
  109. try:
  110. value = base.deserialize_fk_value(field, field_value, using, handle_forward_references)
  111. except Exception as e:
  112. raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
  113. if value == base.DEFER_FIELD:
  114. deferred_fields[field] = field_value
  115. else:
  116. data[field.attname] = value
  117. # Handle all other fields
  118. else:
  119. try:
  120. data[field.name] = field.to_python(field_value)
  121. except Exception as e:
  122. raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
  123. obj = base.build_instance(Model, data, using)
  124. yield base.DeserializedObject(obj, m2m_data, deferred_fields)
  125. def _get_model(model_identifier):
  126. """Look up a model from an "app_label.model_name" string."""
  127. try:
  128. return apps.get_model(model_identifier)
  129. except (LookupError, TypeError):
  130. raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)