Filtering rest framework serializer output - django

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)

Related

How can i group by all data according to model in DRF?

Currently, I am working on a DFR project where can successfully get all data but i need some modify with the json data.
Here Is the code
class PermissionSerializers(serializers.ModelSerializer):
class Meta:
model = Permission
fields = ['id', 'name', 'codename']
def to_representation(self, instance):
return {
'model': instance.content_type.name,
'data' :{
'id': instance.id,
'name': instance.name,
'codename': instance.codename,
}
}
And i get this JSON format,
{
"next": "http://127.0.0.1:8000/en/ga/api-version/common/admin/permissions/?page=4",
"previous": "http://127.0.0.1:8000/en/ga/api-version/common/admin/permissions/?page=2",
"total": 33,
"page": 3,
"page_size": 10,
"results": [
{
"model": "user",
"data": {
"id": 25,
"name": "Can add user",
"codename": "add_user"
}
},
{
"model": "user",
"data": {
"id": 29,
"name": "Admistrative Access",
"codename": "admin_access"
}
},
But I want to modify with something like this which has model name on top and then all available data inside a dictionary:
{
"model": "user",
"data": {
"id": 26,
"name": "Can change user",
"codename": "change_user"
},
{
"id": 25,
"name": "Can add user",
"codename": "add_user"
},
},
You get something like this because you have pagination in your API, if you don't want it just disable pagination.
I came up with this solution:
def list(self, request):
_models_list = [
'organization','user','group', 'logentry', 'organizationtype',
'keyword', 'productsupport','feedbacksupport','twittercredential']
models = ContentType.objects.filter(model__in = _models_list)
model_dict = {
'model': '',
'data':''
}
results = []
for model in models:
_permissions = []
access = ' Access'
if model.model == 'group':
model_dict['model'] = 'Role'+ access
elif model.model == 'organizationtype':
model_dict['model'] = 'Organization Type'+ access
elif model.model == 'productsupport':
model_dict['model'] = 'Product'+ access
elif model.model == 'feedbacksupport':
model_dict['model'] = 'Feedback'+ access
else:
model_dict['model'] = model.model.capitalize()+ access
permissions = Permission.objects.filter(content_type = model)
for premission in permissions:
_permissions.append(premission)
serializer = PermissionSerializers(_permissions, many=True)
data = serializer.data
model_dict['data'] = data
results.append(model_dict.copy())
return Response(results)

How to add additional fields, like count of objects to ModelSerializer with many=True

I don't know how to add additional fields to my ModelSerializer, which accepts many=True. Here is all my code:
ViewSet:
def list(self, request, *args, **kwargs):
contracts = self.request.user.all_contracts
serializer = ContractGetSerializer(contracts, many=True, context={'request': request}, )
return Response({"results": serializer.data}, status=status.HTTP_200_OK)
ContractGetSerializer serializer. It also has inner Many=True fields
class ContractGetSerializer(serializers.ModelSerializer):
files = FileModelSerializer(many=True)
is_author = serializers.SerializerMethodField('is_author_method')
contract_signing_status = serializers.SerializerMethodField('get_recipient_signing_status')
def is_author_method(self, foo):
return foo.owner.id == self.context['request'].user.id
class Meta:
model = Contract
fields = ['id', 'is_author', 'title','contract_signing_status','files', ]
Now my ContractGetSerializer returns a ReturnList with all contracts. How can I add additional fields to that ReturnList and make it a dictionary?
I need for instance to return only 5 recent contracts (filtered by timestamp).
Also, I need to add total SIGNED contracts, and total PENDING contracts, counting all contracts data so that my frontend would not need to do this.
My current JSON:
{
"results": [
{
"id": 178,
"is_author": true,
"title": "ahhzhzh",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE"
}
]
},
{
"id": 179,
"is_author": true,
"title": "dhhdhd",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE"
}
]
},
]
}
My desired JSON:
{
"recents_count": 5,
"signed_count": 10,
"results": [
{
"id": 178,
"is_author": true,
"title": "ahhzhzh",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE"
}
]
},
{
"id": 179,
"is_author": true,
"title": "dhhdhd",
"message_to_all_recipients": null,
"contract_signing_status": "WAITING_FOR_ME",
"contract_signing_type": "SIMPLE",
"contract_signing_date": {
"start_date": "2010-09-04T14:15:22Z",
"end_date": "2010-09-04T14:15:22Z"
},
"recipients": [
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "ADMIN"
},
{
"message": null,
"recipient_signing_status": "NOT_SIGNED",
"recipient_review_status": "NOT_REQUIRED",
"recipient_action": "SIGN",
"role": "BASE"
}
]
},
]
}
There are multiple ways to do so, but I think doing this in serializers is better.
I will do something like this:
at view
def list(self, request, *args, **kwargs):
serializer = ContractResultSerializer(self.request.user, context={'request': request}, )
return Response(serializer.data, status=status.HTTP_200_OK)
at serializers
class ContractResultSerializer(serializers.Serializers):
recents_count = serializers.SerializerMethodField()
signed_count = serializers.SerializerMethodField()
results = serializers.SerializerMethodField()
def get_recents_count(self, obj):
# I don't know how is your model looks like to write the query to get the recent count
# but I think it will be something like this
return obj.contracts.filter(your recent condition).count()
def get_signed_count(self, obj):
# is the same as get_recents_count()
def get_results(self, obj):
return ContractGetSerializer(obj.all_contracts, many=True, context={'request': self.context['request']}).data
class ContractGetSerializer(serializers.ModelSerializer):
files = FileModelSerializer(many=True)
is_author = serializers.SerializerMethodField('is_author_method')
contract_signing_status = serializers.SerializerMethodField('get_recipient_signing_status')
def is_author_method(self, foo):
return foo.owner.id == self.context['request'].user.id
class Meta:
model = Contract
fields = ['id', 'is_author', 'title','contract_signing_status','files', ]
You can also do the same if you like at your view instead of writing a new serializer
for ex:
def list(self, request, *args, **kwargs):
contracts = self.request.user.all_contracts
serializer = ContractGetSerializer(contracts, many=True, context={'request': request}, )
response ={
"recents_count": self.request.user.contracts.filter(your recent condition).count(),
"signed_count": self.request.user.contracts.filter(your recent condition).count(),
"results": serializer.data
}
return Response(response, status=status.HTTP_200_OK)

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 nest a serializer?

