I use django rest framework,
example code
class TestApiView(APIView):
def get(self, request):
return Response({'text': 'allow any'})
def post(self, request):
return Response({'text': 'IsAuthenticated'})
how to make method GET accessible to all, and method POST only authorized
thank you in advance
You can use IsAuthenticatedOrReadOnly permission class:
from rest_framework.permissions import IsAuthenticatedOrReadOnly
class TestApiView(APIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
def get(self, request):
return Response({'text': 'allow any'})
def post(self, request):
return Response({'text': 'IsAuthenticated'})
Related
I am trying to perform an action from superuser accept/reject the task, but after login from superuser it show the error. even if i logged in from non superuser if show the same error
403 Forbidden
i am trying first time perform action from superuser i don't know how can i fix this issue
View.py
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class Approval(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
def test_func(self):
if self.request.user == User.is_superuser:
return True
else:
return False
template_name = 'approve.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name)
def post(self, request):
Urls.py
urlpatterns = [
path('approve',Approval.as_view(), name='approve')
]
You check if the user is a superuser with:
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
class Approval(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
template_name = 'approve.html'
def test_func(self):
return self.request.user.is_superuser
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {'all_saloon': all_saloon})
The all_saloon is however strange: it means that if it is a list or QuerySet it will each time work with the same data, and thus if later a new Saloon is constructed, it will not take that into account.
You can alter the handle_no_permission function to determine what to do in case the test fails:
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.shortcuts import redirect
class Approval(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
template_name = 'approve.html'
def test_func(self):
return self.request.user.is_superuser
def handle_no_permission(self):
return redirect('name-of-some-view')
def get(self, request, *args, **kwargs):
return render(request, self.template_name, {'all_saloon': all_saloon})
Likely you want to work with a ListView [Django-doc] instead.
I wrote a custom permission class for a drf project to protect my view:
views.py
class Employee(APIView):
permission_classes = [BelongsToClient]
serializer_class = EmployeeSerializer
def get(self, request, pk, format=None):
employee = EmployeeModel.objects.get(pk=pk)
serializer = EmployeeSerializer(employee, many=False)
return Response(serializer.data)
def delete(self, request, pk, format=None):
employee = EmployeeModel.objects.get(pk=pk)
employee.Employees_deleted = True
employee.save()
return Response(status=status.HTTP_200_OK)
My permission class:
permission.py
from rest_framework import permissions
class BelongsToClient(permissions.BasePermission):
message= "You are only authorized to view objects of your client"
"""
Object-level permission to only see objects of the authenticated users client
"""
def has_object_permission(self, request, view, obj):
if obj.Mandant == request.user.Mandant:
return True
else:
return False
Unfortunatly this permission class isn't blocking my view even when it should. I dont know why. Did I miss something?
You need to call check_object_permissions method before response for APIView
class Employee(APIView):
permission_classes = [BelongsToClient]
serializer_class = EmployeeSerializer
def get(self, request, pk, format=None):
employee = EmployeeModel.objects.get(pk=pk)
serializer = EmployeeSerializer(employee, many=False)
self.check_object_permissions(request, employee)
return Response(serializer.data)
has_object_permission only called when you use the DestroyAPIView or RetrieveAPIView or ViewSet.
Try to use a viewset just like below
from rest_framework import viewsets
class Employee(viewsets.ViewSet):
permission_classes = [BelongsToClient]
serializer_class = EmployeeSerializer
def delete(self, request, pk, format=None):
employee = EmployeeModel.objects.get(pk=pk)
self.check_object_permissions(request, employee)
employee.Employees_deleted = True
employee.save()
return Response(status=status.HTTP_200_OK)
Note: I didn't test it but it should work.
I am trying to check if account settings view, and username is a superuser then render the html. if not goes to error 403 , but how can I do this using templateview
class AccountSettingsView(LoginRequiredMixin, TemplateView):
template_name = 'profile/account-settings.html'
if request.user.is_superuser:
# error 403
else:
template_name
You can use the UserPassesTestMixin mixin [Django-doc] for that, and then override the test_func(..) method [Django-doc]:
from django.contrib.auth.mixins import UserPassesTestMixin
class AccountSettingsView(LoginRequiredMixin, UserPassesTestMixin, TemplateView):
template_name = 'profile/account-settings.html'
def test_func(self):
return self.request.user.is_superuser
You can override the dispatch method and check that condition there:
class AccountSettingsView(LoginRequiredMixin, TemplateView):
template_name = 'profile/account-settings.html'
def dispatch(self, request, *args, **kwargs):
if self.request.user.is_superuser:
# raise 403
return super().dispatch(request, *args, **kwargs)
I am a beginner learning django rest framework and I just encounter this error and I can't seem to find a way around it. Here is the permissions.py sample code
from rest_framework import permissions
class UpdateOwnProfile(permissions, BaseException):
"""Allow user to edit their own profile"""
def has_object_permission(self, request, view, obj):
"""Check if user is trying to update their own profile"""
if request.method in permissions.SAFE_METHODS:
return True
return obj.id == request.user.id
Here is also a sample of the views.py sample codes
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework import viewsets
from rest_framework.authentication import TokenAuthentication
from profiles_api import serializers
from profiles_api import models from profiles_api import permissions
class HelloApiView(APIView): """Test Api view""" serializer_class = serializers.HelloSerializer
def get(self, request, format=None):
"""Returns a list of Api features"""
an_apiview = [
'Uses HTTP methods as function (get, post, patch, put, delete)',
'Is similar to a traditional Django view',
'Gives you the most control over your application logic',
'Is mapped manually to URLs',
]
return Response({'message': 'Hello', 'an_apiview': an_apiview})
def post(self, request):
"""Create a hello message with our name"""
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
name = serializer.validated_data.get('name')
message = f'Hello {name}'
return Response({'message': message})
else:
return Response(
serializer.errors,
status = status.HTTP_400_BAD_REQUEST
)
def put(self, request, pk=None):
"""Handling updates of objects"""
return Response({'method': 'PUT'})
def patch(self, request, pk=None):
"""Handle a partial update of an object"""
return Response({'method': 'PATCH'})
def delete(self, request, pk=None):
"""Delete an object"""
return Response({'method': 'DELETE'})
class HelloViewset(viewsets.ViewSet): """Test API Viewset""" serializer_class = serializers.HelloSerializer
def list(self, request):
"""Return a hello message"""
a_viewset = [
'Uses actions (list, create, retrieve, update, partial update'
'Automatically maps to URLs using router'
'provides more functionality with less code'
]
return Response({'message': 'Hello', 'a_viewset': a_viewset})
def create(self, request):
"""Create a new hello message"""
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
name = serializer.validated_data.get('name')
message = f'Hello {name}!'
return Response({'message': message})
else:
return Response(
serializer.errors,
status=status.HTTP_400_BAD_REQUEST
)
def retrieve(self, request, pk=None):
"""Handle getting an object by its ID"""
return Response({'http_method': 'GET'})
def update(self, request, pk=None):
"""Handle updating an object"""
return Response({'http_method': 'PUT'})
def partial_update(self, request, pk=None):
"""Handle updating of an object"""
return Response({'http_method': 'PATCH'})
def destroy(self, request, pk=None):
"""Handle removing an object"""
return Response({'http_method': 'DELETE'})
class UserProfileViewSet(viewsets.ModelViewSet): """Handle creating and updating profiles""" serializer_class = serializers.UserProfileSerializer queryset = models.UserProfile.objects.all() authentication_classes = (TokenAuthentication,) permission_classes = (permissions.UpdateOwnProfile,)
And while running the development server I get this error:
class UpdateOwnProfile(permissions, BaseException): TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
permissions (rest_framework.permissions) is of type module (whose type is type FWIW), but the type of BaseException is type (like all regular classes). So you have a metaclass conflict as expected.
Presumably, you meant to use permissions.BasePermission class from the module:
class UpdateOwnProfile(permissions.BasePermission, BaseException):
...
...
You can also import and refer the class directly:
from rest_framework.permissions import BasePermission
class UpdateOwnProfile(BasePermission, BaseException):
...
...
Suppose you want to give out
{field1, field2, field3} on detail request.
{field1, field2} on list request.
{field1} on some other simpler list request.
I have seen examples using get_serializer_class with self.action which can handle detail vs list scenario. (https://stackoverflow.com/a/22755648/433570)
Should I define two viewsets and two url endpoints?
Or is there a better approach here?
I guess this could be applied to tastypie as well. (two resources?)
I haven't tested it myself but I think you can do it overriding the methods you need.
According to the documentation (Marking extra actions for routing) you could do:
class UserViewSet(viewsets.ViewSet):
"""
Example empty viewset demonstrating the standard
actions that will be handled by a router class.
If you're using format suffixes, make sure to also include
the `format=None` keyword argument for each action.
"""
def list(self, request):
pass
def create(self, request):
pass
def retrieve(self, request, pk=None):
pass
def update(self, request, pk=None):
pass
def partial_update(self, request, pk=None):
pass
def destroy(self, request, pk=None):
pass
Or if you need custom methods:
from django.contrib.auth.models import User
from rest_framework import status
from rest_framework import viewsets
from rest_framework.decorators import detail_route, list_route
from rest_framework.response import Response
from myapp.serializers import UserSerializer, PasswordSerializer
class UserViewSet(viewsets.ModelViewSet):
"""
A viewset that provides the standard actions
"""
queryset = User.objects.all()
serializer_class = UserSerializer
#detail_route(methods=['post'])
def set_password(self, request, pk=None):
user = self.get_object()
serializer = PasswordSerializer(data=request.DATA)
if serializer.is_valid():
user.set_password(serializer.data['password'])
user.save()
return Response({'status': 'password set'})
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
#list_route()
def recent_users(self, request):
recent_users = User.objects.all().order('-last_login')
page = self.paginate_queryset(recent_users)
serializer = self.get_pagination_serializer(page)
return Response(serializer.data)