I have a ModelViewSet with their own filter.
class XList(viewsets.ModelViewSet,):
serializer_class = serializers.XXX
queryset = models.XXX.objects.all()
lookup_field = 'field_id'
filter_backends = [DjangoFilterBackend]
filterset_class = filters.MYOWNFILTER
I want show in response the count of data before and after filtering.
My desired answer would be,
{
"next": 2,
"previous": null,
"count": 20,
"TOTAL_COUNT": 100
"size": 10,
"results": [
{} ] }
where TOTAL_COUNT would be the total count of data before any filter, and count, the count of data after filter.
Now, I've got the following response. I need the total count.
{
"next": 2,
"previous": null,
"count": 20,
"size": 10,
"results": [
{} ] }
I'm using pagination to get the response.
def get_paginated_response(self, data):
return Response({
'next': self.page.next_page_number() if self.page.has_next() else None,
'previous': self.page.previous_page_number() if self.page.has_previous() else None,
'count': self.page.paginator.count,
'size': len(data),
'results': data
Related
as per below code I am doing the query for database then I am paginating the query result. so My question what's the use if we already hit the database for all result before pagination. Is this like Django pagination working or I am pretending something wrong?
I am getting the response as expected but had question querying the database before pagination.
Code:
class GetAllUserStoryListViewTest(APIView,LimitOffsetPagination):
permission_classes = (IsAuthenticated,)
def get_object(self,user_id):
user = User.objects.filter(id = user_id).first()
posts = Post.objects.filter(user = user)
return posts
def get(self,request,user_id):
posts = self.get_object(user_id).order_by('-post_time_stamp')
#setting the limit of this user post pagination
LimitOffsetPagination.default_limit = settings.PAGE_SIZE
posts = self.paginate_queryset(posts, request)
serializer_context = {
'request': request,
}
serializer = PostListSerializer(posts,many=True,context=serializer_context)
# return Response(serializer.data)
return self.get_paginated_response(serializer.data)
output:
{
"count": 7,
"next": "http://127.0.0.1:8000/api/list_all_story_test/27/?limit=2&offset=5",
"previous": "http://127.0.0.1:8000/api/list_all_story_test/27/?limit=2&offset=1",
"results": [
{
"id": 15,
"file": "http://127.0.0.1:8000/media/user_27/post/IMG_20190331_144024.jpg",
"post_info": "#cool",
"post_time_stamp": "2020-05-10T10:21:10Z",
"total_comment": 2,
"liked_by": [
"vipin"
],
"user": {
"id": 27,
"username": "vipin",
"email": "vipinks#xyz.edu",
"status": true,
"profile": {
"id": 24,
"full_name": "Vipin",
"mobile": 6732,
"background_picture": "http://127.0.0.1:8000/media/user_27/profile/pexels-photo-531880_0qSgRNx.jpeg",
"profile_picture": "http://127.0.0.1:8000/media/user_27/profile/IMG_20190331_144024.jpg",
"BioDescription": "xyz",
"date_of_birth": "1996-06-01",
"gender": "M",
"account_type": "Private",
"user": 27
},
"last_login": null,
"is_superuser": false,
"is_staff": false,
"is_active": true,
"date_joined": "2020-04-28T11:09:27.691478Z"
},
"comment_usr": [
"xyz",
26,
"Cool Pic"
],
"like_by_you": true
},
{
"id": 13,
"file": "http://127.0.0.1:8000/media/user_30/post/IMG_20190402_102248.jpg",
"post_info": "#Awesome",
"post_time_stamp": "2020-05-10T10:20:22Z",
"total_comment": 8,
"user": {
"id": 30,
"username": "xyz",
"email": "xyz#gmail.com",
"status": false,
"profile": {
"id": 27,
"full_name": "XYZ",
"mobile": 123,
"background_picture": null,
"profile_picture": "http://127.0.0.1:8000/media/user_30/profile/demo.jpg",
"BioDescription": null,
"date_of_birth": null,
"gender": "F",
"account_type": "Private",
"user": 30
},
"last_login": null,
"is_superuser": false,
"is_staff": false,
"is_active": true,
"date_joined": "2020-04-28T11:13:58.030941Z"
},
"like_by_you": true
}
]
}
The pagination hit the database with Count() method, to paginating the result.
And, in every page hit the database by slicing that is more efficient than
using a queryset with all() method and, hit the database with Iteration, which load all the results.
filter() or all() methods don't hit the database. See this to check when a QuerySet is evaluated.
I have 4 models Category, Vendor, Location, Product. Vendor fall under the Category model (vendor is a foreign key to category). The remaining models are under Vendor (Location, Product)
ProductSerializer and LocationSerializer are nested to VendorSerializer, and VendorSerializer is nested to CategorySerializer.
class ProductSerializer(WritableNestedModelSerializer):
class Meta:
model = Product
fields = ['id', 'item_name', 'price']
read_only_fields = ['id']
class LocationSerializer(WritableNestedModelSerializer):
class Meta:
model = Location
fields = ['place']
class VendorSerializer(WritableNestedModelSerializer):
vendor_location = LocationSerializer()
product = ProductSerializer(many=True)
class Meta:
model = Vendor
fields = ['vendor_name','vendor_location','product']
read_only_fields = ['id']
class CategorySerializer(WritableNestedModelSerializer):
vendor = VendorSerializer(many=True)
class Meta:
model = Category
fields = ['id', 'category_name', 'tittle', 'vendor']
read_only_fields = ['id']
# View
class ProductView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None, *args, **kwargs):
products = Category.objects.all()
serializer = CategorySerializer(products, many=True, context={'request': request})
return Response({'response': 'ok', 'result': serializer.data})
# Output
{
"response": "ok",
"result": [
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 1,
"item_name": "test_1",
"price": 3200,
},
{
"id": 2,
"item_name": "test_2",
"price": 2010,
}
]
}
]
}
]
}
# Expected output
{
"response": "ok",
"result": [
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 1,
"item_name": "test_1",
"price": 3200,
}
]
}
]
},
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 2,
"item_name": "test_2",
"price": 2010,
}
]
}
]
}
]
}
In my output, two products are listed. There may be more than two. I only need one product under the product. All products must be printed in the same structure as I mentioned in expected output. How do I do this? Is it possible? Can someone help me do this?
You can modify this line:
# old:
products = Category.objects.all() # definately these are not products
# new:
products = Product.objects.values_list('id', flat=True) # get all products ids
categories = Category.objects.filter(vendor__product__in=products)
And send categories to CategorySerializer, thought this is still not what you want, as every duplicated category will hold information about all products (not only one).
Where I would go from this point? I'd create method get_product in VendorSerializer and somehow save information what Category/Vendor are we in right now and if we have already added a Product for this Category - I'd skip adding next.
PS. I still don't get why you need this format though.
I have a ViewSet which outputs a set of results:
{
"count": 19355,
"next": null,
"previous": null,
"results": [
{
"duration": 5,
...
},
{
"duration": 5,
...
},
...
]
}
I would like to aggregate the totals of the duration of the results, right in that handy little top area next to "count". I know how to do this in a queryset, using annotate and sum, but I don't see a way to get it into the ViewSet output.
Desired output for this data set would be:
{
"count": 19355,
"total_duration": 10,
"next": null,
"previous": null,
"results": [
{
"duration": 5,
...
},
{
"duration": 5,
...
},
...
]
}
I appreciate the help!
I would suggest implementing this using a dedicated Pagination class.
class PaginationWithAggregates(pagination.LimitOffsetPagination):
def paginate_queryset(self, queryset, request, view=None):
self.total_duration = queryset.aggregate(total_duration=Sum('duration'))['total_duration']
return super(PaginationWithAggregates, self).paginate_queryset(queryset, request, view)
def get_paginated_response(self, data):
paginated_response = super(PaginationWithAggregates, self).get_paginated_response(data)
paginated_response.data['total_duration'] = self.total_duration
return paginated_response
Don't forget to declare this pagination class on your GenericView.
I have a rest serializer and i am getting this output(actual data in thousands). I am trying to filter this data such that it displays only the json where a condition is met. (in my case, student.student_id = 29722):
[
{
"student": {
"student_id": 29722,
"first_name": "Michaella",
"middle_name": "Helene",
"last_name": "Bonose",
"email": "",
"phone": null,
"cell_phone": null
},
"credits_completed": null,
"academic_program_gpa": null,
"primary_program": true,
"academic_program": {
"id": 595,
"acad_program_category": {
"id": 1,
"program_type": {
"id": 1,
"program_category_type": "Academic"
},
"title": "Associate in Arts"
},
"acad_program_type": {
"id": 2,
"program_type": "Associate Degree"
},
"acad_program_code": "AA.ARTS",
"program_title": "Associate in Arts Degree",
"required_credits": 60,
"min_gpa": 2.0,
"description": ""
}
},
{
"student": {
"student_id": 29722,
"first_name": "Michaella",
"middle_name": "Helene",
"last_name": "Bonose",
"email": "",
"phone": null,
"cell_phone": null
},
"credits_completed": null,
"academic_program_gpa": null,
"primary_program": true,
"academic_program": {
"id": 596,
"acad_program_category": {
"id": 2,
"program_type": {
"id": 1,
"program_category_type": "Academic"
},
"title": "Associate in Sciences"
},
"acad_program_type": {
"id": 2,
"program_type": "Associate Degree"
},
"acad_program_code": "AS.SCIENCE",
"program_title": "Associate in Sciences Degree",
"required_credits": 60,
"min_gpa": 2.0,
"description": ""
}
}, .......
Here is my APIView for this:
class StudentAcademicProgramList(APIView):
def get(self, request, format=None):
student_academic_program = Student_academic_program.objects.all()
serialized_Student_academic_program = StudentAcademicProgramSerializer(student_academic_program, many=True)
return Response(serialized_Student_academic_program.data)
class StudentAcademicProgramDetail(APIView):
def get_objects(self, pk):
try:
return Student_academic_program.object.get(pk=pk)
except Student_academic_program.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
student_academic_program = self.get_object(pk)
serialized_Student_academic_program = StudentAcademicProgramSerializer(student_academic_program)
return Response(serialized_Student_academic_program.data)
Hoe do i filter this such that it only displays the values where student.student_id = 29722 ?
Do you mean to filter StudentAcademicProgramList?
class StudentAcademicProgramList(APIView):
def get(self, request, format=None):
# This should be populated however you need it to be.
student_id = 29722
student_academic_program = Student_academic_program.objects.filter(student_id=student_id)
serialized_Student_academic_program = StudentAcademicProgramSerializer(student_academic_program, many=True)
return Response(serialized_Student_academic_program.data)
I have two models like this:
class CompanyResource(ModelResource):
class Meta:
queryset = Company.objects.all()
fields = ['title', 'latitude', 'longitude']
resource_name = 'company'
filtering = {
'latitude': ALL,
'longitude': ALL
}
class EventResource(ModelResource):
company = fields.ToOneField(CompanyResource, 'company', full=True)
class Meta:
fields = ['title', 'company']
queryset = Event.objects.all()
resource_name = 'event'
filtering = {
'company': ALL_WITH_RELATIONS
}
Then I try to access /api/v1/event/?format=json&company_latitude__within=2,3 or /api/v1/event/?format=json&company_latitude__lt=1 it isn't filtered on latitude:
{
"meta": {
"limit": 20,
"next": "/api/v1/event/?offset=20&limit=20&format=json",
"offset": 0,
"previous": null,
"total_count": 329
},
"objects": [
{
"company": {
"latitude": "1.30521100000000",
"longitude": "103.81116299999996",
"resource_uri": ""
},
"resource_uri": "/api/v1/event/16/",
"title": "50% off at Infusion#Dempsey, $50 for $100 worth of Fine Dining"
}
]
}
How can I make this work?
Oh it's because of two things. I can't do field__within in Django (why did I think that?) and it should've been /api/v1/event/?format=json&company__latitude__lt=2.