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
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]
...
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)
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
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
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.