I am trying to make the PUT and DELETE methods require authentication but I want the GET method to be public. I know I can take the GET method out and put it into its own function but I would need to make another url for it. What would be the best way to approach this? thanks
#api_view(['GET', 'PUT', 'DELETE'])
#permission_classes([IsAuthenticated])
def getOrUpdateOrDeleteCar(request, pk):
if request.method == 'GET':
vehicle = Car.objects.get(id=pk)
serializer = CarSerializer(vehicle, many=False)
return Response(serializer.data)
elif request.method == 'PUT':
data = request.data
car = Car.objects.get(id=pk)
car.image=data['image']
car.make=data['make']
car.prototype=data['prototype']
car.year=data['year']
car.serviceInterval=data['serviceInterval']
car.seats=data['seats']
car.color=data['color']
car.vin=data['vin']
car.currentMileage=data['currentMileage']
car.save()
serializer = CarSerializer(car, many=False)
return Response(serializer.data)
elif request.method == 'DELETE':
car = Car.objects.get(id=pk)
car.delete()
return Response('Car Deleted!')
Write a custom permission class:
from rest_framework.permissions import BasePermission
class CarPermission(BasePermission):
def has_permission(self, request, view):
if request.method == 'GET':
return True
return bool(request.user and request.user.is_authenticated)
And use it in your API:
#api_view(['GET', 'PUT', 'DELETE'])
#permission_classes([CarPermission])
def getOrUpdateOrDeleteCar(request, pk):
...
Related
this is my modelViewSet
class UserViewSet(viewsets.ModelViewSet):
def list(self, request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def create(self, request):
serializer = UserSerializer(data=request.data)
if serializer.is_valid(raise_exception=True):
pass
def retrieve(self, request, pk):
user = get_object_or_404(User, pk=pk)
serializer = UserSerializer(user)
return Response(serializer.data, status=status.HTTP_200_OK)
def get_permissions(self):
if self.action == "list":
permission_classes = [
IsAdminUser,
]
elif self.action == "create":
permission_classes = [AllowAny]
else:
permission_classes = [AccountOwnerPermission]
return [permission() for permission in permission_classes]
and this is the custom permission class
class AccountOwnerPermission(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
print(object)
print(request.user)
return obj == request.user
i access this view from another user and it show me user retrieve, and that 2 prints on
AccountOwnerPermission won't run. can someone tell me what is wrong with what i did and why has_object_permission wont run.
i change has_object_permission to has_permission and it works, but i dont have access to obj on the other hand
From the docs:
If you're writing your own views and want to enforce object level permissions, or if you override the get_object method on a generic view, then you'll need to explicitly call the .check_object_permissions(request, obj) method on the view at the point at which you've retrieved the object.
So you'll need to call check_object_permissions in your retrieve to be able to trigger has_object_permission:
def retrieve(self, request, pk):
user = get_object_or_404(User, pk=pk)
self.check_object_permissions(request, user) # Add this line
serializer = UserSerializer(user)
return Response(serializer.data, status=status.HTTP_200_OK)
I have a model of uploads and i want to associate the uploaded images to the user so that later each user can only view his objects so so i m trying to save the created objects to the authenticated user, but it's not working and i keep getting owner =null on my model
#api_view(['GET', 'POST'])
def Upload_list(request):
if request.method == 'GET':
queryset = Uploads.objects.all()
uploads=queryset.filter(owner=request.user)
serializer = UploadSerializer(uploads, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = UploadSerializer(data=request.data)
if serializer.is_valid():
serializer.save(owner=request.user)
respFile=list(File.objects.filter(id=str(File.objects.latest('created_at'))))
return Response(respFile)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Edit : i think the problem is in the Post request itself it is not overriding the default method therefore the changes i apply do not work any idea how to change the post method ?
try this
class IsOwnerFilterBackend(filters.BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
queryset=Uploads.objects.all()
return queryset.filter(owner=request.user)
class UploadView(viewsets.ModelViewSet):
queryset=Uploads.objects.all()
serializer_class=UploadSerializer
filter_backends = (IsOwnerFilterBackend,)
#api_view(['GET', 'POST'])
def methodes(self,request,*args,**kwargs):
if request.method=='POST':
serializer=UploadSerializer(data=request.data)
if serializer.is_valid():
serializer.save(owner=request.user)
return Response("test_token success", status=status.HTTP_200_OK)
return HttpResponse({'message':'error'},status=400)
elif request.method=='GET':
images=Uploads.objects.filter(owner=request.user)
serializers=UploadSerializer(images[0],many=False)
return JsonResponse(serializers.data,safe=False)
I implemented BasePermission class in project but when I am going to retrieve logged user with his token it says You don't have a permission to perform this action
permissions.py
class IsLoggedInOrAdmin(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
return obj.user == request.user or request.user.is_staff
class IsAdminUser(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_staff
def has_object_permission(self, request, view, obj):
return request.user and request.user.is_staff
and my views file looks like this
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
def get_permissions(self):
permission_classes = []
if self.action == 'create':
permission_classes = [AllowAny]
elif self.action == 'retrieve' or self.action == 'update' or self.action == 'partial_update':
permission_classes = [IsLoggedInOrAdmin]
elif self.action == 'destroy' or self.action == 'list':
permission_classes = [IsAdminUser]
return [permission() for permission in permission_classes]
here what i have done so far. I created simple user and took token If I send GET request in Postman I am getting a detail error but it works fine with superuser's token but not owner. Where Am I making mistake? Any help please? Thanks in advance!
I am noting from DRF Official DOC
The instance-level has_object_permission method will only be called if
the view-level has_permission checks have already passed
Also note that in order for the instance-level checks to run, the
view code should explicitly call .check_object_permissions(request,
obj)
I think here you need explicitly called the check_object_permission not relaying on has_permission.
How do I write the following views using class based view?
#api_view(['GET', 'POST'])
def hotel_list(request):
# List all hotel or add new .
if request.method == 'GET':
if request.user.is_authenticated:
# Allow GET request for all authenticated users
hotels = models.Hotel.objects.all()
serializer = serializers.HotelSerializer(hotels, many=True)
return Response(serializer.data)
return Response({"message": "not authorized"}, status=status.HTTP_401_UNAUTHORIZED)
elif request.method == 'POST':
if request.user.is_superuser:
# Allow POST method for super users only
serializer = serializers.HotelSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
return Response({"message": "not authorized"}, status=status.HTTP_401_UNAUTHORIZED)
I want to allow different permissions for different groups of user.
First create custom-permissions
permissions.py
class CreateAdminOnly(permissions.BasePermission):
def has_permission(self, request, view):
if request.method == 'POST':
return request.user.is_superuser
return request.user.is_authenticated
def has_object_permission(self, request, view, obj):
if request.method == 'POST':
return request.user.is_superuser
return request.user.is_authenticated
use it with modelviewset in views.py
from rest_framework import mixins
from rest_framework.permissions import IsAuthenticated
from .permissions import CreateAdminOnly
class CreateListRetrieveViewSet(mixins.CreateModelMixin,
mixins.ListModelMixin,
viewsets.GenericViewSet):
queryset = models.Hotel.objects.all()
serializer_class = HotelSerializer
permission_classes = [CreateAdminOnly]
I have a function based view as:
#api_view(['GET', 'PUT', 'DELETE'])
def hotel_detail(request, pk):
# Lots of code
and I'm using this URL pattern:
url(r'^hotel/(?P<pk>[0-9]+)/$', api.hotel_detail)
but it's not working
view:
#api_view(['GET', 'PUT', 'DELETE'])
def hotel_detail(request, pk):
# Retrieve, update or delete a Hotel instance.
try:
hotel = models.Hotel.objects.get(pk=pk)
except models.Hotel.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = serializers.HotelSerializer(hotel)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = serializers.HotelSerializer(hotel, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
hotel.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Im not receiving any error message.
Hi you can try with Named groups
In your urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^hotel/(?P<pk>[0-9]+)/$', api.hotel_detail name="hotel_details"),
]
If you want know more refer the doc Named groups