Django REST Filtering Tutorial - Filter with Current User (Part II)
Django REST Filtering Tutorial (5 Part Series)
Entrée
We’ve seen in part I how to setup our repo, sending HTTP requests and some fundamental concepts about Django REST filtering.
In this second part we will limit our views/querysets/objects with user
, more
precisely with current authenticated user.
The authors list endpoint — /authors/
, displays all items regardless of
whether they belong to current user or not.
$ http :8000/authors
[
{
"first_name": "Name1",
"full_name": "Name1 Surname1",
"id": 1,
"last_name": "Surname1",
"user": 1
},
{
"first_name": "Name2",
"full_name": "Name2 Surname2",
"id": 2,
"last_name": "Surname2",
"user": null
},
{
"first_name": "Name3",
"full_name": "Name3 Surname3",
"id": 3,
"last_name": "Surname3",
"user": 3
}
]
How can we change that behavior in order to return items only owned by current authenticated user?
Note
You can find the code we’re working on this tutorial series in this repository: django-rest-filtering-tutorial
You don’t need to download and setup the repository in order to follow this series, however I’d like to encorauge to do so, since while you play you learn better as always.
Current User
This is one common filter usage which is filtering the queryset to ensure only relevant results to the current authenticated user who makes the request are returned.
For this purpose we will override default get_queryset as we’ve seen in default filtering in detail.
Let’s filter authors list endpoint with the current user:
|
|
Note
In our repo we
use ModelViewSet
for authors endpoint. You can update it like above.
You can look at related AuthorSerializer
and Author
model in the repo,
however for easy access I put them there as well. In order to examine them just
expand the below section.
AuthorSerializer and Author model
AuthorSerializer
from src/authors/serializers.py
:
|
|
Author
model from src/authors/model.py
:
|
|
Now we can make a successful request by including the username and password of
one of the users we created in populate_db.py
:
$ http -a "User1:1234" ":8000/authors/"
[
{
"first_name": "Name1",
"full_name": "Name1 Surname1",
"id": 1,
"last_name": "Surname1",
"user": 1
},
]
As you can recognize now it returns only one object instead of three.
And if you we make a request as anonymous or unauthenticated user, we will get:
$ http ":8000/authors/"
[]
User Authentication and Permission
It’s usually better idea to separate authentication
and permission
layer/logic. For this goal you can use authentication_classes
and
permission_classes
on per-view or per-viewset basis;
|
|
Another method is setting the default authentication globally, using the
DEFAULT_AUTHENTICATION_CLASSES
setting:
|
|
Info
In the repo these are disabled, you can set them globally if you comment out the related lines at the end of the setting.py file.
And now our view will look cleaner like this:
|
|
For more info about authentication
and permissions
you can look at:
Custom FilterBackend
There is another method which is that we can also provide our own generic filtering backend.
To do so override BaseFilterBackend
class, and override the .filter_queryset
method. The method should return a new, filtered queryset.
As well as allowing clients to perform searches and filtering, generic filter backends can be useful to restrict which objects should be visible to any given request or user.
Let’s write IsOwnerFilterBackend
for our current user logic:
|
|
Add this filter to our AuthorListView
:
|
|
Now if we send request we only receive related authors to the user.
One side note to this method; as we’ve already seen above, we can achieve the
same behavior by overriding get_queryset()
on the view, but using a filter
backend allows us to more easily add this restriction to multiple views, or to
apply it across the entire API.
We can also make this filter backend as our global default backend:
|
|
Conclusion
In this tutorial we learned how to filter the queryset to ensure only relevant results to the current authenticated user who makes the request are returned.
See you in the next part of this tutorial series.
All done!