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.

__init__.py 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. """
  2. Interfaces for serializing Django objects.
  3. Usage::
  4. from django.core import serializers
  5. json = serializers.serialize("json", some_queryset)
  6. objects = list(serializers.deserialize("json", json))
  7. To add your own serializers, use the SERIALIZATION_MODULES setting::
  8. SERIALIZATION_MODULES = {
  9. "csv": "path.to.csv.serializer",
  10. "txt": "path.to.txt.serializer",
  11. }
  12. """
  13. import importlib
  14. from django.apps import apps
  15. from django.conf import settings
  16. from django.core.serializers.base import SerializerDoesNotExist
  17. # Built-in serializers
  18. BUILTIN_SERIALIZERS = {
  19. "xml": "django.core.serializers.xml_serializer",
  20. "python": "django.core.serializers.python",
  21. "json": "django.core.serializers.json",
  22. "yaml": "django.core.serializers.pyyaml",
  23. }
  24. _serializers = {}
  25. class BadSerializer:
  26. """
  27. Stub serializer to hold exception raised during registration
  28. This allows the serializer registration to cache serializers and if there
  29. is an error raised in the process of creating a serializer it will be
  30. raised and passed along to the caller when the serializer is used.
  31. """
  32. internal_use_only = False
  33. def __init__(self, exception):
  34. self.exception = exception
  35. def __call__(self, *args, **kwargs):
  36. raise self.exception
  37. def register_serializer(format, serializer_module, serializers=None):
  38. """Register a new serializer.
  39. ``serializer_module`` should be the fully qualified module name
  40. for the serializer.
  41. If ``serializers`` is provided, the registration will be added
  42. to the provided dictionary.
  43. If ``serializers`` is not provided, the registration will be made
  44. directly into the global register of serializers. Adding serializers
  45. directly is not a thread-safe operation.
  46. """
  47. if serializers is None and not _serializers:
  48. _load_serializers()
  49. try:
  50. module = importlib.import_module(serializer_module)
  51. except ImportError as exc:
  52. bad_serializer = BadSerializer(exc)
  53. module = type('BadSerializerModule', (), {
  54. 'Deserializer': bad_serializer,
  55. 'Serializer': bad_serializer,
  56. })
  57. if serializers is None:
  58. _serializers[format] = module
  59. else:
  60. serializers[format] = module
  61. def unregister_serializer(format):
  62. "Unregister a given serializer. This is not a thread-safe operation."
  63. if not _serializers:
  64. _load_serializers()
  65. if format not in _serializers:
  66. raise SerializerDoesNotExist(format)
  67. del _serializers[format]
  68. def get_serializer(format):
  69. if not _serializers:
  70. _load_serializers()
  71. if format not in _serializers:
  72. raise SerializerDoesNotExist(format)
  73. return _serializers[format].Serializer
  74. def get_serializer_formats():
  75. if not _serializers:
  76. _load_serializers()
  77. return list(_serializers)
  78. def get_public_serializer_formats():
  79. if not _serializers:
  80. _load_serializers()
  81. return [k for k, v in _serializers.items() if not v.Serializer.internal_use_only]
  82. def get_deserializer(format):
  83. if not _serializers:
  84. _load_serializers()
  85. if format not in _serializers:
  86. raise SerializerDoesNotExist(format)
  87. return _serializers[format].Deserializer
  88. def serialize(format, queryset, **options):
  89. """
  90. Serialize a queryset (or any iterator that returns database objects) using
  91. a certain serializer.
  92. """
  93. s = get_serializer(format)()
  94. s.serialize(queryset, **options)
  95. return s.getvalue()
  96. def deserialize(format, stream_or_string, **options):
  97. """
  98. Deserialize a stream or a string. Return an iterator that yields ``(obj,
  99. m2m_relation_dict)``, where ``obj`` is an instantiated -- but *unsaved* --
  100. object, and ``m2m_relation_dict`` is a dictionary of ``{m2m_field_name :
  101. list_of_related_objects}``.
  102. """
  103. d = get_deserializer(format)
  104. return d(stream_or_string, **options)
  105. def _load_serializers():
  106. """
  107. Register built-in and settings-defined serializers. This is done lazily so
  108. that user code has a chance to (e.g.) set up custom settings without
  109. needing to be careful of import order.
  110. """
  111. global _serializers
  112. serializers = {}
  113. for format in BUILTIN_SERIALIZERS:
  114. register_serializer(format, BUILTIN_SERIALIZERS[format], serializers)
  115. if hasattr(settings, "SERIALIZATION_MODULES"):
  116. for format in settings.SERIALIZATION_MODULES:
  117. register_serializer(format, settings.SERIALIZATION_MODULES[format], serializers)
  118. _serializers = serializers
  119. def sort_dependencies(app_list):
  120. """Sort a list of (app_config, models) pairs into a single list of models.
  121. The single list of models is sorted so that any model with a natural key
  122. is serialized before a normal model, and any model with a natural key
  123. dependency has it's dependencies serialized first.
  124. """
  125. # Process the list of models, and get the list of dependencies
  126. model_dependencies = []
  127. models = set()
  128. for app_config, model_list in app_list:
  129. if model_list is None:
  130. model_list = app_config.get_models()
  131. for model in model_list:
  132. models.add(model)
  133. # Add any explicitly defined dependencies
  134. if hasattr(model, 'natural_key'):
  135. deps = getattr(model.natural_key, 'dependencies', [])
  136. if deps:
  137. deps = [apps.get_model(dep) for dep in deps]
  138. else:
  139. deps = []
  140. # Now add a dependency for any FK relation with a model that
  141. # defines a natural key
  142. for field in model._meta.fields:
  143. if field.remote_field:
  144. rel_model = field.remote_field.model
  145. if hasattr(rel_model, 'natural_key') and rel_model != model:
  146. deps.append(rel_model)
  147. # Also add a dependency for any simple M2M relation with a model
  148. # that defines a natural key. M2M relations with explicit through
  149. # models don't count as dependencies.
  150. for field in model._meta.many_to_many:
  151. if field.remote_field.through._meta.auto_created:
  152. rel_model = field.remote_field.model
  153. if hasattr(rel_model, 'natural_key') and rel_model != model:
  154. deps.append(rel_model)
  155. model_dependencies.append((model, deps))
  156. model_dependencies.reverse()
  157. # Now sort the models to ensure that dependencies are met. This
  158. # is done by repeatedly iterating over the input list of models.
  159. # If all the dependencies of a given model are in the final list,
  160. # that model is promoted to the end of the final list. This process
  161. # continues until the input list is empty, or we do a full iteration
  162. # over the input models without promoting a model to the final list.
  163. # If we do a full iteration without a promotion, that means there are
  164. # circular dependencies in the list.
  165. model_list = []
  166. while model_dependencies:
  167. skipped = []
  168. changed = False
  169. while model_dependencies:
  170. model, deps = model_dependencies.pop()
  171. # If all of the models in the dependency list are either already
  172. # on the final model list, or not on the original serialization list,
  173. # then we've found another model with all it's dependencies satisfied.
  174. if all(d not in models or d in model_list for d in deps):
  175. model_list.append(model)
  176. changed = True
  177. else:
  178. skipped.append((model, deps))
  179. if not changed:
  180. raise RuntimeError(
  181. "Can't resolve dependencies for %s in serialized app list." %
  182. ', '.join(
  183. '%s.%s' % (model._meta.app_label, model._meta.object_name)
  184. for model, deps in sorted(skipped, key=lambda obj: obj[0].__name__)
  185. )
  186. )
  187. model_dependencies = skipped
  188. return model_list