Where can I to write my logic in APIView? - python

In the CreateAPIView I can override the create method to add my logic:
class OpenstackAccountCreateAPIView(CreateAPIView):
"""
create openstack account
"""
serializer_class = OpenstackAccountCreateSerializer
def create(self, request, *args, **kwargs):
# put my logic here
......
But if I have a APIView, where can I to write my logic?
class OpenstackAccountLoginAPIView(APIView):
serializer_class = OpenstackAccountLoginSerializer
# where can I put my login logic?
My OpenstackAccountLoginSerializer in serializers.py:
class OpenstackAccountLoginSerializer(Serializer):
password = serializers.CharField()

You can overide the method of the verb you want. Probably to create an account you'll want POST. Like this:
class OpenstackAccountLoginAPIView(APIView):
serializer_class = OpenstackAccountLoginSerializer
def post(self, request, format=None):
# Logic goes here, defining resp with whatever you want to respond.
return Response(resp)
Than you can call it with the POST verb, same as when using create with CreateAPIView as in the documentation here.

class OpenstackAccountLoginAPIView(APIView):
serializer_class = OpenstackAccountLoginSerializer
def get(self, request):
"""
Return a list of all users.
"""
def post(self, request):
"""
Create users.
"""

Related

Django : class based view with multiple permissions

I am trying to create a class based view with different permissions per function. I have already created my permissions in a file that I import :
utils.py
from rest_framework.permissions import BasePermission
from rest_framework.authentication import TokenAuthentication
from rest_framework.views import APIView
class IsOwner(BasePermission):
"""
Check if the user who made the request is owner.
Use like that : permission_classes = [IsOwner]
"""
def has_object_permission(self, request, view, obj):
# if request.method in permissions.SAFE_METHODS:
# return True
return obj.user == request.user
class IsAdmin(BasePermission):
"""
Check if the user who made the request is admin.
Use like that : permission_classes = [IsAdmin]
"""
def has_permission(self, request, view):
return request.user.is_admin
class BaseView(APIView):
"""
Check if a user is authenticated
"""
authentication_classes = [
TokenAuthentication,
]
class AdminOrOwnerView(APIView):
"""
Check if a user is admin or owner
"""
authentication_classes = ( IsOwner | IsAdmin,)
I want to create a class with different method. The GET method would allow admins to have a view of all users. The POST method would allow any user to connect.
I have already created the serializer for each of these methods but I cannot assign different permissions per method.
This is my class :
class Users(APIView):
def get(self, request):
"""Only for admin"""
try:
user = Users.objects.all()
except User.DoesNotExist():
return HttpResponse(status=404)
serializer = UserSerializer(users, many=True)
return Response(serializer.data)
def post(self, request):
"""For everyone"""
serializer = RegistrationSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.error)
How I can apply my permissions on each of the methods separately ?
Thank you in advance for your help
You just need to create a permission class like this:
class CustomPermissionClass(BasePermission):
def has_permission(self, request, view):
if request.method == 'GET':
# logic for GET method
elif request.method == 'POST'
# logic for POST metod
# default logic
And add it to your view:
class Users(APIView):
permission_classes = [CustomPermissionClass]

Adding a redirect to CreateAPIView

I want to redirect the user to the AddQuestionsView after the user creates a quiz(after adding title).
My CreateQuiz
class CreateQuizzView(CreateAPIView):
serializer_class = CreateQuizSerializer
My serializers.py file
class CreateQuizSerializer(serializers.ModelSerializer):
class Meta:
model = Quizzer
fields = ['title']
def create(self, validated_data):
user = self.context['request'].user
new_quiz = Quizzer.objects.create(
user=user,
**validated_data
)
return new_quiz
Can i add redirect by adding any Mixin or change need to change the GenericView.
An APIView is normally not used by a browser, or at least not directly, hence a redirect makes not much sense. The idea is that some program makes HTTP requests, and thus retrieves a response. Most API handlers will not by default follow a redirect anyway.
You can however make a redirect, by overriding the post method:
from django.shortcuts import redirect
class CreateQuizzView(CreateAPIView):
serializer_class = CreateQuizSerializer
def post(self, *args, **kwargs):
super().post(*args, **kwargs)
return redirect('name-of-the-view')

Cant create a record within viewset custom view based on url parameters

