Django Rest Framework PUT request on unique model field
13,789
As per the comments implementing the put
method closer to the reference implementation in the docs should fix the issue.
def put(self, request, pk, format=None):
device = self.get_object(pk)
serializer = DeviceSerializer(device, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Saving instances has a bit more information on creating, updating and saving instances by using the serializer
class methods.
Related videos on Youtube
Author by
DmitrySemenov
Updated on September 14, 2022Comments
-
DmitrySemenov over 1 year
I have the following model
class Owner(models.Model): user = models.OneToOneField(User, default=1, editable=True) phone = models.CharField(max_length=40, null=True, blank=True) address = models.CharField(max_length=255, null=True, blank=True) city = models.CharField(max_length=255, null=True, blank=True) state = USStateField(null=True, blank=True) zip = models.CharField(max_length=20, null=True, blank=True) def __str__(self): return "%s %s" % (self.user.first_name, self.user.last_name) class Device(CreationModificationMixin): _STATUSES = ( ('A', 'Active'), ('I', 'Inactive'), ('F', 'Failure'), ) _TYPES = ( ('S', 'Spa'), ('P', 'Pool'), ) udid = models.CharField(max_length=255, verbose_name="Unique ID / MAC Address", null=False, blank=False, unique=True) type = models.CharField(max_length=1, choices=_TYPES, null=False, blank=False) title = models.CharField(max_length=255, null=False, blank=False) status = models.CharField(max_length=1, default='A', choices=_STATUSES) pinged = models.DateTimeField(null=True) owner = models.ForeignKey(Owner, verbose_name="Owner", null=True, blank=True) def __str__(self): return self.udid
I have the following serializer
class DeviceSerializer(serializers.ModelSerializer): class Meta: model = Device fields = ('id', 'udid', 'title', 'type', 'status', 'pinged', 'created')
I have the following API View defined:
class DeviceAPIView(APIView): permission_classes = (IsAuthenticated,) # explicit code_404 = "Device doesn't exists" def get(self, request, device_id): try: d = Device.objects.get(id=device_id, owner=request.user.owner) except Device.DoesNotExist: return Response({'error': self.code_404}, 404) serializer = DeviceSerializer(d) return Response(serializer.data) def put(self, request, device_id): serializer = DeviceSerializer(data=request.DATA) if not serializer.is_valid(): return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) else: data = serializer.data data['id'] = id d = Device(**data).save() serializer = DeviceSerializer(d) return Response(serializer.data, status=status.HTTP_200_OK)
PUT request on existing device
{ "udid": "38-2C-4A-47-C2-ED", "title": "Backyard pool", "type": "S" }
gives me back
{ "udid": ["This field must be unique."] }
However I'm updating the record and passing the same UDID it has. So I'm not getting a duplicate in DB but DRF thinks the other way.
What I need to achieve is
- If UDID of the same record is not changed - then no error should be raised
- if UDID of the record changes and now it's the same as some of record's UDID then error should be returned.
-
sthzg almost 9 yearsLast thing I can think of right now is maybe trying to match the
put()
method to the way it is handled in the docs (if it is DRF 3.x). I.e. with retrieving the instance first and then initializing the serializer with the current instance as first argument.