So I'm trying to create an /api/info url that return various data on my application. It pulls data from various models and puts it together in one response. I got the following:
class SessionInfo(generics.GenericAPIView):
def get(self, request, format=None):
token = Token.objects.get(user=self.request.user)
userprofile = UserProfile.objects.get(user=self.request.user)
is_admin = self.request.user.is_staff
is_primary_owner = userprofile.primary_owner
managers = userprofile.reports_to.all()
man = ["test manager 1", "test manager 2"]
pages = Page.objects.filter(published=True, show_in_menu=True)
pages_output = JSONRenderer().render(PageSerializer(pages).data)
content = {
'user': {
"username": str(self.request.user.username),
"first_name": str(self.request.user.first_name),
"last_name": str(self.request.user.last_name),
"is_admin": is_admin,
"is_primary_owner": is_primary_owner,
"api_token": token.key,
"timezone": 'blalala',
"managers": man,
},
'license': {
"plan" : "gold",
"expiry_date" : "lol",
},
'feature_flags': {
'billing_test': False,
},
'pages': { pages_output },
}
return Response(content)
However it doesn't properly serialize and render pages, making it an escaped string instead:
{
"feature_flags": {
"billing_test": false
},
"user": {
"username": "test#user.com",
"first_name": "Test",
"last_name": "User",
"is_admin": true,
"managers": [
"test manager 1",
"test manager 2"
],
"api_token": "08d1a5827da9a90e7746949ffd2e69e87c51b272",
"timezone": "blalala",
"is_primary_owner": false
},
"license": {
"expiry_date": "lol",
"plan": "gold"
},
"pages": [
"[{\"id\": 1, \"title\": \"Trololol\"}, {\"id\": 2, \"title\": \"NEW pages\"}]"
]
}
if I use directuly use pages_output = PageSerializer(pages) I get:
<webapp_api_v1.serializers.PageSerializer object at 0x10a0d8f90> is not JSON serializable
How can I make a serializer properly nest within my constructed response? Thanks!
Solved it with pages_output = PageSerializer(pages).data and changing 'pages': pages_output,

Django REST Meta data for M2M missing

On my json output I don't seem to get key value pairs on my m2m field attribute_answers. see the code below. How to I add in the attribute_answers fields?
json
{
"id": 20,
"name": "Jake",
"active": true,
"type": {
"id": 1,
"name": "Human",
"active": true,
"created": "2013-02-12T13:31:06Z",
"modified": null
},
"user": "jason",
"attribute_answers": [
1,
2
]
}
Serializer
class ProfileSerializer(serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field='username')
attribute_answers = serializers.PrimaryKeyRelatedField(many=True)
class Meta:
model = Profile
depth = 2
fields = ('id', 'name', 'active', 'type', 'user', 'attribute_answers')
def restore_object(self, attrs, instance=None):
"""
Create or update a new snippet instance.
"""
if instance:
# Update existing instance
instance.name = attrs.get('name', instance.name)
instance.active = attrs.get('active', instance.active)
instance.type = attrs.get('type', instance.type)
instance.attribute_answers = attrs.get('attribute_answers', instance.attribute_answers)
return instance
# Create new instance
return Profile(**attrs)
If I understand your question correctly, you want a Nested Relationship. In your ProfileSerializer, you'll want:
attribute_answers = AttributeAnswerSerializer(many=True)
This will display all the attributes of each associated attribute_answer model and give you something like:
{
"id": 20,
"name": "Jake",
"active": true,
"type": {
"id": 1,
"name": "Human",
"active": true,
"created": "2013-02-12T13:31:06Z",
"modified": null
},
"user": "jason",
"attribute_answers": [
{"id": 1, "foo": "bar"},
{"id": 2, "foo": "bar2"}
]
}