Django RestFramework - convert list to dict - django

I'm translating an API in Java to DRF and the consumption will be in a data.py
Using DRF API
ind = requests.get(base_url + "get_ind?ind_id={}".format(ind))
print(ind.json())
[{ "id": 1, "ind_id": 1, "co_ind": "Some String", "no_ind": "Some String", "ds_ind": "Some String", "ds_not_ind": "", "uni_id": 1, "per_id": [ { "id": 7, "no_per": "Some String", "tip_var": "", "co_per": "Some String", "no_cat": "", "per_id": 7, "uni_id": 1 }, { "id": 9, "no_per": "Some String", "tip_var": "", "co_per": "Some String", "no_cat": "", "per_id": 9, "uni_id": 1 }, ], "co_mod": "Some String" }]
I want:
Using Java API
ind = requests.get(base_url + "get_ind?ind_id={}".format(ind))
print(ind.json())
{ "id": 1, "ind_id": 1, "co_ind": "A", "no_ind": "DOMÍCILIOS QUE POSSUEM EQUIPAMENTO TIC", "ds_ind": "Total de domicílios", "ds_not_ind": "", "uni_id": 1, "per_id": [ { "id": 7, "no_per": "Proporção de domicílios que possuem equipamentos TIC", "tip_var": "", "co_per": "DIC_TV", "no_cat": "", "per_id": 7, "uni_id": 1 }, { "id": 9, "no_per": "Proporção de domicílios que possuem equipamentos TIC", "tip_var": "", "co_per": "DIC_RADIO", "no_cat": "", "per_id": 9, "uni_id": 1 }, ], "co_mod": "A" }
This is the view.py:
class GetIndFilter(SearchFilter):
def filter_queryset(self, request, queryset, view):
queryset = super().filter_queryset(request, queryset, view)
ind_id = request.GET.get('ind_id')
if(ind_id != ''):
result = Inds.objects.filter(ind_id = ind_id)
return result
class GetIndViewSet(viewsets.ModelViewSet):
queryset = Inds.objects.all()
serializer_class = IndsSerializer
filter_backends = [GetIndFilter]
filterset_fields = ['ind_id']

def toDict(list):
dict = {}
for item in list:
dict.update(item)
return dict
ind = toDict(ind.json())

Related

Serialize ManyToManyField with foreign key of nested

