Reputation: 174
I have a view set up to return a list of books to a user, which is retrieved from a simple book model based on the currently logged-in user. However, I also have ReadingSession model which has a foreign key relationship to both the Book, and the User.
When I'm retrieving the books for the user, I'd like to, at the very least, return a list of primary keys that I can use to get the length of in my client.
The following code will get the full set of readingsessions in my BookSerializer:
from rest_framework import serializers
from books.models import Book
class BookSerializer(serializers.ModelSerializer):
readingsession_set = serializers.PrimaryKeyRelatedField(
many=True, read_only=True)
class Meta:
model = Book
fields = ["id", "title", "author", "publisher",
"publish_date", "description", "category",
"language", "small_thumbnail", "thumbnail",
"readingsession_set"]
However, the problem with this is that it will return all of the readingsessions, regardless of whether or not the session belongs to that user.
I'd like to be able to filter that so that it will only return the readingsessions for the current user. Something along the lines of:
readingsession_set = serializers.PrimaryKeyRelatedField(queryset=ReadingSession.objects.filter(user=user), read_only=True)
But I've tried various ways of trying to pass the user (self.request.user
) from the APIView but none seem to work. I've tried passing a context, and tried passing extra **kwargs
in __init__
but none seem to work.
Is there a way of achieving this? Or am I taking the wrong approach?
Thanks
Upvotes: 6
Views: 1686
Reputation: 31
Found right approach in another similar question: How i can to filter queryset by current user in django rest framework Works perfectly for me:
class PrimaryKeyRelatedFieldByUser(serializers.PrimaryKeyRelatedField):
def get_queryset(self):
query_set = super().get_queryset()
request = self.context.get('request')
return query_set.filter(user=request.user)
Just don't forget to set base queryset like:
foo = PrimaryKeyRelatedFieldByUser(queryset=Foo.objects.all())
Upvotes: 2
Reputation:
The user is not present on the serializer's declaration but during its instantiation.
Therefore, you can filter queryset
s by user within the __init__
method.
from rest_framework import serializers
from bar.models import Foo
class RandomSerializer(serializers.Serializer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
user_foos = Foo.objects.filter(user=self._user)
self.fields['foo_ids'] = serializers.PrimaryKeyRelatedField(
required=False,
many=True,
read_only=False,
queryset=user_foos,
default=user_foos)
@property
def _user(self):
request = self.context.get('request', None)
if request:
return request.user
Don't forget to pass the request
object to the serializer in the context (if necessary, e.g., using a simple APIView
.
from rest_framework import views
class RandomView(views.APIView):
serializer_class = RandomSerializer
def post(self, request):
serializer = self.serializer_class(
data=request.data, context={'request': request})
# ...
serializer = RandomSerializer(data=request.data, context={'request': request}
Upvotes: 6
Reputation: 811
You can access the user of the request on the serializer by means of the context.
As mentioned in the documentation, you can always do:
serializer = AccountSerializer(account, context={'request': request})
Thus, you will be able to use self.context['request'].user
inside your serializer.
Hope that's what you're after.
Upvotes: 1