Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could not resolve URL for hyperlinked relationship using view name ( django-rest-framework )

Problem :

I am getting an error like this .

ImproperlyConfigured at /api/users/

Could not resolve URL for hyperlinked relationship using view name "user-detail". You may have failed to include the related model in your API, or incorrectly configured the lookup_field attribute on this field.

I read this post but it didn't work.

serializers.py

class UserSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='user-detail',
                                               lookup_field='profile')

    class Meta:
        model = User
        fields = ('id', 'username', 'first_name', 'last_name', 'url')


class UserProfileSerializer(serializers.ModelSerializer):
    user = serializers.ReadOnlyField(source='user.username')

    class Meta:
        model = UserProfile
        fields = "__all__"
        # user = serializers.ReadOnlyField(source='owner.username')

    def create(self, validated_data):
        pass

    def update(self, instance, validated_data):
        pass

urls.py

user_profile_list = UserProfileViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
user_profile_detail = UserProfileViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
user_list = UserViewSet.as_view({
    'get': 'list'
})
user_detail = UserViewSet.as_view({
    'get': 'retrieve'
})
user_profiles_detail = UserViewSet.as_view({
    'get': 'profile'
})

router = DefaultRouter()
router.register(r'userprofiles', views.UserProfileViewSet)
router.register(r'users', views.UserViewSet)

urlpatterns = [
    url(r'^', include(router.urls))
]

views.py

class UserProfileViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.
    """
    queryset = UserProfile.objects.all()
    serializer_class = UserProfileSerializer
    permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly,)
    pagination_class = LimitTenPagination

    @detail_route(renderer_classes=[renderers.JSONRenderer])
    def perform_create(self, serializer):
        serializer.save(user=self.request.user)


class UserViewSet(viewsets.ReadOnlyModelViewSet):
    """
    This viewset automatically provides `list` and `detail` actions
    """
    queryset = User.objects.all()
    serializer_class = UserSerializer

Snippet from my models.py

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile')

What I tried :

I tried changing user-detail to api:user-detail ( yes api namespace do exist in the main urls.py file )

like image 737
hemo Avatar asked Jan 20 '18 19:01

hemo


2 Answers

  1. Looking at the docs, I believe you have to use HyperLinkedRelatedField. Also, see this related SO post.

  2. You are confusing arguments in your serializer field definition. What I believe should be:

    class UserSerializer(serializers.ModelSerializer):
        url = serializers.HyperlinkedRelatedField(view_name='api:userprofile-detail',
                                                  source='profile')
    

Edit :

Added namespace api

like image 169
dukebody Avatar answered Nov 14 '22 12:11

dukebody


Remove lookup_filed attribute from your HyperlinkedIdentityField since you do not need it.

Hence your serializer class should instead look like below:

class UserSerializer(serializers.ModelSerializer):
    url = serializers.HyperlinkedIdentityField(view_name='user-detail', source='profile',)

    class Meta:
        model = User
        fields = ('id', 'username', 'first_name', 'last_name', 'url')

The attribute lookup_filed is only needed when referring to a model class with relationship-field/attribute used as a primary key instead of the default autoincrement. For example, it would have been relevant to use it if your model class looked like below:

class UserProfile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE, related_name='profile', primary_key=True)
like image 24
Mitch Avatar answered Nov 14 '22 11:11

Mitch