I need to serialize attributes of an item related from many to many, but grouped by each type of attribute.
Models
from django.db import models
class AtributoTipo(models.Model):
nombre = models.CharField(max_length=40)
slug = models.SlugField(max_length=40, unique=True)
class Atributo(models.Model):
tipo = models.ForeignKey(AtributoTipo, on_delete=models.CASCADE)
nombre = models.CharField(max_length=40)
slug = models.SlugField(max_length=40)
class Articulo(models.Model):
codigo = models.CharField(max_length=18, unique=True, db_index=True)
nombre = models.CharField(max_length=255)
atributos = models.ManyToManyField(Atributo, related_name="articulos")
Normal DRF serializers:
from rest_framework import serializers
class AtributoTipoSerializer(serializers.ModelSerializer):
class Meta:
model = AtributoTipo
fields = ["__all__"]
class AtributoSerializer(serializers.ModelSerializer):
tipo_slug = serializers.ReadOnlyField(source="tipo.slug")
tipo_nombre = serializers.ReadOnlyField(source="tipo.nombre")
class Meta:
model = Atributo
fields = ["__all__"]
class ArticuloSerializer(serializers.ModelSerializer):
atributos = AtributoSerializer(many=True, read_only=True) # the dude
class Meta:
model = Articulo
fields = ["__all__"]
This is the result with serializers without any weird method:
{
"id": 44906,
"codigo": "DE0058751",
"atributos": [
{
"id": 15107,
"tipo": 76,
"tipo_slug": "talla",
"tipo_nombre": "Talla",
"nombre": "39",
"slug": "39"
},
{
"id": 43454,
"tipo": 76,
"tipo_slug": "talla",
"tipo_nombre": "Talla",
"nombre": "40",
"slug": "40"
},
{
"id": 23234,
"tipo": 15,
"tipo_slug": "color",
"tipo_nombre": "Color",
"nombre": "Rojo",
"slug": "rojo"
},
{
"id": 12408,
"tipo": 15,
"tipo_slug": "color",
"tipo_nombre": "Color",
"nombre": "Verde",
"slug": "verde"
}
]
}
Desired result:
{
"id": 44906,
"codigo": "DE0058751",
"atributos": [
{
"id": 76,
"slug": "talla",
"nombre": "Talla",
"atributos": [
{
"id": 15107,
"tipo": 76,
"nombre": "39",
"slug": "39"
},
{
"id": 12408,
"tipo": 76,
"nombre": "40",
"slug": "40"
}
]
},
{
"id": 15,
"slug": "color",
"nombre": "Color",
"atributos": [
{
"id": 34234,
"tipo": 15,
"nombre": "Rojo",
"slug": "rojo"
},
{
"id": 2323,
"tipo": 15,
"nombre": "Verde",
"slug": "verde"
}
]
}
]
}
The problem is that you lose the context of the article.
I tried itertools groupby, but I think there must be another logic with DRF.
You can redefine to_representation of ListSerializer and use ListSerializer as a field of your ArticuloSerializer:
class GroupedAttributosSerializer(serializers.ListSerializer):
def to_representation(self, data):
data = super().to_representation(data)
tipo_slug_to_objects = defaultdict(list)
for d in data:
tipo_slug_to_objects[d["tipo_slug"]].append(d)
result = []
for tipo_slug, objects in tipo_slug_to_objects.items():
result.append(
{
"id": objects[0]["tipo"],
"slug": tipo_slug,
"nombre": objects[0]["tipo_nombre"],
"attributos": [
{"id": attribute["id"],
"tipo": attribute["tipo"],
"nombre": attribute["nombre"],
"slug": attribute["slug"]}
for attribute in objects
]
}
)
return result
class ArticuloSerializer(serializers.ModelSerializer):
atributos = GroupedAttributosSerializer(child=AtributoSerializer(), read_only=True, default=[])
class Meta:
model = Articulo
fields = ["__all__"]

cannot be able to produce proper tree structured output using self referencing using django rest framework

