Skip to content

Commit f1578ba

Browse files
author
paul
committed
Use metaclass to maintain the mapping between serializers and models
1 parent ba69cd1 commit f1578ba

File tree

2 files changed

+20
-12
lines changed

2 files changed

+20
-12
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
We need something a little meaningful so the example consists of some simple models in a class heirarchy and an associated heirarchy of model serializers<sup id="n1">[1](#f1).
44

5-
The ??first commit shows how serializers need to be accessed for the model classes in order to serialize/deserialize model data.
5+
The first commit shows how serializers need to be accessed for the model classes in order to serialize/deserialize model data.
66

77
Maintaining the serializer_class_map quickly becomes cumbersome.
88

@@ -17,7 +17,7 @@ but this is repeating the association because its already present in the Meta (s
1717

1818
We could add a serializer_class field to the models but this is coupling the serializers to the models in an undesirable way. We want to keep the serialization concern to our serializers.
1919

20-
So how about a metaclass?
20+
##So how about a metaclass?
2121
If we specify a metaclass for our serializers we can update the serializer_class_map whenever we create a new serializer class.
2222

2323
## Footnotes

example.py

+18-10
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,25 @@ class Car(Model):
2525

2626

2727
# Serializers are responsible for serializing some model class:
28-
class Serializer(object):
28+
class MappedSerializerClass(type):
29+
serializer_class_map = {}
30+
2931
class Meta:
3032
model_class = None
3133

34+
def __init__(cls, *args, **kwargs) -> None:
35+
super().__init__(*args, **kwargs)
36+
model_class = cls.Meta.model_class
37+
if model_class:
38+
MappedSerializerClass.serializer_class_map[model_class] = cls
39+
40+
41+
def get_serializer_class(model):
42+
return MappedSerializerClass.serializer_class_map[type(model)]
43+
44+
45+
class Serializer(object, metaclass=MappedSerializerClass):
46+
3247
def __init__(self, model=None) -> None:
3348
super().__init__()
3449
self.model = model
@@ -50,6 +65,8 @@ def serialize(self):
5065

5166

5267
class VehicleSerializer(ModelSerializer):
68+
class Meta:
69+
model_class = None
5370

5471
def serialize(self):
5572
return {**super().serialize(), 'travels_on': self.model.travels_on}
@@ -80,11 +97,6 @@ def serialize(self):
8097
'ship1': {'class': Ship},
8198
'car1': {'class': Car}}
8299

83-
serializer_class_map = {Model: ModelSerializer,
84-
Building: BuildingSerializer,
85-
Car: CarSerializer,
86-
Ship: ShipSerializer}
87-
88100

89101
def make_model(name, spec):
90102
model_class = spec.pop('class')
@@ -94,10 +106,6 @@ def make_model(name, spec):
94106
models = {name: make_model(name, spec) for name, spec in serialized_models_in.items()}
95107

96108

97-
def get_serializer_class(model):
98-
return serializer_class_map[type(model)]
99-
100-
101109
serialized_models_out = {name: get_serializer_class(model)(model).serialize() for name, model in models.items()}
102110

103111

0 commit comments

Comments
 (0)