Im facing a problem in Django with authorization permissions (a bit new to Django). I have a teacher, student and manager models. When a teacher sends a request to my API they should get different permissions than a student (ie, a student will see all of his own test grades, while a teacher can see all of its own class's students, and a manager can see everything).
My questions are as follows:
- How do I make all of my models valid system users? I've tried adding
models.OneToOneField(User, on_delete=models.CASCADE)
But this requires creating a user, and then assigning it to the teacher. What I want is for the actual teacher "instance" to be the used user.
- How do I check which "type" is my user ? if they are a teacher, student or manager? do I need to go over all 3 tables every time a user sends a request, and figure out which they belong to ? doesnt sound right. I thought about creating a global 'user' table with a "type" column, but then I wont be able to add specific columns to my models (ie a student should have an avg grade while a teacher shouldn't) .
Would appreciate any pointers in the right direction.
CodePudding user response:
When you need multiple user types, for example, in your case multiple roles are needed like a student, teacher, manager, etc… then you need a different role for all the persons to categorize.
To have these roles you need to extend AbstractUser
(for simple case) in your models.py
for your User
model also You can specify permissions in your models. Attaching permissions is done on the model's class Meta
using the permissions
field. You will be able to specify as many permissions as you need, but it must be in a tuple like below:
from django.db import models
from django.contrib.auth.models import AbstractUser
from django.db.models.fields.related import ForeignKey
from django.utils.translation import gettext as _
class Role(models.Model):
STUDENT = 1
TEACHER = 2
MANAGER = 3
ROLE_CHOICES = (
(STUDENT, 'student'),
(TEACHER, 'teacher'),
(MANAGER, 'manager'),
)
id = models.PositiveSmallIntegerField(choices=ROLE_CHOICES, primary_key=True)
def __str__(self):
return self.get_id_display()
class User(AbstractUser):
roles = models.ManyToManyField(Role)
username = models.CharField(max_length = 50, blank = True, null = True, unique = True)
email = models.EmailField(_('email address'), unique = True)
native_name = models.CharField(max_length = 5)
phone_no = models.CharField(max_length = 10)
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['username', 'first_name', 'last_name']
def __str__(self):
return "{}".format(self.email)
class Student(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='students')
sample_field_name = models.CharField(max_length = 50, blank = True, null = True)
class Meta:
permissions = (("sample_permission", "can change sth of sth"),)
class Teacher(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='teachers')
sample_field_name = models.CharField(max_length = 50, blank = True, null = True)
class Meta:
permissions = (("sample_permission", "can change sth in sth"),)
class Manager(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True, related_name='managers')
sample_field_name = models.CharField(max_length = 50, blank = True, null = True)
class Meta:
permissions = (("sample_permission", "can change sth in sth"),)
After that you should have your permissions for your views and Adding permissions to restrict a function to only users that have that particular permission can be done by using a Django built-in decorator, permission_required
for function-based views::
from django.contrib.auth.decorators import permission_required
@permission_required('students.sample_permission')
def student_sample_view(request):
"""Raise permission denied exception or redirect user"""
And if you are using a class-based view, you just need to use a mixin, PermissionRequiredMixin
:
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import ListView
class SampleListView(PermissionRequiredMixin, ListView):
permission_required = 'students.sample_permission'
# Or multiple permissions
permission_required = ('students.sample_permission', 'teachers.other_sample_permission')
This was one way you can manage multiple roles in your Django project, you can also find more ways in below blogs and references: