My design is as following about Django ModelSerializer. There are model A and model B. Model B has a foreign key field of Model A. For some reasons, I can not use the primary key directly to serialize Model B. As my thought, what I need is to serialize two other fields(unique together in Model A).
And I see the SlugRelatedField must be used for one slug field. I searched there is a NaturalKeyField can support NaturalKeyField. But it looks like it is superseeded by django-rest-framework. But I checked the django-rest-framework, there is no such field at all. Can anyone help?? What should I do?
The code is as following. Model A
class AssetModel(models.Model):
org = models.ForeignKey(Org, related_name='models')
name = models.CharField(max_length=128)
model_type = models.SmallIntegerField(default = 3,choices = MODEL_TYPE )
directory = models.CharField(max_length = 128)
...
class Meta:
unique_together = ('org', 'name',)
Model B
class Dataitem(models.Model):
mod = models.ForeignKey(AssetModel, related_name='dataitems')
name = models.CharField(max_length=128)
data_type = models.SmallIntegerField(default =0,choices = DATAITEM_DATATYPE)
...
Serializer of model A
class AssetModelSerializer(serializers.ModelSerializer):
org = serializers.SlugRelatedField(queryset=Org.objects.all(), slug_field='name')
class Meta:
model = AssetModel
fields = ('org', 'name', 'model_type',..
Serializer of model B
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
fields = ('mod', 'name','data_type'...)
The primary key of Model A is just a id Django auto added. When serialize the model B, I need to get the org and name of model A. Both read and write are needed.
The HyperlinkedModelSerializer class is similar to the ModelSerializer class except that it uses hyperlinks to represent relationships, rather than primary keys. By default the serializer will include a url field instead of a primary key field.
Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
In function-based views, we can pass extra context to serializer with “context” parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with “self. context”. From example, to get “exclude_email_list” we just used code 'exclude_email_list = self.
To serialize a queryset or list of objects instead of a single object instance, you should pass the many=True flag when instantiating the serializer. You can then pass a queryset or list of objects to be serialized.
You can do something like this, define a serializer for Dataitem
that can reuse a serializer of the AssetModel
model
class AssetModelSerializer(serializers.ModelSerializer):
class Meta:
model = AssetModel
# Fields org and name of AssetModel will be inlcuded by default
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
mod = AssetModelSerializer()
# This is the Dataitem.mod field
# which is a FK to AssetModel,
# Now it'll be serilized using the AssetModelSerializer
# and include the org and name fields of AssetModelSerializer
I prefer this approach because of the control I get. If you serialize using the above you get a structure like this:
data_item = {'name': ..., 'mod': {'org': ..., 'name': ...}}
^
|___ AssetModel fields
depth = n
You can also use depth = 1
in Dataitem
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
depth = 1 # Will include fields from related models
# e.g. the mod FK to AssetModel
Because the behavior of nested creates and updates can be ambiguous, and may require complex dependencies between related models, REST framework 3 requires you to always write these methods explicitly.
We have to implement create/update
to make this writable as per DRF's documentation
class DataitemSerializer(serializers.ModelSerializer):
class Meta:
model = Dataitem
# Nested serializer
mod = AssetModelSerializer()
# Custom create()
def create(self, validated_data):
# First we create 'mod' data for the AssetModel
mod_data = validated_data.pop('mod')
asset_model = AssetModel.objects.create(**mod_data)
# Now we create the Dataitem and set the Dataitem.mod FK
dataitem = Dataitem.objects.create(mod=asset_model, **validated_data)
# Return a Dataitem instance
return dataitem
There seems to be a library that does this drf-writable-nested
it handles the creation and serialisation of these types
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With