how to set pagination in django custom APIView? - python

I have a very simple APIView, but I don't know how to setup pagination here. In this scenario I create a CustomPagination.
pagination_class = CustomPagination works OK when I define queryset at the beginning in generics.ListAPIView, for ex. queryset = Event.objects.all() but not with custom get:
views.py:
class ProductAPIView(APIView):
def get(self, request):
pagination_class = CustomPagination
data = Product.objects.filter(status=1)
product_serializer = ProductSerializers(data,many=True)
productData=[]
for record in product_serializer.data:
value = json.dumps(record)
temp = json.loads(value)
_id = temp['id']
title = temp['title']
sub_title = temp['sub_title']
productData.append({"id":_id, "title":title, "sub_title":sub_title})
return Response({"productData":productData})
pagination.py:
from rest_framework.pagination import PageNumberPagination
class CustomPagination(PageNumberPagination):
page_size = 1
page_size_query_param = 'page_size'
max_page_size = 1000

your views.py should look like this:
class ProductAPIView(APIView):
pagination_class = CustomPagination()
def get(self, request):
queryset = Product.objects.filter(status=1)
# for pagination
page = self.pagination_class.paginate_queryset(queryset=queryset, request=request)
if page is not None:
serializer = ProductSerializers(page, many=True)
return self.pagination_class.get_paginated_response(serializer.data)
serializer = ProductSerializers(queryset, many=True)
return Response(serializer.data)
Why are you using this:
if it is done automatically by serializer
for record in product_serializer.data:
value = json.dumps(record)
temp = json.loads(value)
_id = temp['id']
title = temp['title']
sub_title = temp['sub_title']
productData.append({"id":_id, "title":title, "sub_title":sub_title})

Related

How to set query parameters in URL in Django

I have for the moment a GET request where I have to send a body as a parameter but as in front it is not possible to make a GET request with a body I would like to pass my parameters as query parameters in the URL . How can I do this with the code I currently have?
My serializer class:
#dataclass
class PlantLinkParams:
plant_id: int
link: str
class LnkPlantPlantByLinkSerializer(serializers.Serializer):
plant_id = serializers.IntegerField()
link = serializers.CharField()
def create(self, validated_data):
return PlantLinkParams(**validated_data)
My view class :
class PlantLinkAPIView(APIView):
permission_classes = (AllowAnonymous,)
queryset = LnkPlantPlant.objects.prefetch_related("plant", "plant_associated")
def get(self, request):
params_serializer = LnkPlantPlantByLinkSerializer(data=request.data)
params_serializer.is_valid(raise_exception=True)
params = params_serializer.save()
data = self.getAllPlantAssociatedByLink(params)
serializer = ReadLnkPlantPlantSerializer(instance=data, many=True)
return Response(serializer.data, status=status.HTTP_200_OK)
def getAllPlantAssociatedByLink(self, params: PlantLinkParams):
data = []
queryset = (
LnkPlantPlant.objects.filter(
plant=params.plant_id,
link=params.link,
)
)
for entry in queryset:
data.append(entry)
return data
You could do something simpler using a ListAPIView:
class PlantLinkAPIView(ListAPIView):
permission_classes = (AllowAnonymous,)
serializer_class = ReadLnkPlantPlantSerializer
def get_queryset(self):
# Retrieve the query parameters (?plant_id=xxx&link=yyy)
try:
plant_id = int(self.request.GET.get('plant_id'))
except (ValueError, TypeError):
# Prevents plant_id to be set if not a valid integer
plant_id = None
link = self.request.GET.get('link')
params = {}
if plant_id:
params['plant__id'] = plant_id
if link:
params['link'] = link
# Only filtering the queryset if one of the params is set
if params:
return LnkPlantPlant.objects.filter(**params)
return LnkPlantPlant.objects.all()
You don't need more than that to get your view working.

How can I pass an object selected by the user, to another view and retrieve a specific column from that object?

