Referencing User ID in Django URL dispatcher

Issue

I’m trying to implement a search feature where user’s can search an email on a React frontend and it’ll return that email’s top 5 love languages. Currently the url path requires the primary key of a love language model, but I want it to use the user id. I have this Django URL set as:

path('love-languages/', LovesView.as_view(), name='love-languages'),
path('love-languages/<int:pk>', LoveView.as_view(), name='love-languages')

Relevant love language model:

class Love(models.Model):
    # Obtaining the user from the user model
    user = models.ForeignKey(
        get_user_model(),
        on_delete = models.CASCADE
    )
    
    # Defining the dropdown choices 
    class LoveLanguages(models.TextChoices):
        ACTS_OF_SERVICE = 'Acts of Service'
        RECEIVING_GIFTS = 'Receiving Gifts'
        QUALITY_TIME = 'Quality Time'
        WORDS_OF_AFFIRMATION = 'Words of Affirmation'
        PHYSICAL_TOUCH = 'Physical Touch'
    
    one = models.CharField(max_length=20, choices=LoveLanguages.choices)
    two = models.CharField(max_length=20, choices=LoveLanguages.choices)
    three = models.CharField(max_length=20, choices=LoveLanguages.choices)
    four = models.CharField(max_length=20, choices=LoveLanguages.choices)
    five = models.CharField(max_length=20, choices=LoveLanguages.choices)    

and love language views:

class LovesView(APIView):
    def get(self, request):
        loves = Love.objects.filter(user=request.user.id)
        data = LoveSerializer(loves, many=True).data
        return Response(data)
    
    def post(self, request):
        request.data['user'] = request.user.id
        love = LoveSerializer(data=request.data)
        if love.is_valid():
            love.save()
            return Response(love.data, status=status.HTTP_201_CREATED)
        else:
            return Response(love.errors, status=status.HTTP_400_BAD_REQUEST)

class LoveView(APIView):
    def get(self, request, pk):
        love = get_object_or_404(Love, pk=pk)
        # if request.user != love.user:
        #     raise PermissionDenied('Unauthorized, you are not signed in as this user')
        # else:
        data = LoveSerializer(love).data
        return Response(data)
    def delete(self, request, pk):
        love = get_object_or_404(Love, pk=pk)
        if request.user != love.user:
            raise PermissionDenied('Unauthorized, you are not signed in as this user')
        else:
            love.delete()
            return Response(status=status.HTTP_204_NO_CONTENT)
    def put(self, request, pk):
        love = get_object_or_404(Love, pk=pk)
        if request.user != love.owner:
            raise PermissionDenied('Unauthorized, you are not signed in as this user')
        else:
            updated_love = LoveSerializer(love, data=request.data)
        if updated_love.is_valid():
            updated_love.save()
            return Response(updated_love.data)
        else:
            return Response(love.errors, status=status.HTTP_400_BAD_REQUEST)

So, if this were the data returned:

{
    "id": 4,
    "user": 2,
    "one": "Acts of Service",
    "two": "Receiving Gifts",
    "three": "Quality Time",
    "four": "Words of Affirmation",
    "five": "Physical Touch"
}

The URL would have to be …/love-languages/4. I want the URL to be …/love-languages/2 because I am not sure how I can access the pk of 4 when only an email is entered. I’ve thought about referencing the love language model in the user model, but I think there should be a way to replace <int:pk> in the URL with something like <int:user>? I tried that and it did not work, I got an error saying TypeError: get() got an unexpected keyword argument 'user' I was reading the django docs for URL dispatcher but couldn’t find anything useful at the moment.

I also tried changing the get request in the views to

 love = get_object_or_404(Love, pk=request.user.id)

but that didn’t work. It only returns the same data regardless of what id is entered in the url.

Solution

If I understand the question correctly here is what you need to do.
Django allows you to query a model and its relationship with __.

So to make a query about Love model with respect to user you would do something like this.

try:
    love = Love.objects.get(user__email=variable_email)
except Love.DoesNotExist:
    raise Http404

there are 2 ways to detect email in url.
you can simply use <str:variable_email> and then clean the email in you view before using it to query your database.
or you can use regex to detect in url pattern.( like question asked here)

Answered By – Mojtaba

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published