How to fetch parent child hierarchy using django rest-framework - django

I am new to Django rest-framework. I am writing an API to fetch details in a parent-child hierarchy. Following is my code;
models.py
class ConfigAttributes(models.Model):
attr_set_name = models.CharField(max_length=32)
product_type = models.CharField(max_length=32)
class ProductInfo(models.Model):
config_attr = models.ForeignKey(ConfigAttributes, on_delete=models.CASCADE)
product_name = models.CharField(max_length=32)
class AttributeDetails(models.Model):
product_info = models.ForeignKey(ProductInfo, on_delete=models.CASCADE)
attribute_name = models.CharField(max_length=32)
serializers.py
class ConfigAttributesSerializer(serializers.ModelSerializer):
class Meta:
model = ConfigAttributes
fields = ['id', 'attr_set_name', 'product_type']
class ProductInfoSerializer(serializers.ModelSerializer):
class Meta:
model = ProductInfo
fields = ['id', 'product_name', 'config_attr_id']
class AttributeDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = AttributeDetails
fields = ['id', 'attribute_name', 'product_info_id']
views.py
class ConfigAttributesViewSet(viewsets.ModelViewSet):
queryset = ConfigAttributes.objects.all()
serializer_class = ConfigAttributesSerializer
class ProductInfoViewSet(viewsets.ModelViewSet):
queryset = ProductInfo.objects.all()
serializer_class = ProductInfoSerializer
class AttributeDetailsViewSet(viewsets.ModelViewSet):
queryset = AttributeDetails.objects.all()
serializer_class = AttributeDetailsSerializer
and app/urls.py
router = routers.DefaultRouter()
router.register('config', ConfigAttributesViewSet)
router.register('product', ProductInfoViewSet)
router.register('attr', AttributeDetailsViewSet)
urlpatterns = [
path('', include(router.urls)),
]
When I call the API, my required hierarchy and output is;
[
{
"attr_set_name" : "abc",
"product_type" : "efg",
"product_info" : {
"product_name" : "hij",
"attribute_details" : {
"attribute_name" : "klm"
}
}
}
]
What are the changes need to done in the files to get the above output in hierarchy (I am using Postman to check my APIs). Thank you for the help.

You can nest your serializers. To match your general API hierarchy this is as close as you can get. Unfortunately, the relationship fields will be lists.
class AttributeDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = AttributeDetails
fields = ['id', 'attribute_name', 'product_info_id']
class ProductInfoSerializer(serializers.ModelSerializer):
attribute_details = AttributeDetailsSerializer(many=True)
class Meta:
model = ProductInfo
fields = ['id', 'product_name', 'config_attr_id', 'attribute_details']
class ConfigAttributesSerializer(serializers.ModelSerializer):
product_infos = ProductInfoSerializer(many=True)
class Meta:
model = ConfigAttributes
fields = ['id', 'attr_set_name', 'product_type', 'product_infos']
You can get the specific parent elements if you start with the AttributeDetails instance though:
class ConfigAttributesSerializer(serializers.ModelSerializer):
class Meta:
model = ConfigAttributes
fields = ['id', 'attr_set_name', 'product_type',]
class ProductInfoSerializer(serializers.ModelSerializer):
config_attribute = ConfigAttributesSerializer(many=False)
class Meta:
model = ProductInfo
fields = ['id', 'product_name', 'config_attr_id', 'config_attribute']
class AttributeDetailsSerializer(serializers.ModelSerializer):
product_info = ProductInfoSerializer(many=False)
class Meta:
model = AttributeDetails
fields = ['id', 'attribute_name', 'product_info_id', 'product_info']

Related

django rest_framework how to display nested relationship

