Reputation: 2321
I have models which consist in a User
model and a Present
one. A User
can have multiple Present
but a Present
has a unique User
:
My models.py
is:
from django.db import models
from django.contrib.auth.models import User
class Present(models.Model):
name = models.CharField(max_length=15)
price = models.FloatField()
link = models.CharField(max_length=15)
isAlreadyBought = models.BooleanField()
user = models.ForeignKey(User, related_name='presents', on_delete=models.CASCADE)
My serializers.py
are:
from django.contrib.auth.models import User, Group
from rest_framework import serializers
from blog.models import Present, Location
from django.contrib.auth.models import User
class UserSerializer(serializers.ModelSerializer):
presents = serializers.PrimaryKeyRelatedField(many=True, queryset=Present.objects.all(), required=False)
class Meta:
model = User
fields = ('username', 'password', 'email', 'presents')
def create(self, validated_data):
user = super().create(validated_data)
if 'password' in validated_data:
user.set_password(validated_data['password'])
user.save()
return user
class PresentSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(), read_only=False, many=False)
class Meta:
model = Present
fields = ('name', 'link', 'price', 'isAlreadyBought', 'user')
def create(self, validated_data):
return Present.objects.create(**validated_data)
Currently, if I want to get the all the presents associate with a given User, I use the primary key (in views.py
):
class PresentsOfUser(viewsets.ModelViewSet):
queryset = Present.objects.all().filter(user=33)
serializer_class = PresentSerializer
However, I would rather use the username
field of the User
instead of the primary key.
I have tried using a SlugRelatedField
but I am not sure this is the right way to achieve my goal:
class PresentSerializer(serializers.ModelSerializer):
user = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', read_only=False, many=False)
class Meta:
model = Present
fields = ('name', 'link', 'price', 'isAlreadyBought', 'user')
def create(self, validated_data):
return Present.objects.create(**validated_data)
And with this modification, I now use the following View
to get the user 'Marcel'
whose id
is 33
:
class PresentsOfUser(viewsets.ModelViewSet):
queryset = Present.objects.all().filter(user='Marcel')
serializer_class = PresentSerializer
But in this case, I get:
ValueError: invalid literal for int() with base 10: 'Marcel'
But if I replace user='Marcel'
by user=33
(as previously), I get:
[{"name":"Nintendo","link":"fake_link","price":50.8,"isAlreadyBought":true,"user":"Marcel"},{"name":"Gamecube","link":"fake_link","price":50.8,"isAlreadyBought":true,"user":"Marcel"}]
where the user field is now the username
and not the user's id
.
However, I do not understand why filtering with user='Marcel'
fails...
Upvotes: 1
Views: 2194
Reputation: 2321
I ended up by overriding the get_queryset
method while keeping the PrimaryKeyRelatedField
in my serializer (with user__username='Marcel'
as mishbah suggested):
class PresentsOfUser(viewsets.ModelViewSet):
serializer_class = PresentSerializer
def get_queryset(self):
"""
Optionally restricts the returned purchases to a given user,
by filtering against a `username` query parameter in the URL.
"""
queryset = Present.objects.all()
username = self.kwargs['user']
if username is not None:
queryset = queryset.filter(user__username=username)
if len(queryset) == 0:
raise Http404
return queryset
It also works when replacing PrimaryKeyRelatedField
by SlugRelatedField
:
user = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='username', read_only=False, many=False)
and adding to_field='username'
in the ForeignKey
of my Present
model:
user = models.ForeignKey(User, related_name='presents', to_field='username', on_delete=models.CASCADE)
Upvotes: 2
Reputation: 5597
I think your issue is w/ this line:
queryset = Present.objects.all().filter(user='Marcel')
With the assumption Marcel
is username with pk
=> 33
You can't filter using a string, instead something like this:
queryset = Present.objects.all().filter(user__username='Marcel')
Hope that helps.
Upvotes: 1