Last active
May 26, 2021 02:33
-
-
Save emilsas/0364e1e756759be6017f19cc8fdb41e8 to your computer and use it in GitHub Desktop.
DjangoModelPermissions Example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib.auth.base_user import AbstractBaseUser | |
from django.contrib.auth.models import PermissionsMixin | |
from django.db import models | |
from django.utils.translation import ugettext_lazy as _ | |
class Account(AbstractBaseUser, PermissionsMixin): | |
email = models.EmailField(unique=True, null=True) | |
is_staff = models.BooleanField( | |
_('staff status'), | |
default=False, | |
help_text=_('Designates whether the user can log into this site.'), | |
) | |
is_active = models.BooleanField( | |
_('active'), | |
default=True, | |
help_text=_( | |
'Designates whether this user should be treated as active. ' | |
'Unselect this instead of deleting accounts.' | |
), | |
) | |
USERNAME_FIELD = 'email' | |
def is_provider(self): | |
is_prov = False | |
try: | |
is_prov = self.provider is not None | |
except ProviderUserProfile.DoesNotExist: | |
pass | |
return is_prov | |
def is_customer(self): | |
is_cust = False | |
try: | |
is_cust = self.customer is not None | |
except CustomerUserProfile.DoesNotExist: | |
pass | |
return is_cust | |
class CustomerUserProfile(models.Model): | |
account = models.OneToOneField(Account, blank=True, null=True, related_name='customer_profile') | |
product = models.ForeignKey(Product, null=True, related_name='customers', on_delete=models.CASCADE) | |
name = models.CharField(max_length=100, blank=True) | |
last_name = models.CharField(max_length=100, blank=True) | |
phone_number = models.CharField(max_length=100) | |
class ProviderUserProfile(models.Model): | |
account = models.OneToOneField(Account, null=True, related_name='provider_profile', on_delete=models.CASCADE) | |
products = models.ManyToManyField(Product, blank=True, related_name='providers') | |
class Product(models.Model): | |
name = models.CharField(max_length=100) | |
price = models.IntegerField() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from rest_framework import permissions | |
class OnlyProvidersPermission(permissions.BasePermission): | |
message = 'Only Providers are allowed to access.' | |
def has_permission(self, request, view): | |
return request.user.is_authenticated and ( | |
request.user.is_provider() or request.user.is_superuser) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from rest_framework import viewsets | |
from rest_framework.permissions import DjangoModelPermissions | |
from api.permissions import OnlyProvidersPermission | |
from api.serializers import ProductSerializer | |
from myapp.models import Product | |
class ProductViewSet(viewsets.ModelViewSet): | |
""" | |
Permissions mut be set in this precise order because DjangoModelPermissions calls | |
get_queryset and a user that is not an operator will not have one. | |
""" | |
serializer_class = ProductSerializer | |
queryset = Product.objects.none() # Required for DjangoModelPermissions | |
permission_classes = [DjangoModelPermissions, OnlyProvidersPermission] | |
# If I invert the order of permission classes it's works perfectly | |
# permission_classes = [OnlyProvidersPermission, DjangoModelPermissions] | |
def get_queryset(self): | |
user = self.request.user | |
if user.is_superuser: | |
return Product.objects.all() | |
# In this line DjangoModelPermissions fails when is tested with a user without provider_profile, | |
# because ._queryset() always ask for .get_queryset() to determine model name. | |
return user.provider_profile.products.all() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment