Django - combining two models serializer into one JSON response - python

I have two models List and Card. I'm trying to combine these two and make a single JSON response
My List JSON response
[
{
"id": 1,
"name": "List of things to do"
},
{
"id": 2,
"name": "one more"
}
]
My Card JSON response
[
{
"id": 1,
"title": "My first scrum card",
"description": "list things todo here",
"story_points": null,
"business_value": null,
"list": 1
},
{
"id": 2,
"title": "File my taxes",
"description": "fill it before 1st of nov",
"story_points": null,
"business_value": null,
"list": 1
},
]
My serializers.py file
from rest_framework import serializers
from .models import List, Card
class CardSerializer(serializers.ModelSerializer):
class Meta:
model = Card
fields = '__all__'
class ListSerializer(serializers.ModelSerializer):
cards = CardSerializer(read_only=True, many=True)
class Meta:
model = List
fields ='__all__'
My api.py file
from rest_framework.viewsets import ModelViewSet
from .models import List, Card
from .serializers import ListSerializer, CardSerializer
class ListViewSet(ModelViewSet):
queryset = List.objects.all()
serializer_class = ListSerializer
class CardViewSet(ModelViewSet):
queryset = Card.objects.all()
serializer_class = CardSerializer
My models.py
from django.db import models
class List(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return "List : {}".format(self.name)
class Card(models.Model): # to create card table
title = models.CharField(max_length=100)
description = models.TextField(blank=True)
list = models.ForeignKey(List, related_name = "card"
,on_delete=models.PROTECT) # creating a foriegn key for storing list
story_points = models.IntegerField(null=True, blank = True)
business_value = models.IntegerField(null=True, blank = True)
def __str__(self):
return "Card : {}".format(self.title)
How can I achieve something like below in My List JSON response ?
[
{
"id": 1,
"cards":[
{
"id": 1,
"title": "My first scrum card",
"description": "list things todo here",
"story_points": null,
"business_value": null,
"list": 1
}],
"name": "List of things to do"
},
{
"id": 2,
"cards":[
{
"id": 2,
"title": "File my taxes",
"description": "fill it before 1st of nov",
"story_points": null,
"business_value": null,
"list": 1
}],
"name": "one more"
},
]
I have tried to do it but I was unable to implement it. So I posted it here.
Heading
Many thanks.

You can also use SerializerMethodeField https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield.
class ListSerializer(serializers.ModelSerializer):
cards = serializers.SerializerMethodField()
class Meta:
model = List
fields = '__all__'
def get_cards(self, obj):
data = CardSerializer(obj.card.all(), many=True).data
return data

change the list related_name to cards and ListViewSet will do what you want
class Card(models.Model): # to create card table
title = models.CharField(max_length=100)
description = models.TextField(blank=True)
list = models.ForeignKey(List, related_name = "cards"
,on_delete=models.PROTECT)
...

Related

Nested JSON output for Primary and Foreign key Django Rest Framework

Iam using Django 3.2 with Restframework.
I have a Model as a for a Primary key named Tag and a Model connected as a foreign key named TagItem.
I tried to get a nested JSON output for it but its not working as expected.
Models.py
class Tags(models.Model):
tagId = models.CharField(primary_key=True, max_length=100,default=1)
section = models.CharField(max_length=100)
class TagItem(models.Model):
tagId= models.ForeignKey(Tags, on_delete=models.CASCADE,default=1)
select = models.BooleanField(default=False)
name = models.CharField(max_length=50)
views.py
def get_tag_details(request):
if request.method == 'GET':
tag = Tags.objects.all()
tagitem = TagItem.objects.all()
TagSerializeobj = TagsSerializer(tag,many=True)
TagItemSerializeobj = TagItemSerializer(tagitem, many=True)
result = {}
result['tag'] = TagSerializeobj.data
for item in TagItemSerializeobj:
if item.tagId == result['tag'].tagId:
result['tagItem'] = item
return Response(result)
Error: 'ListSerializer' object is not iterable
How to iterate of get items nested under related Tags only.
Required output
{
"id": 1,
"section": "crafts",
"items": [
{
"id": "10",
"select": false,
"name": "Wood"
},
{
"id": "11",
"select": false,
"name": "Clay"
}
]
},
{
"id": 2,
"section": "states",
"items": [
{
"id": "20",
"select": false,
"name": "Andhra Pradesh"
},
{
"id": "21",
"select": false,
"name": "Arunachal Pradesh"
},
]
}
You don't need to do all those processing in your views. ModelSerializer can do it for you, so you can just define a model serializer for TagItem that is nested on a model serializer for Tag so something like:
class TagItemModelSerializer(serializers.ModelSerializer):
class Meta:
model = TagItem
fields = '__all__'
class TagModelSerializer(serializers.ModelSerializer):
items = serializers.SerializerMethodField()
class Meta:
model = Tag
fields = '__all__'
def get_items(self, obj):
return TagItemModelSerializer(obj.tag_items.all(), many=True)
And in your views:
serializer = TagModelSerializer(Tags.objects.all(), many=True)
return Response(serializer.data)
I get unexpected keyword error when i tried to assign

Django Rest Framework: Derived model serializer fields

I'm working on building a tree-like hierarchical database system using Django Rest Framework and django-polymorphic-tree. I have two models- BaseTreeNode and DescriptionNode (the later one is derived from BaseTreeNode). Specifically, here's my models.py:
class BaseTreeNode(PolymorphicMPTTModel):
parent = PolymorphicTreeForeignKey('self', blank=True, null=True, related_name='children', verbose_name=_('parent'))
title = models.CharField(_("Title"), max_length=200)
def __str__(self):
return "{}>{}".format(self.parent, self.title)
class Meta(PolymorphicMPTTModel.Meta):
verbose_name = _("Tree node")
verbose_name_plural = _("Tree nodes")
# Derived model for the tree node:
class DescriptionNode(BaseTreeNode):
description = models.CharField(_("Description"), max_length=200)
class Meta:
verbose_name = _("Description node")
verbose_name_plural = _("Description nodes")
So, each title field (belonging to BaseTreeNode) has an associated description field (belonging to DescriptionNode) with it.
Now, all I want to have is a JSON that returns a nested representation of my entire tree.
For now, I have only defined a simple serializer with a recursive field.
My serializers.py
from rest_framework_recursive.fields import RecursiveField
class DescriptionNodeSerializer(serializers.ModelSerializer):
class Meta:
model = DescriptionNode
fields = ('description',)
class BaseTreeNodeSerializer(serializers.ModelSerializer):
subcategories = serializers.ListSerializer(source="children",child=RecursiveField())
class Meta:
model = BaseTreeNode
fields = ('id', 'title', 'subcategories')
Which gives me (for BaseTreeNodeSerializer only):
[
{
"id": 1,
"title": "Apple",
"subcategories": [
{
"id": 2,
"title": "Contact Person",
"subcategories": []
},
{
"id": 3,
"title": "Sales Stage",
"subcategories": [
{
"id": 4,
"title": "Suspecting",
"subcategories": [
{
"id": 5,
"title": "Contact verification",
"subcategories": []
}
]
},
{
"id": 6,
"title": "Prospecting",
"subcategories": [
{
"id": 7,
"title": "Client Detail",
"subcategories": []
}
]
}
]
},
{
"id": 9,
"title": "Medium",
"subcategories": [
{
"id": 10,
"title": "Status",
"subcategories": []
}
]
},
{
"id": 13,
"title": "Remainder",
"subcategories": []
}
]
}
]
My question is, how can I include the description field (from the derived model) which is associated with every single title field (from the BaseTreeNode model) in the hierarchy?
Something like:
... {
"id": 5,
"title": "Contact verification",
"description": "Verified"
"subcategories": []
} ...
The Corresponding Model would be as follows:
class DescriptionNode(BaseTreeNode):
basetreenode = models.OneToOneField(BaseTreeNode, related_name="base_tree")
description = models.CharField(_("Description"), max_length=200)
class Meta:
verbose_name = _("Description node")
verbose_name_plural = _("Description nodes")
Serializer would be as follows:
from rest_framework_recursive.fields import RecursiveField
class BaseTreeNodeSerializer(serializers.ModelSerializer):
description = serializers.SerializerMethodField()
subcategories = serializers.ListSerializer(source="children",child=RecursiveField())
class Meta:
model = BaseTreeNode
fields = ('id', 'title', 'description', 'subcategories')
def get_description(self, obj):
return obj.base_tree.description #base_tree is related name of basetreenode field

Django REST API populate only selected fields from Many to many field

I have a working API in my project that look something like this :
{
"id": 1,
"project_name": "Project A",
"user": [
{
"id": 3,
"employee_id": "001",
"official_name": "RAY PAlMER",
"nick_name": "RAY",
"date_of_birth": "1965-08-25",
"gender": "1",
"race": "CAUCASIAN",
"food_pref": "Vegetarian",
},
{
"id": 3,
"employee_id": "002",
"official_name": "LAIRA OMOTO",
"nick_name": "LAIRA",
"date_of_birth": "1990-01-15",
"gender": "2",
"race": "WHITE",
"food_pref": "Any",
}
]
}
The user field is a foreign key field and its populating everything from its source model called Employee. My question is how can I populate the user many to many field with only several field that I wanted to get from the Employee Model. For example I just want to populate only a user id, official name, and gender, therefore the output should be something like this
{
"id": 1,
"project_name": "Project A",
"user": [
{
"id": 3,
"official_name": "RAY PAlMER",
"gender": "1",
},
{
"id": 4,
"official_name": "LAIRA",
"gender": "2",
}
]
}
Below is my source code :
Project Model :
class Project(models.Model):
user = models.ManyToManyField(Employee, blank=True)
Employee Model :
class Employee(models.Model):
official_name = models.CharField(max_length=200, null=True, blank=True)
gender_choice = (
('male', 'Male'),
('female', 'Female')
)
gender = models.CharField(max_length=10, choices=gender_choice, null=True,
blank=True)
Serializer :
class MarketingReportSerializer(serializers.ModelSerializer):
class Meta:
model = Project
fields = ('id', 'project_name','user')
depth = 1
Any help is much appreciated thanks!
API :
class MarketingReportAPI(APIView):
def get(self, request):
all_projects = Project.objects.all()
project_serializer = MarketingReportSerializer(all_projects, many=True)
return Response(project_serializer.data)
Create EmployeeSerializer serializer.
class EmployeeSerializer(serializers.ModelSerializer):
class Meta:
model = Employee
fields = ('id', 'official_name', 'gender')
Now use it in your MarketingReportSerializer
class MarketingReportSerializer(serializers.ModelSerializer):
user = EmployeeSerializer(many=True)
class Meta:
model = Project
fields = ('id', 'project_name', 'user')
And then you can use MarketingReportSerializer in your view.

Django REST Framework nested serializer having no effect

I am attempting to set up a nested serializer in Django REST Framework, but after following the short guide in the documentation, http://www.django-rest-framework.org/api-guide/relations/#nested-relationships, I have had no change in the serialized data.
models.py
class Franchise(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
class Item(models.Model):
id = models.AutoField(primary_key=True)
franchise = models.ForeignKey(Franchise, on_delete=None)
title = models.CharField(max_length=255)
Initial serializers.py
class ItemListSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = ('id', 'franchise', 'title')
class FranshiseDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Franchise
fields = ('id', 'name', 'items')
When I query ItemListSerializer with a query set I get back the expected:
[
{
"id": 1,
"franchise": 1,
"title": "Item 1",
},
{
"id": 2,
"franchise": 1,
"title": "Item 2"
},
{
"id": 3,
"franchise": 2,
"title": "Item 3",
}
]
And the expected result when I query FranchiseDetailSerializer with a pre-existing franchise object.
{
"id": 1,
"name": "Franchise 1"
}
Now, when I change FranchiseDetailSerializer, as per the DRF guide on nested relations:
class FranshiseDetailSerializer(serializers.ModelSerializer):
items = ItemListSerializer(many=True, read_only=True)
class Meta:
model = Franchise
fields = ('id', 'name', 'items')
I would expect the get the following result:
{
"id": 1,
"name": "Franchise 1"
"items": [
{"id": 1, "title": "Item 1", "franchise": 1},
{"id": 2, "title": "Item 2", "franchise": 1}
]
}
But instead, I get no change, as though I hadn't updated FranchiseDetailSerializer at all:
{
"id": 1,
"name": "Franchise 1"
}
The worst part about this for me is that I am not getting any kind of error, I'm simply not seeing results.
Any and all help is appreciated, thanks.
Actually you missed a tiny part of docs :)
album = models.ForeignKey(Album, related_name='tracks')
Define related_name in ForeignKey
franchise = models.ForeignKey(Franchise, on_delete=None, related_name='items')
After that stuff started working for me.

Django REST - How can I get a JSON with two models?

I've two models (Map and Place) and I want to create a JSON with both of these (a map contains several places).
models.py
class Map(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200)
class Place(models.Model):
map = models.ForeignKey('main.Map')
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200)
I use this to serialize these models individually :
serializers.py
class MapSerializer(serializers.ModelSerializer):
class Meta:
model = Map
fields = ('id', 'name')
class PlaceSerializer(serializers.ModelSerializer):
class Meta:
model = Place
fields = ('id', 'name', 'map')
I want a JSON like this, but I've no idea how to serialize this correctly...
{
"maplist": {
"maps": [
{
"id": "1",
"name": "dust2",
"places": [
{
"id": "1",
"name": "Long"
},
{
"id": "2",
"name": "Middle"
}
]
},
{
"id": "2",
"name": "inferno",
"places": [
{
"id": "1",
"name": "Middle"
},
{
"id": "2",
"name": "ASite"
}
]
}
]
}
}
Thanks in advance for your help.
Try with nested serializers:
class PlaceSerializer(serializers.ModelSerializer):
class Meta:
model = Place
fields = ('id', 'name')
class MapSerializer(serializers.ModelSerializer):
places = PlaceSerializer(many=True)
class Meta:
model = Map
fields = ('id', 'name')
To make this work, you need to change your model to include a related name to your foreign key:
class Place(models.Model):
map = models.ForeignKey('main.Map', related_name="places")
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=200)

Categories

Resources