Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django groups and permissions

I would like to create 2 groups (Professors, Students). And I would like to restrict students from creating and deleting Courses.

views.py:

def is_professor(function=None):

    def _is_professor(u):
      if user.groups.filter(name='Professor').exists():
          return True
      else:
          raise HttpResponseForbidden
  return _is_professor(function)

class ListCourseView(ListView):

    model = Course
    template_name = 'course_list.html'
    fields = '__all__'

@is_professor
class CreateCourseView(CreateView):

    def get_queryset(self, request):
        if not request.user.is_superuser:
             return False

    model = Course
    template_name = 'course/edit_course.html'
    fields = '__all__'

    def get_success_url(self):
        return reverse('courses-list')

    def get_context_data(self, **kwargs):

         context = super(CreateCourseView, self).get_context_data(**kwargs)
        context['action'] = reverse('courses-new')

        return context

class UpdateCourseView(UpdateView):

    model = Course
    template_name = 'course/edit_course.html'
    fields = '__all__'

    def get_success_url(self):
        return reverse('courses-list')

def get_context_data(self, **kwargs):

    context = super(UpdateCourseView, self).get_context_data(**kwargs)
    context['action'] = reverse('courses-edit',
                                kwargs={'pk': self.get_object().id})

    return context

class DeleteCourseView(DeleteView):

    model = Course
    template_name = 'course/delete_course.html'

    def get_success_url(self):
        return reverse('courses-list')

models.py

 class Course(models.Model):
    name = models.CharField(
    max_length=255,
    )

    def __str__(self):
        return ' '.join([
        self.name
        ])



class UserProfile(models.Model):
    user = models.OneToOneField(User)

    picture = models.ImageField(upload_to='profile_images', blank=True)

    class Meta:
        permissions = ( ('add_course', 'Add course'), )

    def __unicode__(self):
        return self.user.username

This is what I tried. First of all I get an error

NameError: global name 'user' is not defined.

And secondly I still don't think this would work :)

like image 679
ssapp Avatar asked Mar 23 '16 12:03

ssapp


1 Answers

Something that i did for one of my django project is :

I defined a function that will check permissions and if user is authenticated :

from django.contrib.auth.decorators import user_passes_test

def group_required(*group_names):
    """Requires user membership in at least one of the groups passed in."""
    def in_groups(u):
        if u.is_authenticated():
            if bool(u.groups.filter(name__in=group_names)) | u.is_superuser:
                return True
        return False

    return user_passes_test(in_groups, login_url='403')

And then i passed this function as decorator for my functions :

from whatever import group_required

@group_required('Professor')
def action_only_for_professor(request):
    # do things

@group_required('Student')
def action_only_for_student(request):
    # do other things

With this method you can declare multi-group for your functions like this :

@group_required('Professor', 'Student', 'Administrator', ...)

This trick work only with method that you create. if you want to do the same for class, i suggest you to check django-braces (e.q. http://django-braces.readthedocs.org/en/latest/index.html). Django Braces works like this :

from braces.views import GroupRequiredMixin

class CreateCourseView(CreateView, GroupRequiredMixin):
    group_required = u"Professor"

    def get_queryset(self, request):
        if not request.user.is_superuser:
             return False

    model = Course
    template_name = 'course/edit_course.html'
    fields = '__all__'

    def get_success_url(self):
        return reverse('courses-list')

    def get_context_data(self, **kwargs):

         context = super(CreateCourseView, self).get_context_data(**kwargs)
        context['action'] = reverse('courses-new')

        return context

If you want to use more than one group permission in your class, just do it like this :

group_required = [u"Professor", u"Student", u"Administrator", etc...]

Django-braces is very powerful to check permissions for your class, in the sense that you can check if a user is authenticated (with LoginRequiredMixin), is anonymous (AnonymousrequiredMixin), is superuser (SuperuserRequiredMixin), got one (PermissionRequiredMixin) or multiple permissions (MultiplePermissionRequiredMixin), and more and more stuff ! You just have to inherit your class with the appropriate mixin you want to use ;)

Hope it will help, and waiting for your return about all that :)

like image 104
Bloodbee Avatar answered Sep 20 '22 03:09

Bloodbee