Reputation: 310
I would like to be able to check if the user accessing a page is a specific user.
For instance, when a user accesses the "Edit Post" page on my blog app, I want to ensure that the user is the author of the post.
Currently, I check that the user accessing '/Blog/Edit//' has the blog.change_post permission.
However, if a second user (who also has that permission) were to enter the URL to change someone else's post, they would pass that permission check and be able to edit someone else's post.
What I want is a @user_passes_test function that check's the user object accessing the view against the author attribute of the post.
#/Blog/urls.py
urlpatterns = [
...
path('Edit/<int:pk>', views.BlogEdit, name='BlogEdit'),
...
]
#/Blog/views.py
@permission_required('blog.change_post', login_url='/Portal/login')
def BlogEdit(request, pk):
post = get_object_or_404(Post, pk=pk)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
post = form.save(commit=False)
post.save()
return redirect('/Blog', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'Blog/Edit.html', {'form': form})
Upvotes: 4
Views: 1519
Reputation: 476547
You can add an extra filter to your get_object_or_404
:
@permission_required('blog.change_post', login_url='/Portal/login')
def BlogEdit(request, pk):
post = get_object_or_404(Post, pk=pk, author=request.user)
if request.method == "POST":
form = PostForm(request.POST, instance=post)
if form.is_valid():
form.save()
return redirect('/Blog', pk=post.pk)
else:
form = PostForm(instance=post)
return render(request, 'Blog/Edit.html', {'form': form})
Here author
is the hypothetical ForeignKey
from Post
to the user model. It is possible that the name is different, but the idea is still the same.
This thus means that in case the pk
is the pk
of a Blog
for which request.user
is not the author
, then we will have a 404 response.
The advantage of filtering here, is that we use a single query for the filtering. We will not (lazily) load the author
to check if it is the same as the logged in user.
Note:
post = form.save(commit=False)
andpost.save()
are equivalent topost = form.save()
(so withcommit=True
).
Upvotes: 6
Reputation: 310
I figured it out from This Post in the end. What urbanspaceman suggests works for class based views, but for function based views you can do:
@permission_required('blog.change_post', login_url='/Portal/login')
def BlogEdit(request, pk):
post = get_object_or_404(Post, pk=pk)
if post.author != request.user:
raise Http404("You are not allowed to edit this Post")
# ... Rest of view here ... #
Upvotes: 1
Reputation: 3385
In a class based view change the get_queryset
method to filter by current user.
class MyView(LoginRequiredMixin, UpdateView):
...
def get_queryset(self):
"""
Only the current logged in user can edit ...
"""
return super().get_queryset().filter(created_by=self.request.user)
Upvotes: 1