I have an endpoint /api/v1/invoice/#id/
I want that only author of this invoice should be able to view invoice Or staff should be able to view this invoice And superuser should be able to view, update, delete invoice
I tried creating permissions.py file in my app:
permissions.py
from rest_framework.permissions import BasePermission
class AuthorGetStaffGetAdminAll(BasePermission):
edit_methods = ("PUT", "PATCH", "DELETE")
def has_permission(self, request, view):
if request.user.is_authenticated:
return True
return False
def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
return True
if obj.author == request.user and request.method not in self.edit_methods:
return True
if request.user.is_staff and request.method not in self.edit_methods:
return True
return False
serializer.py
class InvoiceSerializer(serializers.ModelSerializer):
order = serializers.SlugRelatedField(slug_field='id', queryset=order.Order.objects.all())
id = serializers.CharField(max_length=100, read_only=True)
class Meta:
model = invoice.Invoice
fields = ['id', 'invoice_series', 'order', 'payment_id']
view.py
class InvoiceDisplayView(APIView):
permission_classes = [AuthorGetStaffGetAdminAll]
def get(self, request, invoice_id):
invoice = Invoice.objects.get(id__iexact=invoice_id)
serializer = InvoiceSerializer(invoice)
return Response(serializer.data)
urls.py
from django.urls import path
from . import views
urlpatterns = [
path('v1/invoices/<str:invoice_id>/', views.InvoiceDisplayView.as_view(), name="invoice_view"),
]
CodePudding user response:
Since you are using APIView
and not generic view, you have to call check_object_permissions
explicitly, this answer explains everything.
Your get method should look like this:
def get(self, request, invoice_id):
invoice = Invoice.objects.get(id__iexact=invoice_id)
self.check_object_permissions(request, invoice) # This calls permissions
serializer = InvoiceSerializer(invoice)
return Response(serializer.data)
CodePudding user response:
APIView do not have object level permission check. You can update your APIView with RetrieveUpdateDestroyAPIView :
class InvoiceDisplayView(RetrieveUpdateDestroyAPIView):
lookup_field = 'invoice_id' # primary key
permissions_classes = [IsAuthenticatedAndOwner]
queryset = Invoice.objects.all()
serializer_class = InvoiceSerializer
if your primary key is invoice_id you can do this and no get method is required, this alone serves put update delete and get all alone, usually primary_key is just id or pk , in that case lookup_field will be 'id' or 'pk' and you need to update your urls as well :
urlpatterns = [
path('v1/invoices/<int:id>/', views.InvoiceDisplayView.as_view(), name="invoice_view"),
]