Aliquis
Aliquis

Reputation: 2309

Django: Permission per instance

At the moment, I plan to write a website where users can write blog posts. I haven't started with the implementation yet because I am new to Django and want to get an overview in how I should solve problems and structure the overall project.

My problem: The users aren't allowed to use Django's admin page (/admin). The users should only interact with the website that I write.

The users at my website will be able to create blog posts. Now, I have to ensure that only the creator of the blog post should be able to edit/delete his own post. All the other users should only be able to read this post.

So, I need permissions per user/instance. I know that there are some full-blown permission-systems like django-guardian, but I would like to prefer to solve it on my own. Also to better understand the Django framework.

I`ve already read the Django docs, but I am overwhelmed.

I guess this is such a common problem that I there is also a common solution to this problem. Can someone help me where I should look at, where to start?

My idea so far (please comment):

In create a page like blog/5/edit that is only accessible for the user that created the blog post number 5. This should be easily within the view function, right? On this page there is a Form to edit the blog post.

Something like this for the view (pseudo-code!)

if request.user != blogpost.user:
    redirect/error page
else:
    show Form/process Form

Is this secure? I haven't found such a solution so far while searching the internet. However, spontaneously and as a Django beginner, I think this could already by enough.

Upvotes: 2

Views: 1235

Answers (1)

Yannic Hamann
Yannic Hamann

Reputation: 5205

Yes, you can do that. For that purpose I recommend to create an custom decorator like so:

decorators.py:

from django.core.exceptions import PermissionDenied
from .models import YourBlogPostModel

def user_is_blog_post_user(function):
    def wrap(request, *args, **kwargs):
        post = YourBlogPostModel.objects.get(pk=kwargs['blog_post_id'])
        if post.user == request.user:
            return function(request, *args, **kwargs)
        else:
            raise PermissionDenied
    wrap.__doc__ = function.__doc__
    wrap.__name__ = function.__name__
    return wrap

You can then use it in conjunction with other decorators.

views.py:

@login_required
@user_is_blog_post_user
def function_based_view(request, blog_post_id):
    # ...

Take a look here for a more detailed explanation.


If you are using CVB you can either create an own Mixin or decorate the class.

class UserIsBlogPostAdmin(object):
     """Verify that the current user is the user of the blog post."""
     def dispatch(self, request, *args, **kwargs):
         blog_post = get_object_or_404(YourBlogPostModel, pk=args[0])
         if blog_post.user != request.user
             raise Http404
         return super().dispatch(request, *args, **kwargs)

Upvotes: 1

Related Questions