-
Notifications
You must be signed in to change notification settings - Fork 87
/
Copy pathserializer.py
100 lines (83 loc) · 3.76 KB
/
serializer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# Copyright (C) DATADVANCE, 2010-2023
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""Serializer to support Django models as subscription events."""
import datetime
import logging
import django.core.serializers
import django.db
import msgpack
# Module logger.
LOG = logging.getLogger(__name__)
class Serializer:
"""Serialize/deserialize Python collection with Django models.
Serialize/deserialize the data with the MessagePack like Redis
Channels layer backend does.
If `data` contains Django models, then it is serialized by the
Django serialization utilities. For details see:
Django serialization:
https://docs.djangoproject.com/en/dev/topics/serialization/
MessagePack:
https://github.com/msgpack/msgpack-python
"""
@staticmethod
def serialize(data):
"""Serialize the `data`."""
def encode_extra_types(obj):
"""MessagePack hook to serialize extra types.
The recipe took from the MessagePack for Python docs:
https://github.com/msgpack/msgpack-python#packingunpacking-of-custom-data-type
Supported types:
- Django models (through `django.core.serializers`).
- Python `datetime` types:
- `datetime.datetime`
- `datetime.date`
- `datetime.time`
"""
if isinstance(obj, django.db.models.Model):
return {
"__djangomodel__": True,
"as_str": django.core.serializers.serialize("json", [obj]),
}
if isinstance(obj, datetime.datetime):
return {"__datetime__": True, "as_str": obj.isoformat()}
if isinstance(obj, datetime.date):
return {"__date__": True, "as_str": obj.isoformat()}
if isinstance(obj, datetime.time):
return {"__time__": True, "as_str": obj.isoformat()}
return obj
return msgpack.packb(data, default=encode_extra_types, use_bin_type=True)
@staticmethod
def deserialize(data):
"""Deserialize the `data`."""
def decode_extra_types(obj):
"""MessagePack hook to deserialize extra types."""
if "__djangomodel__" in obj:
obj = next(
django.core.serializers.deserialize("json", obj["as_str"])
).object
elif "__datetime__" in obj:
obj = datetime.datetime.fromisoformat(obj["as_str"])
elif "__date__" in obj:
obj = datetime.date.fromisoformat(obj["as_str"])
elif "__time__" in obj:
obj = datetime.time.fromisoformat(obj["as_str"])
return obj
return msgpack.unpackb(data, object_hook=decode_extra_types, raw=False)