I have a Django function based API that inputs page number and on each page the size of the page. Here is my code.
#api_view(['POST'])
def attendance_all_get_list_by_page(request):
# ----- YAML below for Swagger -----
"""
description: attendance_all_get_list_by_page
parameters:
- name: page
type: integer
required: true
location: form
- name: page_limit
type: integer
required: true
location: form
"""
attendance_list = Attendance.objects.all().order_by('id')
page = request.GET.get('page', request.POST['page'])
paginator = Paginator(attendance_list, request.POST['page_limit'])
try:
attendances = paginator.page(page)
except PageNotAnInteger:
attendances = paginator.page(request.POST['page'])
except EmptyPage:
attendances = paginator.page(paginator.num_pages)
serializer = AttendanceSerializer(list(attendances), many=True)
data = serializer.data[:]
return Response(data, status=status.HTTP_200_OK)
my serializer:
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ("id", "username")
class AttendanceSerializer(serializers.ModelSerializer):
employee = EmployeeSerializer(many=False, read_only=True)
class Meta:
model = Attendance
fields = ('id','employee','created_at')
Imagine I had attendance record of
16,17,18,19
So for example with page=2 page_limit=2, it will show the following (this should be the last page of 4 records)
[
{
"id": 18,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:29:29.698339Z"
},
{
"id": 19,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:38:53.639749Z"
}
]
if I did (page=3 page_limit=2) or (page=10 page_limit=2), it will still show
[
{
"id": 18,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:29:29.698339Z"
},
{
"id": 19,
"employee": {
"id": 16,
"username": "haha"
},
"created_at": "2017-12-28T03:38:53.639749Z"
}
]
the expected result should be
[]
Whats wrong with my pagination, something is affecting over the last page. I want so that the last page should show the last page result but after that it should be empty record lists.
You catch EmptyPage and return last page content. So if you are out of range you will get second page everytime.
You need to return empty list in this case:
except EmptyPage:
attendances = []
Related
In Django Rest Framework, I want to group my serializer data by date, How can I do that.
I have to group it by date on the basis of timestamp date.
my model: mongo model with some more fields also but only uses these two fields
class MyModel(Document):
#mongo model
candidate_id = StringField(required=True, db_field='c')
timestamp = DateTimeField(required=True, db_field='d')
...
... more fields
My Views: my views file
class MyView(generics.ListAPIView):
serializer_class = MySerializer
def get_queryset(self):
recruiter_id = self.request.GET.get("recruiter_id")
activity_list = MyModel.objects.filter(recruiter_id=str(recruiter_id)).order_by('- timestamp')
return activity_list
my serializer: using serializermethod field to get data from other DB by using candidate id from activity model
class MySerializer(serializers.Serializer):
candidate_id = serializers.CharField()
name = serializers.SerializerMethodField()
designation = serializers.SerializerMethodField()
age = serializers.SerializerMethodField()
timestamp = serializers.DateTimeField(format="%H:%M")
def get_name(self, obj):
return something
def get_designation(self, obj):
return something
def get_age(self, obj):
return something
I want to group my response by Date like :
[
{
"date": "2022-12-05",
"candidates":[
{
"candidate_id": 1,
"name": "One",
"designation": "Lead",
"age": 30,
"timestamp": "14:30"
}
]
},
{
"date": "2022-12-04",
"candidates":[
{
"candidate_id": 2,
"name": "Two",
"designation": "Lead",
"age": 30,
"timestamp": "14:30",
}
]
}
]
my actual response is like:
[
{
"candidate_id": 1,
"name": "One",
"designation": "Lead",
"age": 30,
"activity_timestamp": "13:12"
},
{
"candidate_id": 2,
"name": "Two",
"designation": "Lead",
"age": 30,
"activity_timestamp": "13:12"
}
]
I'm new to Django,i tryed to list all invoices from my model Invoices and im getting items as only its object, to make the code efficient i need to get the whole data of items in a single query how can i get the details of items along with the data instead of item objects
Here is what i have tryed
models.py
class ItemsInvoice(models.Model):
invoiceId = models.CharField(max_length=20)
product_Id = models.CharField(max_length=20)
item_price = models.CharField(max_length=20)
class Invoices(models.Model):
customer = models.CharField(max_length=10,null=True)
total_amount = models.CharField(max_length=12,null=True)
items = models.ManyToManyField(ItemsInvoice,related_name="item_invoice")
views.py
class InvoiceView(ListAPIView):
serializer_class = InvoiceSerializers
def get_queryset(self):
# queryset = Invoices.objects.prefetch_related('items').all().order_by('-id')
queryset = Invoices.objects.all().order_by('-id')
return queryset
serializers.py
class InvoiceSerializers(serializers.ModelSerializer):
class Meta:
model = Invoices
fields = '__all__'
if i run it on my postman, its response will be like this
API response what i have
[
{
"id": 69,
"customer": "4",
"total_amount": "25000",
"items": [
66,
67,
68
]
}
]
but actually i want my output like this , ie the item field should list all data inside in it
API response what i want
[
{
"id": 69,
"customer": "4",
"total_amount": "25000",
"items": [
{
"id": 66,
"invoiceId": "69",
"product_Id": "3",
"item_price": "300",
},
{
"id": 67,
"invoiceId": "69",
"product_Id": "4",
"item_price": "200",
},
{
"id": 68,
"invoiceId": "69",
"product_Id": "4",
"item_price": "200",
}
]
}
]
how can i achieve it by using django-orm or raw query
You must define ItemInvoiceSerializer and set many=true.
class ItemInvoiceSerializer(serializers.ModelSerializer):
class Meta:
model = ItemsInvoice
fields = '__all__'
class InvoiceSerializers(serializers.ModelSerializer):
items = ItemInvoiceSerializer(many=True) # i changed true to True
class Meta:
model = Invoices
fields = '__all__'
Using Django REST framework I want to change the serializer response fields order dynamically by a list of given field names.
Output from DRF is the following:
{
"items": [
{
"name": "John",
"age": 25,
"id": 3
},
{
"name": "Sam",
"age": 20,
"id": 8
}
]
}
My filed order list is:
order_list = ['id', 'age', 'name']
What I want is:
{
"items": [
{
"id": 3,
"age": 25,
"name": "John"
},
{
"id": 8,
"age": 20,
"name": "Sam"
}
]
}
Serializer code:
class ItemSerializer(serializers.Serializer):
name = serializers.CharField()
id = serializers.IntegerField()
age = serializers.IntegerField()
To change the ordering, you will need to change the field definition in the serializer meta class.
class ItemSerializer(serializers.Serializer):
name = serializers.CharField()
id = serializers.IntegerField()
age = serializers.IntegerField()
class Meta(object):
fields = ( # this needs to be ordered properly
'id',
'age',
'name',
)
You can loop over the serializer data and order the fields using OrderedDict.
The data in the serializer is already using OrderedDict, but we can use it to further order accordingly.
from collections import OrderedDict
data = serializer.data
ordered_data = []
for item in data:
item_dict = OrderedDict()
item_dict['id'] = item['id']
item_dict['age'] = item['age']
item_dict['name'] = item['name']
ordered_data.append(item_dict)
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id','product_id','sku', 'title','price','images')
class WishListSerializer(serializers.ModelSerializer):
product = ProductSerializer()
class Meta:
model = WishList
fields = ('wishlist_id','product',)
I have two serializers. Wishlist and Product. I want to list all wishlist products. It works fine now. But the product details is in "product" key element. Can I remove that product key, and show the product details along with the wishlist_id ?
Present result:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"wishlist_id":1,
"product": {
"id": 1460,
"product_id": "04396134-3c90-ea7b-24ba-1fb0db11dbe5",
"sku": "bb4sd817",
"title": "Trinity Belt",
}
},
{
"wishlist_id":2,
"product": {
"id": 596,
"product_id": "52588d22-a62c-779b-8044-0f8d9892e853",
"sku": "ml346",
"title": "Martina Liana",
}
}
]
}
Expected result:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"wishlist_id":1,
"id": 1460,
"product_id": "04396134-3c90-ea7b-24ba-1fb0db11dbe5",
"sku": "bb4sd817",
"title": "Trinity Belt",
},
{
"wishlist_id":2,
"id": 596,
"product_id": "52588d22-a62c-779b-8044-0f8d9892e853",
"sku": "ml346",
"title": "Martina Liana",
}
]
}
This is a very bad practice and you need a lot of effort to implement serialization and deserialization, especially in case of Post, Update etc.
I can think of 2 ways.
1) You could use in the WishListSerializer the missing fields as SerializerMethodField
example
product_id = serializers.SerializerMethodField()
def get_product_id(self, obj):
return obj.get_product().product_id
2)
class WishListSerializer(serializers.HyperlinkedModelSerializer):
product_id = serializers.CharField(source='product.product_id')
.......
class Meta:
model = WishList
fields = (product_id, ......)
You could "unnest" items in to_representation
docs on it https://www.django-rest-framework.org/api-guide/fields/#custom-fields
...
class WishListSerializer(serializers.ModelSerializer):
product = ProductSerializer()
class Meta:
model = WishList
fields = ('wishlist_id', 'product',)
# add
def to_representation(self, instance):
data = super().to_representation(instance)
flat_data = dict(wishlist_id=data['wishlist_id'], **data['product']) # construct (new dict) flat data
# or you could restructure same dict: data.update(data.pop('product'))
return flat_data
Django rest framework returns the following output at an API endpoint
[
{
"id": "QFELD_2.3.2.QF1",
"siteuxid": "VBKM02_Abschlusstest",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA0",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
{
"id": "QFELD_2.3.2.QF2",
"siteuxid": "VBKM02_Abschlusstest",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA1",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
...
Is it possible to return the data in an list object format like:
{
"QFELD_2.3.2.QF1" : {
"siteuxid": "VBKM02",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA0",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
"QFELD_2.3.2.QF2" : {
"siteuxid": "VBKM02",
"section": 2,
"maxpoints": 4,
"intest": true,
"uxid": "KA1",
"points": 0,
"value": 0,
"rawinput": "",
"state": 3
},
...
My Serializer is:
class ScoreSerializer(serializers.ModelSerializer):
id = serializers.CharField(required=False, allow_blank=True, max_length=100, source='q_id')
class Meta:
model = Score
fields = ('id', 'siteuxid', 'section', 'maxpoints', 'intest', 'uxid', 'points', 'value', 'rawinput', 'state')
And View is:
class ScoreViewSet(viewsets.ModelViewSet):
serializer_class = ScoreSerializer
The ListMixin code a is good place to get started. You should get the serializer's result and transform it as you like.
class ListModelMixin(object):
"""
List a queryset.
"""
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)
# Might need to change this not to transform all the data
data = {i['id']: i for i in serializer.data}
return self.get_paginated_response(data)
serializer = self.get_serializer(queryset, many=True)
data = {i['id']: i for i in serializer.data}
return Response(data)