I'm trying to display foreign related fields like this example and it works
{
"reqid": 10,
"reqdate": "2022-12-05",
"reqdescription": "Aircon Not working",
"officerequestor": "OVCAA ",
"officeid": "PPD ",
"inspection": {
"insdate": "2022-12-06",
"diagnosis": "need to buy prism",
"inspector": "EMP-322 "
}
},
this is my serializers.py
class RequestAdditionDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Inspection
fields = ['insdate',
'diagnosis',
'inspector'
]
class RequestorSerializer(serializers.ModelSerializer):
inspection = RequestAdditionDetailsSerializer(read_only=True)
class Meta:
model = Request
fields = ['reqid',
'reqdate',
'reqdescription',
'officerequestor',
'officeid',
'inspection'
]
My question is can I do this the other way around like this
{
"inspectid": 5,
"reqid": "10",
"insdate": "2022-12-06",
"diagnosis": "need to buy prism",
"inspector": "EMP-322",
"isinspected": {
"reqdescription": "Aircon Not working",
"reqdate": "2022-12-05",
"officerequestor": "OVCAA"
}
},
this is what I've tried, tbh I don't think this will work is there a solution for this.
if no maybe i'll add additional columns on inspection like reqdescription,reqdate etc.. just to show them
class InspectionAdditionalDetailsViewSerializer(serializers.ModelSerializer):
class Meta:
model = Request
fields = ['reqdescription',
'reqdate',
'officerequestor'
]
class InspectionSerializer(serializers.ModelSerializer):
request_details = InspectionAdditionalDetailsViewSerializer(read_only=True)
class Meta:
model = Inspection
fields = ['inspectid',
'reqid',
'insdate',
'diagnosis',
'inspector',
'isinspected',
'request_details'
]
this is my models.py
class Inspection(models.Model):
inspectid = models.AutoField(primary_key=True)
reqid = models.OneToOneField('Request', models.DO_NOTHING, db_column='reqid', blank=True, null=True)
class Meta:
managed = False
db_table = 'inspection'
class Request(models.Model):
reqid = models.AutoField(primary_key=True)
class Meta:
managed = False
db_table = 'request'
You have defined the OneToOne field name reqid therefore you should use it as serializer key.
Noted that Django will add _id to the field so it will become reqid_id in your database, it's best to name it req or request only to refer to related object.
class InspectionAdditionalDetailsViewSerializer(serializers.ModelSerializer):
class Meta:
model = Request
fields = [
'reqdescription',
'reqdate',
'officerequestor',
]
class InspectionSerializer(serializers.ModelSerializer):
reqid = InspectionAdditionalDetailsViewSerializer(read_only=True)
class Meta:
model = Inspection
fields = [
'inspectid',
'reqid',
'insdate',
'diagnosis',
'inspector',
'isinspected',
]

How can to get data from related model in Django Rest Framework?

