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

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)

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

How to make the category itself in the Parent Category and not just the id

I'm using Django Rest Framework for API and I wrote the model Category in which I have parent and I'm using it like this: parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
In API it looks like this:
{
"id": 7,
"name": "softwares",
"img": "",
"parent": 1
},
{
"id": 8,
"name": "databases",
"img": "",
"parent": 1
},
{
"id": 9,
"name": "appearance",
"img": "",
"parent": 2
},
{
"id": 10,
"name": "media",
"img": "",
"parent": 2
},
{
"id": 11,
"name": "system",
"img": "",
"parent": 2
},
Here is Category Serializer:
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
And Category View Set:
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
action_to_serializer = {
"retrieve": CategoryDetailSerializer,
}
def get_serializer_class(self):
return self.action_to_serializer.get(
self.action,
self.serializer_class
)
How can I make the category itself and not just the id?
Assuming you won't be handling with an infinite sequence of relations and are handling this with just one level of parenting, you can achieve that by using nested serializers, an example on your scenario would be something like this:
class NestedCategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ('id', 'name', 'img')
class CategorySerializer(serializers.ModelSerializer):
parent = NestedCategorySerializer()
class Meta:
model = Category
fields = '__all__'
If your relationship needs more depth levels, you can improve this example to include always the serialized parent - be careful with cycles.

Django - combining two models serializer into one JSON response

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)
...

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.

Categories

Resources