Another could not resolve URL for hyperlinked relationship error

Question:

Yes I know a similar question has been asked many times, but I am sorry none of answers have really helped me or I missed something important.

I want to make registration when posted data from client are in format:

{
    "email": "[email protected]",
    "first_name": "s",
    "last_name": "d",
    "password": "f"
}

and server return:

{
    "results": {
        "email": "[email protected]",
        "first_name": "s",
        "last_name": "d"
    }
}

When I post data I got:

ImproperlyConfigured at /api/register Could not resolve URL for
hyperlinked relationship using view name “customuser-detail”. You may
have failed to include the related model in your API, or incorrectly
configured the lookup_field attribute on this field.

So I have serializers.py like:

class RegisterUserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = CustomUser
        fields = ('url', 'email', 'first_name', 'last_name', 'password')
        write_only_fields = ('password',)

    def create(self, validated_data):
        user = CustomUser.objects.create(**validated_data)
        try:
            user.set_password(user.password)
            user.save()
            return user
        except KeyError:
            return user


class RegisterUserRetrieveSerializer(serializers.Serializer):
    results = RegisterUserSerializer(source='*')

Then api viewsets in views.py:

class RegisterUserViewSet(mixins.CreateModelMixin,
                          viewsets.GenericViewSet):
    permission_classes = (AllowAny,)
    parser_classes = (parsers.JSONParser,)
    serializer_class = serializers.RegisterUserSerializer
    model = CustomUser

    def create(self, request):
        serializer = serializers.RegisterUserSerializer(data=request.data)
        if serializer.is_valid(raise_exception=True):
            user = serializer.save()
            serializer = serializers.RegisterUserRetrieveSerializer(user, context={'request': request})
            results = serializer.data
            return Response(results, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

And urls.py:

router = routers.DefaultRouter()
router_without_trailing_slashes = routers.DefaultRouter(trailing_slash=False)
router.register(r'register', RegisterUserViewSet, base_name='customuser')
router_without_trailing_slashes.register(r'register', RegisterUserViewSet, base_name='customuser')

urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^templates/', include('core.main.urls'), name='templates'),

    url(r'^api/', include(router_without_trailing_slashes.urls)),
    url(r'^api/', include(router.urls)),
]

The new user is saved correctly to db so I suppose the error is somehow connected with RegisterUserRetrieveSerializer.
Any ideas?

Asked By: Matúลก Bartko

||

Answers:

It looks like the problem is that you are including the url field in the serializer, but DRF is unable to generate that url, because there is no detail view for the serializer.

There are two options:

  1. Remove the url field from the serializer
  2. Add mixins.RetrieveModelMixin to the ViewSet, so that the serializer can generate a detail url for the instance
Answered By: Joey Wilhelm

Error is happening due to the ‘url’ field included in fields list in serializer.

After adding ‘url’ field you need to define the view_name and lookup_field for that url in extra_kwargs.

class RegisterUserSerializer(serializers.HyperlinkedModelSerializer):  
    class Meta:
        model = CustomUser
        fields = ('url', 'email', 'first_name', 'last_name', 'password')
        write_only_fields = ('password',)
        extra_kwargs = {
               "url":{
                  "view_name": "customuser-detail",
                  "lookup_field": "pk"
               }
Answered By: Abhishek Upadhyay