I'm trying to figure out the most efficient way to GET values inside my stock_list column from the current object that's being viewed by a user.
BucketDetail is used to retrieve the specific object selected by the user via item = self.kwargs.get('pk')
class BucketDetail(generics.RetrieveAPIView):
permission_classes = [IsAuthenticated]
serializer_class = BucketListSerializer
queryset = Bucket.objects.all()
def get_object(self, queryset=queryset, **kwargs):
item = self.kwargs.get('pk')
return get_object_or_404(Bucket, slug=item)
How can I pass the object instance, from BucketDetail to BucketData view, followed by getting the column, stock_list, from the current object instance?
class BucketData(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
stocks = Bucket.objects.get(stock_list)
...
data = response.json()
return Response(data, status=status.HTTP_200_OK)
above is what I have so far, stocks = Bucket.objects.get(stock_list) does not work like I thought.
models.py
class Bucket(models.Model):
category_options = (
('personal', 'Personal'),
('social', 'Social'),
)
class BucketObjects(models.Manager):
def get_queryset(self):
return super().get_queryset()
...
slug = models.SlugField(unique=True, blank=True)
stock_list = ArrayField(models.CharField(max_length=6,null=True),size=30,null=True)
...
objects = models.Manager()
bucketobjects = BucketObjects()
class Meta:
ordering = ('-created',)
def total_stocks_calc(self):
self.stock_count = Bucket.objects.aggregate(Sum('stock_list', distinct=True))
self.save()
You should use model pk or your unique slug to retrieve stock_list data within your BucketData view. You also should use a serializer for the data. Pass your slug or pk from urls file to your view. Try something like this (code is not tested and can be improved):
Serializer:
class StockListSerializer(ModelSerializer):
stock_list = serializers.ListField(child=serializers.CharField())
class Meta:
model = Bucket
fields = ("stock_list",)
View:
class BucketData(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, *args, **kwargs):
slug = kwargs.get("slug")
bucket_object = get_object_or_404(Bucket, slug=slug)
serialzer = StockListSerializer(bucket_object.stock_list)
return Response(serialzer.data, status=status.HTTP_200_OK)

Django REST Framework filter backend with multiple value?

I want to get query list with one key more values. For example,
http://127.0.0.1:8000/management/device/model/list/?device_type=1&hardware_model_mother=master&hardware_model_mother=MasterModel1&hardware_model_child=SlaveModel1
Then i can get query list of device_type=1,hardware_model_child=SlaveModel1,hardware_model_mother=master
and device_type=1,hardware_model_child=SlaveModel1,hardware_model_mother=MasterModel1.
I need a list of fields that's why i didn't use the function in_bulk().
I found some filters in django-filter's doc, here's the link:
https://django-filter.readthedocs.io/en/latest/ref/filters.html
I choose MultipleChoiceFilter, it will use OR, that's what i wanted.
Here's my filter's code:
from django_filters import FilterSet, MultipleChoiceFilter
from Device_set.views.DeviceModelFilter import DeviceModelFilter
from .head import *
# one key for multiple values
class DeviceModelFilter(FilterSet):
MOTHER_CHOICES, CHILD_CHOICES = DeviceModelFilter().MyChoices()
hardware_model_mother = MultipleChoiceFilter(choices=MOTHER_CHOICES)
hardware_model_child = MultipleChoiceFilter(choices=CHILD_CHOICES)
class Meta:
model = device_model
fields = ['hardware_model_mother', 'hardware_model_child']
and my ListAPIView:
class DeviceModelListView(ListAPIView):
permission_classes = [Developer | IOTWatch | IsAdminUser]
serializer_class = DeviceModelListSerializer
queryset = device_model.objects.all()
filter_backends = (SearchFilter, DjangoFilterBackend,)
filter_class = DeviceModelFilter
search_fields = ('id', 'name')
filterset_fields = ('hardware_model_mother', 'hardware_model_child')
def list(self, request, *args, **kwargs):
dtype = self.request.query_params.get('device_type')
if dtype is not None:
queryset = self.queryset.filter(device_type__icontains=dtype)
else:
queryset = self.queryset
queryset = self.filter_queryset(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)
def get(self, request, *args, **kwargs):
return Response(Return_msg(self.list(request)))
when url is http://127.0.0.1:8000/management/device/model/list/?device_type=1&hardware_model_mother=master&hardware_model_mother=MasterModel1
The result is right:
right response
However, when url is http://127.0.0.1:8000/management/device/model/list/?device_type=1&hardware_model_child=SlaveModel1
It's wrong:
false
Traceback:
Traceback
It cost me about one day to solve this problem, could you please tell me how to fix it, or anther way to implement it?

Assign a serializer field to current user id and "not" allow to edit it from BrowsableAPIRenderer on Django Rest Framework 2.3.13

I have a below view, serializer and model. Using BrowsableAPIRenderer i render HTML page. I need to assign current user id to user_id field and hide the same from HTML rendering(not allow to edit and enter). I am using Django rest framework 2.3.13. Kindly help me to achieve this.
serializer.py
class TagOwnerSerializer(serializers.HyperlinkedModelSerializer):
tag_id = serializers.SlugRelatedField(slug_field='tag_id')
user_id = serializers.IntegerField(write_only=True)
class Meta:
model = TagOwner
fields = ('url','tag_id','start_time','end_time','user_id')
views.py
class TagOwnerViewSet(viewsets.ModelViewSet):
"""
TagOwner table view set.
"""
model = TagOwner
queryset = TagOwner.objects.all()
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
serializer_class = TagOwnerSerializer
renderer_classes = (BrowsableAPIRenderer, JSONRenderer,JSONPRenderer,XMLRenderer,YAMLRenderer)
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter ,filters.OrderingFilter)
filter_class = TagOwnerFilter
#search_fields = ('tag_id',)
ordering_fields = '__all__'
def get_queryset(self):
user = self.request.user
if self.request.user.is_authenticated():
if not user:
return []
return TagOwner.objects.filter(user_id=user.id)
public_tags = TagReads.objects.filter(public=True).values_list('tag_id').distinct()
return TagOwner.objects.filter(tag_id__in=public_tags)
def create(self,request):
serializer = self.serializer_class(data=request.DATA)
if serializer.is_valid():
user=self.request.user.id
serializer.save(user_id = user)
return Response(serializer.data, status = status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
models.py
class TagOwner(models.Model):
user_id = models.IntegerField(blank=False,db_column='user_id',)
tag_id = models.OneToOneField('Tags',on_delete=models.CASCADE,primary_key=True,db_column='tag_id',)
start_time = models.DateTimeField(blank=True, null=True)
end_time = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tag_owner'
Found it myself.
serializer.py
class TagOwnerSerializer(serializers.HyperlinkedModelSerializer):
tag_id = serializers.SlugRelatedField(slug_field='tag_id')
user_id = serializers.Field(source='user_id')
#user_id = serializers.PrimaryKeyRelatedField(read_only=True,default=serializers.CurrentUserDefault())
class Meta:
model = TagOwner
fields = ('url','tag_id','start_time','end_time','user_id')
views.py
class TagOwnerViewSet(viewsets.ModelViewSet):
"""
TagOwner table view set.
"""
model = TagOwner
queryset = TagOwner.objects.all()
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
serializer_class = TagOwnerSerializer
renderer_classes = (BrowsableAPIRenderer, JSONRenderer,JSONPRenderer,XMLRenderer,YAMLRenderer)
filter_backends = (filters.DjangoFilterBackend, filters.SearchFilter ,filters.OrderingFilter)
filter_class = TagOwnerFilter
#search_fields = ('tag_id',)
ordering_fields = '__all__'
def get_queryset(self):
user = self.request.user
if self.request.user.is_authenticated():
if not user:
return []
return TagOwner.objects.filter(user_id=user.id)
public_tags = TagReads.objects.filter(public=True).values_list('tag_id').distinct()
return TagOwner.objects.filter(tag_id__in=public_tags)
def pre_save(self, obj):
obj.user_id = self.request.user.id
This worked perfectly for me.

Django Rest Framework : Got AttributeError when attempting to get a value for field `data_params` on serializer `OrderCreateSerializer`

This is my models:
class Order(models.Model):
"""
订单
"""
order_num = models.CharField(max_length=128, unique=True) # 订单编号
order_status = models.CharField(max_length=12) # 订单状态 "未支付", "已支付,未完成", "已完成", "已经删除","其他"
product_describe = models.TextField() # 产品描述
billing_type = models.CharField(max_length=16) # 计费类型
buytime = models.CharField(max_length=16) # 比如:1月 永久
count = models.IntegerField() # 购买数量
paytype = models.CharField(max_length=16) # 支付方式(支付包,微信,xxx)
cost = models.DecimalField(max_digits=8, decimal_places=2, default=0.00) # 费用(需要花费多少钱)
account = models.ForeignKey(to=Account) # 所属账户
ctime = models.DateTimeField(auto_now_add=True) # 创建时间
uptime = models.DateTimeField(auto_now=True) # 更新时间
def __str__(self):
return self.product_describe
def __unicode__(self):
return self.product_describe
This is my serializer:
class OrderCreateSerializer(ModelSerializer):
data_params = serializers.DictField() # 根据产品数据模型不同而异
class Meta:
model = Order
fields = (
"product_describe", # 产品描述 (购买xx产品 + 参数)
"billing_type", # 计费类型 ("包年包月")
# "buytime", # "购买时间"
# "count", # 数量
# "paytype", # 支付方式
"data_params", # 数据
)
def create(self, validated_data):
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
validated_data["order_num"] = generateOrderNum(userid=user.id)
validated_data["order_status"] = "未支付"
data_dic = validated_data.pop("data_params") #
validated_data["buytime"] = data_dic["data"]["buytime"]
validated_data["count"] = data_dic["data"]["count"]
validated_data["paytype"] = "" # 支付类型
validated_data["cost"] = 0.00 # 所需钱
validated_data["account"] = user.account # 是哪个账户
return Order.objects.create(**validated_data)
You see, in my serializer I have pop the data_params:
data_dic = validated_data.pop("data_params")
But when I access this API, I get:
AttributeError at /api/financialmanage/order/add/
Got AttributeError when attempting to get a value for field data_params on serializer OrderCreateSerializer.
The serializer field might be named incorrectly and not match any attribute or key on the Order instance.
Original exception text was: 'Order' object has no attribute 'data_params'.
If I don't pop data_params, I will get bellow error:
TypeError at /api/financialmanage/order/add/
'data_params' is an invalid keyword argument for this function
EDIT
My views.py:
class OrderSerializerCreateAPIView(CreateAPIView):
"""
create Order
"""
serializer_class = OrderCreateSerializer
permission_classes = []
queryset = Order.objects.all()
EDIT-2
In my case the data_params dictionary is necessary for me.
Because when I buy a product(such as CloudServer), which has count, vcpus, ram, disk, and bandwidth, I through the data_params to get that.
You may want to know why I must use data_params to receive the data, because, the product may be different, if the product is Wine, it can not have the vcpus property now.
I resolved it that same to yours:
data_params = serializers.DictField() # yours
data_params = serializers.DictField(write_only=True) # try it, pls.
the source code:
# rest_framework/serializers.py => L504
def to_representation():.
..
fields = self._readable_fields # this function rest_framework/serializers.py=>L371
...
class OrderCreateSerializer(ModelSerializer):
data_params = DictField(child=serializers.CharField())
.
.
.
def create(self, validated_data):
print(validated_data)
data_dic = validated_data.pop("data_params")
print(data_dic)
return super(OrderCreateSerializer, self).create(validated_data)
class OrderSerializer(ModelSerializer):
class Meta:
model = Order
fields = '__all__'
# by #Vasil Shtiliyanov if you want return data_parms after create
def to_representation(self, instance):
serialized_data = super(OrderSerializer, self).to_representation(instance)
serialized_data['data-params'] = #logic goes here
return serialized_data
class OrderSerializerCreateAPIView(CreateAPIView):
"""
create Order
"""
serializer_class = OrderCreateSerializer
permission_classes = []
queryset = Order.objects.all()
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = self.perform_create(serializer)
data = OrderSerializer(instance).data
headers = self.get_success_headers(data )
return Response(data , status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
return serializer.save()
If you want to add the data-params argument to the serializer when it is not a field in the model you should use the def to_representation function of DRF. Should look something like this:
def to_representation(self, instance):
serialized_data = super(SerializerClass, self).to_representation(instance)
serialized_data['data-params'] = #logic goes here
return serialized_data
And remove data-params from fields parameter of the Meta class.

Categories

Resources