Reputation: 1378
I want to restrict my ViewSet so that it allows for different inputs based on permissions:
My models:
class Link(models.Model):
name = models.CharField("name", max_length = 128)
page = models.PositiveIntegerField("page", default = 1, choices = [(1, 1), (2, 2), (3, 3)])
layouts = models.ManyToManyField(Layout)
class Layout(models.Model):
name = models.CharField("name", max_length = 32)
Serializer:
class LinkSerializer(serializers.ModelSerializer):
test = serializers.SerializerMethodField("get_layouts")
def get_layouts(self): ## this is not displayed?
return "test"
class Meta:
model = Link
fields = ["name", "page", "test"]
I have a helper class that provides a all_pages
permission for example. in the restframework API I now have a dropdown from page 1-3, but if the user does not have the right to use all pages, I want to only show page 1
for selection (or make it a text field witout input field).
Same problem applies for the ManyToMany
field: How can I restrict the layouts dropdown options to the ones I selected in the admin-planel for that user?
Right now I manually check everything in the PUT
method of the ViewSet
and return a "user is not allowed ... -> BAD REQUEST".
EDIT: BC I was asked, right now I do something like this:
class TestViewSet(viewsets.ViewSet):
serializer_class = LinkSerializer
http_method_names = ['get', 'put', 'head']
authentication_classes = [SessionAuthentication,]
permission_classes = [IsAuthenticated,]
def list(self, request):
...
def put(self, request):
## page logic
if "app.all_pages" in request.user.get_user_permissions():
try:
if not 1 < int(request.data["page"]) <= 3:
return Response(data = "page not 2 or 3",
status = status.HTTP_406_NOT_ACCEPTABLE)
except Exception as E:
return Response(data = f"""Error in page selection: {E}""",
status = status.HTTP_400_BAD_REQUEST)
page = int(request.data["page"])
else:
page = 2
## layout logic:
store = Store.objects.get(user = request.user)
allowed_layouts = [l.id for l in store.layouts.all()]
if not int(request.data["layout"]) in allowed_layouts:
return Response(data = f"""layout not allowed for store {store}""",
status = status.HTTP_406_NOT_ACCEPTABLE)
layout = Layout.objects.get(pk = request.data["layout"])
## do something with page 2 and layout ... in DB/another API
Upvotes: 0
Views: 458
Reputation: 2130
The question is a bit unclear, so I'm going to explain how permissions work and you'll use them yourself.
P.1
Permissions in DRF as just wrappers for 2 methods, here's how it works.
class PermissionX:
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj)
return True
This is a permission, has_permission
says (request.user
has permission to access the
current view
?) and has_object_permission
says (request.user
has persmission to act on obj
).
The obj
is the object being acted on inside the view. If your view works with users, the object will be an instance of User
.
This is used with permission_classes
like this
permission_classes = [IsAuthenticated, PermissionX]
P.2
You usually use user.has_perm(perm)
instead of 'name' in user.permissions
. This is because the permissions can exist in user.groups
and not only user.permissions
.
P.3
Any exception raised should be of type PermissionDenied
which exists in DRF.
P.4
Extract your permission in a permission.py folder in your current app.
P.5
Your permissions won't be integrated in django admin's interface. This is because it's not using DRF and it's not using your endpoints. It's using things that django made available for it. This is normal, the logic we're talking about will be enforced by your API itself and when you create a custom dashboard, you need to enforce it on the frontend as a type of UX as well.
Upvotes: 1