I have below Comment model and i want to implement the comment-reply functionality and in turn send the response as JSON using django rest framework. But in the reponse im getting the records even for 'parent not equal to None' in parent node. I want all the records whose having parent value should be displayed as only children.
models.py:
'''
class Comment(models.Model):
name = models.TextField('comment')
expression = models.ForeignKey('Expression', on_delete=models.CASCADE, related_name='expression')
datecreated = models.DateTimeField('date created', auto_now_add=True)
dateupdated = models.DateTimeField('date updated', auto_now=True)
parent = models.ForeignKey('self', on_delete=models.PROTECT, null=True, blank=True, related_name='replied_to')
class META:
verbose_name_plural = "comments"
ordering = ['-datecreated']
def __str__(self):
return '{}'.format(self.name)
'''
views.py:
'''
class CommentViewSet(viewsets.ModelViewSet):
comments = Comment.objects.all()
queryset = comments
serializer_class = CommentSerializer
#list_route()
def roots(self, request, *args, **kwargs):
slug = kwargs.get('slug')
expression = Expression.objects.get(author=request.user, slug=slug)
queryset = expression.expression.filter(parent=None)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
'''
serializers.py:
'''
class RecursiveSerializer(serializers.Serializer):
def to_representation(self, value):
serializer = self.parent.parent.__class__(value, context=self.context)
# data = serializer.data.filter(parent!=0)
return serializer.data
class CommentSerializer(serializers.ModelSerializer):
'''
Ref: http://voorloopnul.com/blog/representing-hierarchical-data-with-django-rest-framework/
'''
expression = serializers.CharField(required=False, read_only=True)
replied_to = RecursiveSerializer(many=True, read_only=True)
class Meta:
model = Comment
read_only_fields = ('id','datecreated', 'dateupdated',)
fields = ('id','name','expression','datecreated','dateupdated','parent','replied_to')
'''
Actual Result:
'''
[
{
"id": 5,
"name": "my new comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:23.174877+05:30",
"dateupdated": "2019-04-19T15:38:23.174877+05:30",
"parent": null,
"replied_to": [
{
"id": 6,
"name": "my sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:55.061534+05:30",
"dateupdated": "2019-04-23T23:56:01.846904+05:30",
"parent": 5,
"replied_to": [
{
"id": 7,
"name": "my sub sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:42:46.981884+05:30",
"dateupdated": "2019-04-23T23:56:38.131256+05:30",
"parent": 6,
"replied_to": []
}
]
}
]
},
{
"id": 6,
"name": "my sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:55.061534+05:30",
"dateupdated": "2019-04-23T23:56:01.846904+05:30",
"parent": 5,
"replied_to": [
{
"id": 7,
"name": "my sub sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:42:46.981884+05:30",
"dateupdated": "2019-04-23T23:56:38.131256+05:30",
"parent": 6,
"replied_to": []
}
]
},
{
"id": 7,
"name": "my sub sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:42:46.981884+05:30",
"dateupdated": "2019-04-23T23:56:38.131256+05:30",
"parent": 6,
"replied_to": []
}
]
'''
Expected Ouput:
'''
[
{
"id": 1,
"name": "new comment1",
"expression": "My new expression1",
"datecreated": "2019-04-07T17:52:52.784429+05:30",
"dateupdated": "2019-04-07T17:52:52.784429+05:30",
"parent": null,
"replied_to": []
},
{
"id": 5,
"name": "my new comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:23.174877+05:30",
"dateupdated": "2019-04-19T15:38:23.174877+05:30",
"parent": null,
"replied_to": [
{
"id": 6,
"name": "my sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:55.061534+05:30",
"dateupdated": "2019-04-23T23:56:01.846904+05:30",
"parent": 5,
"replied_to": [
{
"id": 7,
"name": "my sub sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:42:46.981884+05:30",
"dateupdated": "2019-04-23T23:56:38.131256+05:30",
"parent": 6,
"replied_to": []
}
]
}
]
},
]
'''
Changed the views as below:
'''
class CommentViewSet(viewsets.ModelViewSet):
queryset = Comment.objects.all()
serializer_class = CommentSerializer
def list(self, request, **kwargs):
slug = kwargs.get('slug')
try:
expression = Expression.objects.get(author=request.user, slug=slug)
queryset = expression.expression.filter(parent=None)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
except Expression.DoesNotExist as err:
return Response(data={'error':'Expression matching query does not exist.'}, status=status.HTTP_404_NOT_FOUND)
'''
Now im getting desired hierarchy as below:
'''
[
{
"id": 5,
"name": "my new comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:23.174877+05:30",
"dateupdated": "2019-04-19T15:38:23.174877+05:30",
"parent": null,
"replied_to": [
{
"id": 6,
"name": "my sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:38:55.061534+05:30",
"dateupdated": "2019-04-23T23:56:01.846904+05:30",
"parent": 5,
"replied_to": [
{
"id": 7,
"name": "my sub sub comment",
"expression": "My new expression",
"datecreated": "2019-04-19T15:42:46.981884+05:30",
"dateupdated": "2019-04-23T23:56:38.131256+05:30",
"parent": 6,
"replied_to": []
}
]
}
]
},
{
"id": 8,
"name": "new test user comment",
"expression": "My new expression",
"datecreated": "2019-04-24T00:43:57.939082+05:30",
"dateupdated": "2019-04-24T00:43:57.939082+05:30",
"parent": null,
"replied_to": []
}
]
'''

Filtering list of elements based on a model #property in a ViewSet - Django Rest Framework

