4

I'm going to use UpdateAPIView in django. When I completed the view and ran the server, the following error occurred.

Expected view updateViewSet to be called with a URL keyword argument named "pk". Fix your URL conf, or set the `.lookup_field` attribute on the view correctly.

I wonder why I shouldn't designate lookup_field as pk in my code and what I can use instead of pk. Here is my code

serializers.py

from rest_framework import serializers
from .models import arduino

class arduinoSerializers (serializers.ModelSerializer) :
    name = serializers.CharField(source='name.username', read_only=True)
    class Meta :
        model = arduino
        fields = ['name', 'temp', 'humi']

views.py

from .models import arduino
from .serializers import arduinoSerializers
from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from rest_framework.generics import CreateAPIView, UpdateAPIView

class arduinoViewSet (ViewSet) :
    serializer_class = arduinoSerializers
    
    def data (self, request) :
        queryset = arduino.objects.filter(name=self.request.user)
        serializer = arduinoSerializers(queryset, many=True)
        return Response(serializer.data)
        
class createViewSet (CreateAPIView) :
    serializer_class = arduinoSerializers

    def perform_create (self, serializer) :
        serializer.save(name=self.request.user)

    def get_queryset (self) :
        user = self.request.user
        return arduino.objects.filter(name=user)

    def dataReceive (self, request) :
        queryset = self.get_queryset()
        serializer = arduinoSerializers(queryset, many=True)
        if serializer.is_valid() :
            perform_create(serializer)
        return Response(serializer.data)

class updateViewSet (UpdateAPIView) :
    serializer_class = arduinoSerializers
    lookup_field = 'pk'

    def perform_update (self, serializer) :
        serializer.update(name=self.request.user)

    def get_queryset (self) :
        user = self.request.user
        return arduino.objects.filter(name=user)

    def dataReceive (self, request) :
        queryset = self.get_queryset()
        serializer = arduinoSerializers(queryset, many=True)
        if serializer.is_valid() :
            perform_update(serializer)
            return Response(serializer.data)

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('api.urls')),
    path('auth/', include('rest_auth.urls')),
    path('auth/registration/', include('rest_auth.registration.urls')),
]

api\urls.py

urlpatterns = [
    path('data/', arduinoViewSet.as_view({'get' : 'data'})),
    path('create/', createViewSet.as_view()),
    path('update/', updateViewSet.as_view()),
]

thanks in advance

leedjango
  • 411
  • 2
  • 9
  • 18

3 Answers3

1

The update view doesn’t know which id(pk) to update. Try adding the pk in the update url

urlpatterns = [
    path('update/<int:pk>/', updateViewSet.as_view()),
]
0

It was said that you need to call the URL with a primary key, so it should be

urlpatterns = [
    path('data/<int:pk>/', arduinoViewSet.as_view({'get' : 'data'})),
]

But honestly, I think pk can be any value as long as it is unique, but your error occurred in the first place because, since you didn't specify a field, Django will look for one named 'pk'.

crimsonpython24
  • 2,223
  • 2
  • 11
  • 27
0

While the accepted answer fixes the problem you were having, since the title of your question has, more generally, to do with specifying a lookup field for an UpdateView, I wanted to go ahead and post this more general answer for anyone who might come across this question if they are trying to do a lookup based on something other than pk.

Looking at CCBV docs for UpdateView.get_object(), you can see that if <int:pk> is not in the url, then UpdateView looks for slug_field (with a default name of slug which you can see under Attributes on the above page). Therefore, instead of <int:pk> in the url, you could put <slug:slug> in the url. In this case the second slug in the <slug:slug> part of the declaration is the default url keyword used by UpdateView if looking up by a slug. As an aside, if you name your slug keyword argument in your url declaration something like: <slug:different_slug_name>, then you would need to specify slug_url_kwarg = different_slug_name on the UpdateView. Finally, if the SlugField on your model is named something other than slug (again, the default as you can see in the Attributes on CCBV), then on the UpdateView you would need to specify slug_field = model_slug_field_name.

Dan Swain
  • 2,910
  • 1
  • 16
  • 36