django-polymorphic-tree serializer - django

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

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 to fetch parent child hierarchy using django rest-framework

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']

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 Rest Framework get attributes from foreign key's class

here's my models:
class Recruteur(models.Model):
entrepriseName = models.CharField(max_length=50)
emplacement = models.CharField(max_length=50)
class Offre(models.Model):
title = models.CharField(max_length=100, blank=True, default=0)
idRecruteur = models.ForeignKey(Recruteur,verbose_name = "idRecruteur", on_delete=models.CASCADE, default=None)
and here's my api.py:
class VilleViewSet(ModelViewSet):
queryset = Offre.objects.values('idRecruteur__emplacement').distinct()
serializer_class = VilleSerializer
serializers.py:
class EmplacementSerializer(serializers.ModelSerializer):
class Meta:
model = Recruteur
fields = ('emplacement',)
class VilleSerializer(serializers.ModelSerializer):
emplacements = EmplacementSerializer(source='idRecruteur', read_only=True)
class Meta:
model = Offre
fields = ( 'emplacements',)
i was expecting a result like this
but i got nothing instead ..
Any ideas why?
You get nothing, because there is no emplacements field in Offre model. I guess, what you want is to get serialized Recruteur record, that is referenced by idRecruteur field. Try this:
class VilleSerializer(serializers.ModelSerializer):
idRecruteur = EmplacementSerializer(read_only=True)
class Meta:
model = Offre
fields = ( 'idRecruteur',)

Django admin: list not correct (duplicate rows)

My admin.py is like this:
class ResizableAdmin(admin.ModelAdmin):
class Media:
css = {
}
js = ('js/vendor/jquery-1.11.2.min.js',)
class GroupeMotsForm(django.forms.ModelForm):
mots = django.forms.ModelMultipleChoiceField(
queryset=Mot.objects.all().order_by('groupes__description', 'texte'),
widget=django.forms.SelectMultiple(attrs={'class': 'resize_dst'})
)
class Meta:
model = GroupeMots
fields = ['description', 'admin_taille_fenetre', 'mots', ]
widgets = {
'admin_taille_fenetre': django.forms.NumberInput(
attrs={'class': 'resize_src'}
)
}
class GroupeMotsAdmin(ResizableAdmin):
form = GroupeMotsForm
In my database I have only one row in GroupeMots:
It's displayed 3 times in the list of the admin interface:
Any idea where to look? Where could Django look to have 3 results? They all point to the same record. I'm stuck.
My model is like that:
class GroupeMots(models.Model):
description = models.CharField(max_length=150)
mots = models.ManyToManyField(Mot, blank=True)
class Meta:
ordering = ['mots__texte']
def __str__(self):
return u'{0}'.format(
self.description
)
And the problem came from ordering = ['mots__texte'] because there seems to be 3 results, so "ordering" generates dupes... I changed it to description and now it's ok