Aggregate totals of a ViewSet results in Django Rest Framework - django

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.

Related

Count before filter in django

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

what's the use if I am querying all the database before pagination in Django?

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.

How to use a field as a filter group?

Currently have a list of Records that have fields child (Child model has Parent) and date.
class Record(models.Model):
child = models.ForeignKey(Child)
date = DateField()
... other fields
I would like to generate a daily list of Records that are grouped at a date level.
i.e. Parent > 2020-06-06 > Child + Record other fields
Right now I've devised a way to brute force through all the records at the serializer level if I select from the Parent level.
records = serializers.SerializerMethodField()
def get_records(self, obj):
qs = Record.objects.filter(child__parent=obj)
dates_dict = defaultdict(list)
for row in qs.all():
date = row.date.strftime('%Y-%m-%d')
dates_dict[date].append(RecordSerializer(row).data)
return dates_dict
However, this messes with pagination as it creates a single record because there's only 1 Parent. I do not need the Parent data at all. What I would like is for the data to be paginated on the date level.
{
"id": 1,
"name": "Parent",
"reports": {
"2020-05-20": [
{
"child": {
"id": 1,
},
..other fields
},
{
"child": {
"id": 2,
},
..other fields
},
{
"child": {
"id": 3,
},
..other fields
},
]
}
}
How would I paginate this if I'm filtering on the Python level? I am trying to achieve this:
{
"count": 100,
"next": "NEXT",
"prev": "PREV",
"results": {
"2020-05-20": [
{
"child": {
"id": 1,
},
..other fields
},
{
"child": {
"id": 2,
},
..other fields
},
{
"child": {
"id": 3,
},
..other fields
},
]
}
}
Thank you

queryset filtering via a list of query values

A beginner django question...
Here's a JSON response...
"data": [
{
"type": "Subject",
"id": "0",
"attributes": {
"created": "2019-01-01T00:00:00Z",
"modified": "2019-01-01T00:00:00Z",
"subject_code": "A&H",
"subject_name": "AH",
"subject_short_name": "A & HUM"
},
"relationships": {
"organization": {
"data": {
"type": "Organization",
"id": "61"
}
},
"created_user": {
"data": null
},
"last_updated_user": {
"data": null
}
},
"links": {
"self": "http://localhost:8001/v1/subject_owner/0"
}
},
The above response is coming from a serializer
queryset = Subject.objects.all()
I have a query which is
http://localhost:8001/v1/subject_owner?owner_ids=62,63
So, how do we write a filtering condition for the owner_ids as a list? The response should have only the results where the owner_ids match organization_id. I have tried few:
queryset.filter(organization__in=[owner_id_list])
and
queryset.filter(organization=owner_id_list)
and obviously they don't work. Any help will be appreciated.
FYI, here's the model class...
class SubjectManager(models.Manager):
def get_by_natural_key(self, subject_code):
return self.get(subject_code=subject_code)
class Subject(get_subject_base_class(Organization)):
objects = SubjectManager()
def __str__(self):
return self.subject_code
def natural_key(self):
return (self.subject_code,)
You have to make something like that:
owner_id_list = [62, 63]
Subject.objects.filter(organization_id__in=owner_id_list)

alter the structure Tastypie uses in the list view

I have json list view that look like this:
{
"objects": [
{
"active": false,
"id": 4,
},
{
"active": false,
"id": 5,
}
]
}
I want to get rid of "objects" word, so that structure will look like this:
{
[
{
"active": false,
"id": 4,
},
{
"active": false,
"id": 5,
}
]
}
This link to docs has no clue in it
It's impossible. {} means dict. Dict needs key and value.
I guess You need
[
{
"active": false,
"id": 4,
},
{
"active": false,
"id": 5,
}
]
If yes, overwrite Resource.alter_list_data_to_serialize function:
def alter_list_data_to_serialize(self, request, data):
return data[self._meta.collection_name]
Paginator class need to be dict with field named Resouce._meta.collection_name.