Development of an internal social media platform with personalised dashboards for students
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.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  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. field_names_cache = {} # Model: <list of field_names>
  70. for d in object_list:
  71. # Look up the model and starting build a dict of data for it.
  72. try:
  73. Model = _get_model(d["model"])
  74. except base.DeserializationError:
  75. if ignorenonexistent:
  76. continue
  77. else:
  78. raise
  79. data = {}
  80. if 'pk' in d:
  81. try:
  82. data[Model._meta.pk.attname] = Model._meta.pk.to_python(d.get('pk'))
  83. except Exception as e:
  84. raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), None)
  85. m2m_data = {}
  86. if Model not in field_names_cache:
  87. field_names_cache[Model] = {f.name for f in Model._meta.get_fields()}
  88. field_names = field_names_cache[Model]
  89. # Handle each field
  90. for (field_name, field_value) in d["fields"].items():
  91. if ignorenonexistent and field_name not in field_names:
  92. # skip fields no longer on model
  93. continue
  94. field = Model._meta.get_field(field_name)
  95. # Handle M2M relations
  96. if field.remote_field and isinstance(field.remote_field, models.ManyToManyRel):
  97. try:
  98. values = base.deserialize_m2m_values(field, field_value, using)
  99. except base.M2MDeserializationError as e:
  100. raise base.DeserializationError.WithData(e.original_exc, d['model'], d.get('pk'), e.pk)
  101. m2m_data[field.name] = values
  102. # Handle FK fields
  103. elif field.remote_field and isinstance(field.remote_field, models.ManyToOneRel):
  104. try:
  105. value = base.deserialize_fk_value(field, field_value, using)
  106. except Exception as e:
  107. raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
  108. data[field.attname] = value
  109. # Handle all other fields
  110. else:
  111. try:
  112. data[field.name] = field.to_python(field_value)
  113. except Exception as e:
  114. raise base.DeserializationError.WithData(e, d['model'], d.get('pk'), field_value)
  115. obj = base.build_instance(Model, data, using)
  116. yield base.DeserializedObject(obj, m2m_data)
  117. def _get_model(model_identifier):
  118. """Look up a model from an "app_label.model_name" string."""
  119. try:
  120. return apps.get_model(model_identifier)
  121. except (LookupError, TypeError):
  122. raise base.DeserializationError("Invalid model identifier: '%s'" % model_identifier)