I want to be able to create or update an object using the same request. The operation should be idempotent.
Sending a PUT request to DRF work as expected if the object exists but if the object doesn't exists I get a 404 instead of creating it.
models.py:
class Btilog(models.Model):
md5hash = models.CharField(primary_key=True, max_length=32)
vteip = models.ForeignKey('vte.VTE')
timestamp = models.DateTimeField(blank=False)
source = models.TextField()
code = models.CharField(max_length=10, blank=False)
msg = models.TextField(blank=False)
api.py:
class BtilogSerializer(serializers.ModelSerializer):
class Meta:
model = models.Btilog
class BtilogVSet(viewsets.ModelViewSet):
queryset = models.Btilog.objects.all()
serializer_class = BtilogSerializer
permission_classes = (permissions.AllowAny,)
urls.py:
...
router = routers.DefaultRouter()
router.register(r'btilog', api.BtilogVSet)
urlpatterns = patterns('',
url(r'^api/', include(router.urls)),
...
)
Failing request
http --form PUT http://192.168.10.121:8888/logger/api/btilog/60c6b9e99c43c0bf4d8bc22d671169b1/ vteip='172.25.128.85' 'code'='Test' 'md5hash'='60c6b9e99c43c0bf4d8bc22d671169b1' 'timestamp'='2015-05-31T13:34:01' msg='Test' source='Test'
HTTP/1.0 404 NOT FOUND
Allow: GET, PUT, PATCH, DELETE, HEAD, OPTIONS
Content-Type: application/json
Date: Mon, 09 Feb 2015 15:16:47 GMT
Server: WSGIServer/0.1 Python/2.7.6
Vary: Accept, Cookie
{
"detail": "Not found"
}
As described here: http://restcookbook.com/HTTP%20Methods/put-vs-post/ the correct behaviour of put should be to create the object if it doesn't exists.
The same error occurs using The Browsable API Tool from DRF to make the request. Is the behaviour of DRF also alike? What I'm doing wrong?
The Http404 exceptionIf you raise Http404 at any point in a view function, Django will catch it and return the standard error page for your application, along with an HTTP error code 404. In order to show customized HTML when Django returns a 404, you can create an HTML template named 404.
Custom exception handlingThe exception handler function should either return a Response object, or return None if the exception cannot be handled. If the handler returns None then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.
The rendering process takes the intermediate representation of template and context, and turns it into the final byte stream that can be served to the client. REST framework includes a number of built in Renderer classes, that allow you to return responses with various media types.
HyperlinkedModelSerializer is a layer of abstraction over the default serializer that allows to quickly create a serializer for a model in Django. Django REST Framework is a wrapper over default Django Framework, basically used to create APIs of various kinds.
Well, maybe you should try to overwrite update method inside your modelviewset, which handle the PUT http method:
class BtilogVSet(viewsets.ModelViewSet):
queryset = models.Btilog.objects.all()
serializer_class = BtilogSerializer
permission_classes = (permissions.AllowAny,)
def update(self, request, *args, **kwargs):
try:
instance = Btilog.objects.get(pk=kwargs['pk'])
serializer = serializers.BtilogSerializer(instance=instance,data=request.data)
if serializer.is_valid():
btilog=serializer.save()
return Response(serializer.data,status=status.HTTP_200_OK)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
except Btilog.DoesNotExist:
serializer = serializers.BtilogSerializer(data=request.data)
if serializer.is_valid():
btilog=serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
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