Below is a data structure that can be accessible trough an endpoint built with Django Rest Framework:
"sites": [{
"id": 1,
"configs": [
{
"id": 1,
"subconfigs": [
{
"id": 1,
"name": "subconfig_1",
"macro_subconfigs": [1, 2]
"flag": true
},
{
"id": 2,
"name": "subconfig_2",
"macro_subconfigs": [1]
"flag": false
},
{
"id": 3,
"name": "subconfig_3",
"macro_subconfigs": [2]
"flag": false
},
],
"macro_subconfigs": [
{
"id": 1,
"flag": true,
"subconfigs": [
{
"id": 1,
"name": "subconfig_1",
"macro_subconfigs": [1, 2]
"flag": true
},
{
"id": 2,
"name": "subconfig_2",
"macro_subconfigs": [1]
"flag": false
},
],
"name": "macro_subconfig_1"
},
{
"id": 2,
"flag": false,
"subconfigs": [
{
"id": 1,
"name": "subconfig_1",
"macro_subconfigs": [1, 2]
"flag": true
},
{
"id": 3,
"name": "subconfig_3",
"macro_subconfigs": [2]
"flag": false
},
],
"name": "macro_subconfig_2"
},
]
}
]
}]
My models are the followings:
Config
class Config(TimeStampedModel):
site = models.ForeignKey("site.Site", related_name="configs")
#property
def macro_subconfigs(self):
try:
return MacroSubConfig.objects.filter(subconfigs__config__pk=self.pk).distinct()
except MacroSubConfig.DoesNotExist:
return tuple()
SubConfig
class SubConfig(TimeStampedModel):
name = models.CharField(max_length=200)
config = models.ForeignKey(
"Config", related_name="subconfigs", on_delete=models.CASCADE
)
flag = models.BooleanField(default=True)
MacroSubConfig
class MacroSubConfig(TimeStampedModel):
name = models.CharField(max_length=100)
subconfigs = models.ManyToManyField(SubConfig, related_name="macro_subconfigs")
flag = models.BooleanField(default=True)
And my serializers:
class SiteConfigSerializer(serializers.HyperlinkedModelSerializer):
configs = ConfigSerializer(many=True)
class Meta:
model = Site
fields = ("name", "configs")
class SubConfigSerializer(serializers.ModelSerializer):
class Meta:
model = SubConfig
fields = ("name")
class ConfigSerializer(serializers.ModelSerializer):
subconfigs = SubConfigSerializer(many=True)
macro_subconfigs = MacroSubConfigSerializer(many=True)
class Meta:
model = Config
fields = ("name", "subconfigs", "macro_subconfigs")
class MacroSubConfigSerializer(serializers.HyperlinkedModelSerializer):
subconfigs = serializers.PrimaryKeyRelatedField(
many=True, queryset=SubConfig.objects.all()
)
class Meta:
model = MacroSubConfig
fields = ["subconfigs", "name"]
In my SiteViewSet, I would like to filter macro_subconfigs in the macro_subconfigs's list which have flag: true. I already managed to do the same for subconfigs in the subconfigs's list.
The expected result is the following:
"sites": [{
"id": 1,
"configs": [
{
"id": 1,
"subconfigs": [
{
"id": 1,
"name": "subconfig_1",
"macro_subconfigs": [1, 2]
"flag": true
}
],
"macro_subconfigs": [
{
"id": 1,
"flag": true,
"subconfigs": [
{
"id": 1,
"name": "subconfig_1",
"macro_subconfigs": [1, 2]
"flag": true
},
{
"id": 2,
"name": "subconfig_2",
"macro_subconfigs": [1]
"flag": false
},
],
"name": "macro_subconfig_1"
}
]
}
]
}]
How do you filter elements from a list in the Config object, in the SiteViewSet?
Feel free to ask me more precisions if needed. Thanks
More infos
What I have tried in my ViewSet
class SiteConfigViewSet(PublicViewSet):
serializer_class = serializers.SiteConfigSerializer
def get_queryset(self):
subconfigs = Process.objects.filter(flag=True)
macro_subconfigs = MacroProcess.objects.filter(flag=True)
return permissions.get_allowed_sites(self.request).prefetch_related(
Prefetch("configs__subconfigs", queryset=subconfigs),
Prefetch("configs__subconfigs__macro_subconfigs", queryset=macro_subconfigs),
)

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,

Filtering rest framework serializer output

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)