I am trying to build an endpoint using Django Rest Framework for the device detail endpoint on http://127.0.0.1:8000/api/v1/controller/device/<pk>/
Models:-
class AbstractDevice(OrgMixin, BaseModel):
name = models.CharField()
mac_address = models.CharField()
key = KeyField()
model = models.CharField()
os = models.CharField()
system = models.CharField()
notes = models.TextField(blank=True, help_text=_('internal notes'))
last_ip = models.GenericIPAddressField()
management_ip = models.GenericIPAddressField()
hardware_id = models.CharField()
class AbstractConfig(BaseConfig):
device = models.OneToOneField(Device, on_delete=models.CASCADE)
templates = SortedManyToManyField()
vpn = models.ManyToManyField()
STATUS = Choices('modified', 'applied', 'error')
status = StatusField()
context = JSONField()
For the above models, I have created serializers as:-
class DeviceConfigSerializer(serializers.ModelSerializer):
config = serializers.JSONField()
context = serializers.JSONField()
class Meta:
model = Config
fields = ['backend', 'status', 'templates', 'context', 'config']
class DeviceDetailSerializer(serializers.ModelSerializer):
config = DeviceConfigSerializer()
class Meta(BaseMeta):
model = Device
fields = [
'id',
'name',
'organization',
'mac_address',
'key',
'last_ip',
'management_ip',
'model',
'os',
'system',
'notes',
'config',
]
def update(self, instance, validated_data):
instance = self.instance or self.Meta.model(**validated_data)
instance.name = validated_data['name']
instance.organization = validated_data['organization']
instance.mac_address = validated_data['mac_address']
instance.key = validated_data['key']
instance.last_ip = validated_data['last_ip']
instance.management_ip = validated_data['management_ip']
instance.model = validated_data['model']
instance.os = validated_data['os']
instance.system = validated_data['system']
instance.notes = validated_data['notes']
instance.config.backend = validated_data['config']['backend']
instance.config.status = validated_data['config']['status']
config_templates = validated_data['config']['templates']
instance.config.templates.clear()
for template in config_templates:
instance.config.templates.add(template.pk)
instance.config.context = json.loads(
json.dumps(validated_data['config']['context']),
object_pairs_hook=collections.OrderedDict,
)
instance.config.config = json.loads(
json.dumps(validated_data['config']['config']),
object_pairs_hook=collections.OrderedDict,
)
instance.save()
instance.config.save()
return instance
Since I want to incorporate a nested serializer and to make it writable so, it is required to manually add the .update
method.
and the views:
class DeviceDetailView(RetrieveUpdateDestroyAPIView):
serializer_class = DeviceDetailSerializer
queryset = Device.objects.all()
The above codes work fine for PUT
request but when I try to send a patch request, it expects all the fields, i., until I feed all the fields, I am not able to send the request, but then this is not a patch request when I have to feed all the fields for changing a single field.
ps: I have abstracted the representation of the models for this questions, and tried to give an idea of the model.
when you are writing instance.organization = validated_data['organization']
you are not checking if the key
is actually present or not.
so, for that you can do it like validated_data.get('organization')
. This represents if you have organization present in validated data then you your variable will be assigned.
you are fetching all the validated data into variables and then you are trying to update it but you can do it easily with this code.
instance = super().update(instance, validated_data)
return instance
This will only update yourfields which is only present in validated_data. It will not update the other fields.
you can just get the data from the validated_data and update it.
In this case what you have done is correct and i think it will work perfect.
If you still face any issue, please reply me in this thread i will try to give you answer.