Hello I have a django rest framework view set. For the create view I want to create a custom view that will create a new record based on two different parameters that are passed on through the url which are namespace and path. I looked at the documentation but i couldnt find how it should look like. I am noit sure what I need to do in order to create a record based on both url parameters.
I basically tried setting the create to a CreateAPIView but it did not work
class PreferenceViewSet(viewsets.ViewSet):
queryset = Preference.objects.all()
serializer_class = PreferenceSerializer
def get_permissions(self):
if self.action == 'create' or self.action == 'destroy':
permission_classes = [IsAuthenticated]
else:
permission_classes = [IsAdminUser]
return [permission() for permission in permission_classes]
def list(self, request):
queryset = Preference.objects.all()
serializer = PreferenceSerializer(queryset, many=True)
return Response(serializer.data)
def create(self, request):
queryset = Preference.objects.all()
serializer = PreferenceSerializer(queryset, many=True)
return Response(serializer.data)
I want to setup the create to create a preference with the two parameters that are passe in the url
path('preferences/<str:namespace>/<str:path>', preference_path, name='preference-path'),
I wanted it to create a new object with the namespace and path
You need to do this in 2 steps:
Add the url arguments to serializer context from viewset
Override create method on the serializer and use data passed on the context to create the record
So, at first override get_serializer_context method to add the arguments to context:
class PreferenceViewSet(viewsets.ViewSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._namespace = None
self._path = None
...
...
def get_serializer_context(self):
context = super().get_serializer_context()
context.update(namespace=self._namespace, path=self._path)
return context
def create(self, request):
self._namespace = self.kwargs['namespace']
self._path = self.kwargs['path']
queryset = Preference.objects.all()
serializer = PreferenceSerializer(queryset, many=True)
return Response(serializer.data)
Now, you can access the parameters inside the overriden create method of the serializer and create the record as you want e.g.:
class PreferenceSerializer(serializers.HyperlinkedModelSerializer):
...
...
def create(self, validated_data):
namespace = self.context['namespace']
path = self.context['path']
# Create object here based on the params

Modifying a Django Rest Framework Request

I have a Django rest framework api set up, and I'm trying to insert the current time into incoming PUT requests. I currently have:
class ItemViewSet(viewsets.ModelViewSet):
queryset = Item.objects.filter(done = False).order_by('-time')
serializer_class = ItemSerializer
paginate_by = None
def list(self, request, *args, **kwargs):
self.object_list = self.filter_queryset(self.get_queryset())
serializer = self.get_serializer(self.object_list, many=True)
return Response({'results': serializer.data})
This handles partial updates, but I would like to be able to send a request setting an Item to done = True and have the api also insert a unix timestamp into the data sent to the serializer. Could I alter the request object like this, or is there a better way?
def put(self, request, *args, **kwargs):
request.data['time'] = time.time()
return self.partial_update(request, *args, **kwargs)
Instead of modifying request, override serializer's method update.
Class ItemlSerializer(serializers.ModelSerializer):
class Meta:
model = ItemModel
fields = '__all__'
read_only_fields = ('time',)
def update(self, instance, validated_data):
instance.time = time.time()
return super().update(instance, validated_data)
You make a Parent serializer mixin with a serializer method field. Then all your serializers can inherit this serializer mixin.
class TimeStampSerializerMixin(object):
timestamp = serializers.SerializerMethodField()
def get_timestamp((self, obj):
return str(timezone.now())

How to create a mixin pattern in Python

I'm trying to understand the concept of mixins using the following example:
I have a simple serializer using the DRF:
class TestSerializer(serializers.ModelSerializer):
class Meta:
model = Test
fields = ('url', 'name', 'user')
I would like to create a mixin which enhances (overwrites the class get_queryset) for any custom serializer by added a check that the user owns the objects and only shows these items for example...
def get_queryset(self):
"""
This view should return a list of all the items
for the currently authenticated user.
"""
user = self.request.user
return ???????.objects.filter(user=user)
So my TestSerializer would look like this:
class TestSerializer(serializers.ModelSerializer, UserListMixin):
etc
and UserListMixin:
class UserListMixin(object):
"""
Filtering based on the value of request.user.
"""
def get_queryset(self, *args, **kwargs):
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
user = self.request.user
return super([?????????], self).get_queryset(*args, **kwargs).filter(user=user)
What I'm having difficulty with is creating the UserListMixin class. How can I return the correct object based on what I'm extending return [OBJECT].objects.filter(user=user) and would this approach work?
Filters are chainable, so the best thing to do here is to call the super method to get the default queryset, then add your filter on top:
def get_queryset(self, *args, **kwargs)
user = self.request.user
return super(UserListMixin, self).get_queryset(*args, **kwargs).filter(user=user)

Categories

Resources