How to Convert Api view class to CreateModelMixin - django

class Add_Product(APIView):
def post(self,request,*args, **kwargs):
user=request.user
if user.is_authenticated:
data=request.data
date=datetime.now().date()
slug=user.username+"-"f'{int(time())}'
print(data)
serializer=ProductSerializer(data=data,many=True)
if serializer.is_valid():
print(serializer.data)
serializer.save(user=request.user,slug=slug)
return Response("Your product is added")
return Response(serializer.errors)
return Response("Login First")
I want to convert this to CreateModelMixin But i don't know how to pass values like request.user and slug in create method.
class Product_List(GenericAPIView,CreateModelMixin):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def post(self,request,*args, **kwargs):
return self.create(request,*args,**kwargs)

You can pass the user to the serializer through its context then override its create method:
# View
class Product_List(GenericAPIView,CreateModelMixin):
queryset = Product.objects.all()
serializer_class = ProductSerializer
permission_classes = (IsAuthenticated,)
def get_serializer_context(self):
return {'user': self.request.user}
# Serializer
class ProductSerializer(serializers.ModelSerializer):
[...]
def create(self, validated_data):
user = self.context['user']
slug = f'{user.username}-{int(time())}'
return Product.objects.create(
user=user,
slug=slug,
**validated_data
)

Related

Check if object parent user == request.user on child object create/update

