serialization.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. import json
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.core import serializers
  4. from extras.utils import is_taggable
  5. __all__ = (
  6. 'deserialize_object',
  7. 'serialize_object',
  8. )
  9. def serialize_object(obj, resolve_tags=True, extra=None, exclude=None):
  10. """
  11. Return a generic JSON representation of an object using Django's built-in serializer. (This is used for things like
  12. change logging, not the REST API.) Optionally include a dictionary to supplement the object data. A list of keys
  13. can be provided to exclude them from the returned dictionary.
  14. Args:
  15. obj: The object to serialize
  16. resolve_tags: If true, any assigned tags will be represented by their names
  17. extra: Any additional data to include in the serialized output. Keys provided in this mapping will
  18. override object attributes.
  19. exclude: An iterable of attributes to exclude from the serialized output
  20. """
  21. json_str = serializers.serialize('json', [obj])
  22. data = json.loads(json_str)[0]['fields']
  23. exclude = exclude or []
  24. # Include custom_field_data as "custom_fields"
  25. if 'custom_field_data' in data:
  26. data['custom_fields'] = data.pop('custom_field_data')
  27. # Resolve any assigned tags to their names. Check for tags cached on the instance;
  28. # fall back to using the manager.
  29. if resolve_tags and is_taggable(obj):
  30. tags = getattr(obj, '_tags', None) or obj.tags.all()
  31. data['tags'] = sorted([tag.name for tag in tags])
  32. # Skip any excluded attributes
  33. for key in list(data.keys()):
  34. if key in exclude:
  35. data.pop(key)
  36. # Append any extra data
  37. if extra is not None:
  38. data.update(extra)
  39. return data
  40. def deserialize_object(model, fields, pk=None):
  41. """
  42. Instantiate an object from the given model and field data. Functions as
  43. the complement to serialize_object().
  44. """
  45. content_type = ContentType.objects.get_for_model(model)
  46. if 'custom_fields' in fields:
  47. fields['custom_field_data'] = fields.pop('custom_fields')
  48. data = {
  49. 'model': '.'.join(content_type.natural_key()),
  50. 'pk': pk,
  51. 'fields': fields,
  52. }
  53. instance = list(serializers.deserialize('python', [data]))[0]
  54. return instance