I have next models
class User(AbstractUser):
ip_address = models.CharField(max_length=15)
class Statistic(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='statistics')
clicks = models.PositiveSmallIntegerField()
and serializers
class UserListSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ['id', 'first_name', 'ip_address']
class UserStatisticSerializer(serializers.ModelSerializer):
class Meta:
model = Statistic
How can I get in Response data in following format:
{
'user_data': {
'id': 1, 'first_name': 'name', ...,
'statistics': [
{'id': 1, 'clicks': 100},
{'id': 3, 'clicks': 550}
]
}
I go to the link /api/v1/users/<int:pk>/ and call next function:
class UserDetailStatisticApiView(RetrieveAPIView):
queryset = ???
serializer_class = ???
Thnx for help
View
class UserDetailStatisticApiView(RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserListSerializer
Serializers
class UserStatisticSerializer(serializers.ModelSerializer):
class Meta:
model = Statistic
fields = '__all__'
class UserListSerializer(serializers.ModelSerializer):
statistics = SerializerMethodField()
class Meta:
model = User
fields = ['id', 'first_name', 'statistics']
def get_statistics(self,obj):
statistics = Statistic.objects.filter(user=obj)
return UserStatisticSerializer(statistics, many=True).data
serializers
class StatisticSerializer(serializers.ModelSerializer):
class Meta:
model = Statistic
fields = ['date', 'clicks', 'page_views']
class UserStatisticSerializer(serializers.ModelSerializer):
statistics = StatisticSerializer(many=True)
class Meta:
model = User
fields = [
'first_name', 'last_name', 'gender', 'ip_address', 'statistics'
]
views
class UserDetailStatisticApiView(RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserStatisticSerializer

How to serialize models with multiple foreign keys?

I want to serialize data in the format given below.I'm new to django-rest framework.I am working in a varsity project.So, little help will be appreciated.
{
{
"Series_name":"something",
"Home_team":"anything",
"Away_team":"sbh",
"players":[
{
"id":"1",
...
}
{
"id":"2",
...
}
]
},
{
"Series_name":"something2",
"Home_team":"anything",
"Away_team":"sbh",
"players":[
{
"id":"1",
...
}
{
"id":"1",
...
}
]
}
}
I have tried this.But this doesn't give satisfactory result.In fact it returns empty set.
class PlayersSerializer2(serializers.ModelSerializer):
class Meta:
model = Players
fields = ['name', 'country', 'image', 'role', 'credit']
class SeriesListSerializer2(serializers.ModelSerializer):
class Meta:
model = SeriesList
fields = '__all__'
class SeriesSquadsSerializer(serializers.ModelSerializer):
players = PlayersSerializer2(many=True, read_only=True)
series = SeriesListSerializer2(many=True, read_only=True)
class Meta:
model = SeriesSquads
fields = ['series', 'players']
these are the models I'm working with.I've 3 models SeriesList,Series_Squads and Players.Series_sqauds has unique pairs (Series_name,Players).It has two foreign keys pointing objects of SeriesList and Players.
class SeriesList(models.Model):
Series_name = models.CharField(max_length=250,
unique=True,primary_key=True)
No_of_matches = models.IntegerField()
Home_team = models.CharField(max_length=250)
Away_team = models.CharField(max_length=250)
class SeriesSquads(models.Model):
Series_name = models.ForeignKey(SeriesList, on_delete=models.CASCADE)
Squad_player = models.ForeignKey(Players, on_delete=models.CASCADE)
class Players(models.Model):
name = models.CharField(default="", max_length=250)
country = models.CharField(max_length=250)
image = models.CharField(max_length=500)
role = models.CharField(max_length=30)
credit = models.FloatField(default=None)
You can get user of SerializerMethodField to get your ForeignKey related objects into your serializer. Update your serializer so that:
class PlayersSerializer2(serializers.ModelSerializer):
class Meta:
model = Players
fields = ['name', 'country', 'image', 'role', 'credit']
class SeriesSquadsSerializer(serializers.ModelSerializer):
players = PlayersSerializer2(many=True, read_only=True)
Series_name = serializers.SerializerMethodField()
Home_team = serializers.SerializerMethodField()
Away_team = = serializers.SerializerMethodField()
class Meta:
model = SeriesSquads
fields = ['players']
def get_Series_name(self, obj):
return obj.Series_name.Series_name
def get_Home_team(self, obj):
return obj.Series_name.Home_team
def get_Away_team(self, obj):
return obj.Series_name.Away_team

Django Serialize multiple models in a single view

Here's the scenario, i have two models Offre and Recruteur
class Recruteur(models.Model):
[...]
entrepriseName = models.CharField(max_length=50)
[...]
class Offre(models.Model):
[...]
idRecruteur = models.ForeignKey(Recruteur,verbose_name = "idRecruteur", on_delete=models.CASCADE, default=None)
[...]
And I have the following serializers:
class RecruteurByIdSerializer(serializers.ModelSerializer):
class Meta:
model = Recruteur
fields = ( 'entrepriseName',)
class OffreSerializer(serializers.ModelSerializer):
recruteur = RecruteurByIdSerializer(many=True, read_only=True)
class Meta:
model = Offre
fields = ( 'title', 'dateAjout', 'description', 'recruteur')
i expected this result:
but im getting this instead:
what am i doing wrong ?
You have to provide source parameter as below,
class OffreSerializer(serializers.ModelSerializer):
entrepriseName = RecruteurByIdSerializer(source='idRecruteur', read_only=True)
class Meta:
model = Offre
fields = ('title', 'dateAjout', 'description', 'entrepriseName')

django-polymorphic-tree serializer

I would like to serialize all the nodes in my PolymorphicMPTTModel with their corresponding fields. Following the documentation django-polymorphic and django-mptt i get this:
{
"count":1,
"next":null,
"previous":null,
"results":[
{
"title":"Submenu",
"subcategories":[
{
"title":"Plato1",
"subcategories":[
]
},enter code here
{
"title":"Plato2",
"subcategories":[
]
}
]
}
]
}
The structure is fine, but the fields of the children are missing.
Models:
class Menu(PolymorphicMPTTModel):
parent = PolymorphicTreeForeignKey('self', blank=True, null=True, related_name='children', verbose_name='parent')
title = models.CharField("Title", max_length=200)
class SubMenu(Menu):
titulo = models.CharField("Titulo", max_length=200,default="not defined")
class Plato(Menu):
titulo = models.CharField("Titulo",max_length=200,default="not defined")
descripcion = models.TextField()
ingredientes = JSONField()
precio = models.PositiveSmallIntegerField(default=0)
# Extra settings:
can_have_children = False
Serializers:
class PlatoSerializer(serializers.ModelSerializer):
class Meta:
model = Plato
fields = ('titulo', 'descripcion', 'ingredientes', 'precio')
class SubMenuSerializer(serializers.ModelSerializer):
class Meta:
model = SubMenu
fields = ('titulo',)
class MenuItemModuleSerializer(serializers.ModelSerializer):
subcategories = serializers.ListSerializer(source="children",child=RecursiveField())
class Meta:
model = Menu
fields = ('title','subcategories')
View:
class MenuView(viewsets.ModelViewSet):
queryset = Menu.objects.all()
queryset = queryset.toplevel()
serializer_class = MenuItemModuleSerializer
I know I'm kinda late to the party but I had the same issue and finally found a solution that is working for me.
As django-rest-polymorphic states, you need a mapping between models and serializers:
class ProjectPolymorphicSerializer(PolymorphicSerializer):
model_serializer_mapping = {
Menu: MenuItemModuleSerializer,
SubMenu: SubMenuSerializer,
Plato: PlatoSerializer
}
Your RecursiveField() creates a serializer instance from its parent class. That makes all your child objects using the MenuItemModuleSerializer and thus missing child fields.
Every child needs to get mapped to its serializer using ProjectPolymorphicSerializer
RecursiveField(to='ProjectPolymorphicSerializer')
Change your MenuItemModuleSerializer to this:
class MenuItemModuleSerializer(serializers.ModelSerializer):
subcategories = serializers.ListSerializer(source="children", child=RecursiveField(to='ProjectPolymorphicSerializer'))
class Meta:
model = Menu
fields = ('title','subcategories')