I want to check if parent object user is request.user to correctly add child amd grandchild object permissions.
Wanna figure out how to do it properly in Django & DRF.
Models:
class Parent(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Child(models.Model):
parent = models.ForeignKey(Parent, on_delete=models.CASCADE, related_name='childs')
class SecondChild(models.Model):
parent = models.ForeignKey(Child, on_delete=models.CASCADE, related_name='secondchilds')
Views:
class ParentViewSet(viewsets.ModelViewSet):
queryset = Parent.objects.all()
serializer_class = ParentSerializer
permission_classes = [permissions.IsAuthenticated, IsOwner]
def perform_create(self, serializer):
serializer.save(user=self.request.user)
def get_queryset(self):
user = self.request.user
if user.is_superuser:
return Parent.objects.all()
return Parent.objects.filter(user=user).prefetch_related('childs', 'childs__secondchilds')
class ChildViewSet(viewsets.ModelViewSet):
queryset = Child.objects.all()
serializer_class = ChildSerializer
permission_classes = [permissions.IsAuthenticated]
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
parent_id = self.request.data.get('parent_id')
parent_instance = Parent.objects.filter(id=parent_id).first()
if not serializer.is_valid(raise_exception=True):
print(serializer.errors)
serializer.save(parent=parent_instance)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def get_queryset(self):
user = self.request.user
if user.is_superuser:
return Parent.objects.all()
return Child.objects.filter(parent__user=user).prefetch_related('SecondChild')
you can do the checking on your custom permission class, then add the it to your view's permission_classes list
permissions
class IsParentOwnerOrReadOnly(permissions.BasePermission):
def has_permission(self, request, view):
parent_id = int(request.data.get('parent_id'))
parent_instance = Parent.objects.filter(id=parent_id).first()
return (request.method in permissions.SAFE_METHODS or
(parent_instance and request.user == parent_instance.user))
views
class ChildViewSet(viewsets.ModelViewSet):
...
permission_classes = [permissions.IsAuthenticated, IsParentOwnerOrReadOnly]
...

How can I pass serializer.data into create function without using save function in views django?

views.py
def productslist(request):
products = Products.objects.all()
context = {'products':products}
return render(request,'productslist.html',context)
def productsform(request):
return render(request,'productscreate.html')
#api_view(['GET','POST'])
def products_list(request):
if request.method == 'GET':
product = Products.objects.all()
serializer = Productserialize(product,many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = Productserialize(data=request.data)
if serializer.is_valid():
def create(serializer):
return Products.objects.create(serializer)
return Response(serializer.data)
return Response(serializer.errors)
#api_view(['GET','PUT'])
def products_detail(request, pk):
products = Products.objects.get(pk=pk)
if request.method == 'GET':
serializer = Productserialize(products)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = Productserialize(products, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors)
In views.py I have done create function but it is not working not saving data
I want to save serializer data using create function
I want to pass serializer.data into create function in post method api
serializer.py
class Productserialize(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=100)
description = serializers.CharField(required=False, allow_blank=True, max_length=100)
image = serializers.FileField()
def create(self, validated_data):
"""
Create and return a new `Snippet` instance, given the validated data.
"""
return Products.objects.create(**validated_data)
Just use a ListCreateAPIView and use a ModelSerializer instead of a Serializer.
# Serializer
class ProductSerializer(serializers.ModelSerializer):
class Meta:
fields = ('id', 'title', 'description', 'image')
model = Product
# View
from rest_framework.generics import ListCreateAPIView
class ProductListCreate(ListCreateAPIView):
serializer_class = ProductSerializer
queryset = Product.objects.all()
ListCreateAPIView handle GET to list and POST to create new objects, you don't need to override anything else.
you can try to call it
if serializer.is_valid():
def create(serializer):
return Products.objects.create(serializer.data)
crerate(serializer)
return Response(serializer.data)

DRF: Creating mixin using different serializers & objects

I have two APIView classes with almost similar behaviour (and code). Different are only serializers and models object (Favorite & FavoriteSerializer for first class and PurchaseList and PurchaseListSerializer for second). As far as I understand it is a perfect usecase for mixin, according to DRF docs ([DRF: Creating custom mixins] 1https://www.django-rest-framework.org/api-guide/generic-views/).
Unfortunately, I'm struggling with how to define mixin without the definition of serializer & obj in it.
class FavoriteViewSet(APIView):
def get(self, request, recipe_id):
user = request.user.id
data = {"user": user, "recipe": recipe_id}
serializer = FavoriteSerializer(
data=data,
context={"request": request},
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status.HTTP_201_CREATED)
def delete(self, request, recipe_id):
user = request.user
favorite_recipe = get_object_or_404(
Favorite, user=user, recipe__id=recipe_id
)
favorite_recipe.delete()
return Response(
"Рецепт удален из избранного", status.HTTP_204_NO_CONTENT
)
class PurchaseListView(APIView):
def get(self, request, recipe_id):
user = request.user.id
data = {"user": user, "recipe": recipe_id}
serializer = PurchaseListSerializer(
data=data, context={"request": request}
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status.HTTP_201_CREATED)
def delete(self, request, recipe_id):
user = request.user
purchase_list_recipe = get_object_or_404(
PurchaseList, user=user, recipe__id=recipe_id
)
purchase_list_recipe.delete()
return Response(
"Рецепт удален из списка покупок", status.HTTP_204_NO_CONTENT
)
You can create your own mixin like this:
class CustomMixin:
serializer_class = None
model_class = None
def get(self, request, recipe_id):
user = request.user.id
data = {"user": user, "recipe": recipe_id}
serializer = self.serializer_class(
data=data,
context={"request": request},
)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(serializer.data, status.HTTP_201_CREATED)
def delete(self, request, recipe_id):
user = request.user
obj = get_object_or_404(
self.model_class, user=user, recipe__id=recipe_id
)
obj.delete()
return Response(
"Рецепт удален из избранного", status.HTTP_204_NO_CONTENT
)
class FavoriteViewSet(CustomMixin, APIView):
serializer_class = FavoriteSerializer
model_class = Favorite
class PurchaseListView(CustomMixin, APIView):
serializer_class = PurchaseListSerializer
model_class = PurchaseList
Or use the GenericApiView with the bulti-in mixins
https://www.django-rest-framework.org/api-guide/generic-views/#genericapiview

Range Filter not working in django rest does not react at all when filtered

Range Filter not working in django rest does not react at all when filtered
View
class MDShopListView(generics.ListAPIView):
queryset = smartphone.objects.all()
filter_backends = (DjangoFilterBackend,)
filterset_class = ShoppFilter
def get(self,request):
queryset = self.get_queryset()
serializer=MDShopListSerializer(queryset,many=True)
return Response(serializer.data)
You need to filter the queryset, with self.filter_queryset(…) [drf-doc]:
class MDShopListView(generics.ListAPIView):
queryset = smartphone.objects.all()
filter_backends = (DjangoFilterBackend,)
filterset_class = ShoppFilter
def get(self, request):
queryset = self.filter_queryset(self.get_queryset())
serializer=MDShopListSerializer(queryset,many=True)
return Response(serializer.data)
But actually overriding get(…) is not necessary, since now it does almost exactly what a ListAPIView does by default, except that you do not paginate. Indeed, a ListAPIView is defined as [GitHub]:
class ListAPIView(mixins.ListModelMixin,
GenericAPIView):
"""
Concrete view for listing a queryset.
"""
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
and the .list(…) method is defined in the ListModelMixin as [GitHub]:
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
You thus can define this as:
class MDShopListView(generics.ListAPIView):
queryset = smartphone.objects.all()
filter_backends = (DjangoFilterBackend,)
filterset_class = ShoppFilter
# specify the serializer ↓
serializer_class = MDShopListSerializer

In ModelSerializer self.context doesn't have request , how to get this

my serialiser class is:
class NakshatraDateSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(read_only=True)
is_note_present = serializers.SerializerMethodField(read_only=True)
def get_is_note_present(self, nakshatra_date ):
user = None
request = self.context.get("request")
print (str(request))
if request and hasattr(request, "user"):
user = request.user
# user = serializers.SerializerMethodField('_user')
if user is None:
logging.error("user is none")
return False
try:
nakshatra_date_note = Notes.objects.all().get(nakshatra_date=nakshatra_date, created_by=user)
except ObjectDoesNotExist:
nakshatra_date_note = None
if nakshatra_date_note is None:
logging.error("no note present for this nakshatra date")
return False
logging.error(str(nakshatra_date_note))
return True
date = serializers.DateField(
required=True,
error_messages={
"date": "Nakshatra for date already present",
},
validators=[UniqueValidator(queryset=NakshatraDate.objects.all(), message="Nakshatra for date already present
")]
)
class Meta:
model = NakshatraDate
fields = (
'id', 'is_note_present', 'date', 'updated', 'created')
vewclass is :
class NakshatraDateViewSet(viewsets.ModelViewSet):
"""
Nakshatra dates
"""
permission_classes = (AllowAny,)
queryset = NakshatraDate.objects.all()
serializer_class = NakshatraDateSerializer
pagination_class = LargeResultsSetPagination
filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
filter_class = NakshatraDateFilter
def filter_queryset(self, queryset):
queryset = super(NakshatraDateViewSet, self).filter_queryset(queryset)
return queryset.order_by('-id')
def perform_create(self, serializer):
serializer.save()
i am trying to set value 'True' in variable is_note_present if a Note is present on a particular date. or else 'False'. But i am not able to get request object in self.context.
class Notes(models.Model):
date = models.DateField(null=False)
updated = models.DateTimeField(auto_now=True)
created = models.DateTimeField(auto_now_add=True, editable=False)
created_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='notes', on_delete=models.CASCADE)
i tried various way to get request . some of them aredef get_serializer_context(self):
return {'request': self.request}
and trien to context (context={'request':request}) with serialize_class variable in modelviewset
still i am not able to get the request in self.context
Your view should be like this.
class NakshatraDateViewSet(viewsets.ModelViewSet):
"""
Nakshatra dates
"""
permission_classes = (AllowAny,)
serializer_class = NakshatraDateSerializer
pagination_class = LargeResultsSetPagination
filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
filter_class = NakshatraDateFilter
def get_queryset(self, queryset):
queryset = NakshatraDate.objects.all()
return queryset.order_by('-id')
def get_serializer_context(self):
return {'request': self.request}
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(data=serializer.data)
return Response(status=status.HTTP_400_BAD_REQUEST)
You can see further about viewsets here.