I'm using Django rest framework serializer to return plans for a mobile application. For now my serializer response looks like this:
[
{
"id": 1,
"nome": "Test",
"localizacao": "Example - MG",
"instituicao": "Example",
"modalidade": "Example",
"categoria": "Category 1",
"frequencia_semanal": 1,
"carga_horaria": 2,
"quantidade_alunos": 2,
"valor_unitario": "12.00",
"taxa_matricula": "12.00",
"informacoes_adicionais": ""
}
]
I need to separate plans by category so, response structure must look like this:
[
"Category 1": [
{
"id": 1,
"nome": "Test",
"localizacao": "Example",
"instituicao": "Example",
"modalidade": "Example",
"frequencia_semanal": 1,
"carga_horaria": 2,
"quantidade_alunos": 2,
"valor_unitario": "12.00",
"taxa_matricula": "12.00",
"informacoes_adicionais": ""
}
]
]
The "categoria" value, must be keys and all plans belonging to that category must be contained in the key.
there is my models.py
class Plano(models.Model):
PUBLICO_ALVO_MENORES = 1
PUBLICO_ALVO_ADOLESCENTES = 2
PUBLICO_ALVO_ADULTOS = 3
PUBLICO_ALVO_TODOS = 4
PUBLICO_ALVO_CHOICES = (
(PUBLICO_ALVO_MENORES, 'Menores'),
(PUBLICO_ALVO_ADOLESCENTES, 'Adolecentes'),
(PUBLICO_ALVO_ADULTOS, 'Adultos'),
(PUBLICO_ALVO_TODOS, 'Todas as idades'),
)
nome = models.CharField(max_length=200)
localizacao = models.ForeignKey('Localizacao', on_delete=models.PROTECT)
instituicao = models.ForeignKey('Instituicao', null=True, on_delete=models.PROTECT)
modalidade = models.ForeignKey('PlanoModalidade', verbose_name='Modalidades', on_delete=models.PROTECT)
categoria = models.ForeignKey('PlanoCategoria', verbose_name='Categorias', on_delete=models.PROTECT)
publico_alvo = models.SmallIntegerField(choices=PUBLICO_ALVO_CHOICES, null=True)
frequencia_semanal = models.PositiveSmallIntegerField(verbose_name='Frequência semanal')
carga_horaria = models.PositiveSmallIntegerField(verbose_name='Carga horária diária')
quantidade_alunos = models.PositiveSmallIntegerField(verbose_name='Quantidade de alunos')
valor_unitario = models.DecimalField(decimal_places=2, max_digits=18, verbose_name='Valor unitário')
taxa_matricula = models.DecimalField(decimal_places=2, max_digits=18, verbose_name='Taxa matrícula')
informacoes_adicionais = models.TextField(max_length=200, blank=True)
DRF serializers.py
class PlanosSerializer(serializers.ModelSerializer):
categoria = serializers.StringRelatedField()
modalidade = serializers.StringRelatedField()
localizacao = serializers.StringRelatedField()
instituicao = serializers.StringRelatedField()
class Meta:
model = Plano
fields = [
'id', 'nome', 'localizacao', 'instituicao', 'modalidade', 'categoria',
'frequencia_semanal', 'carga_horaria', 'quantidade_alunos', 'valor_unitario',
'taxa_matricula', 'informacoes_adicionais',
]
Please help me haha.
I recoment change your JSON to anything similar to:
[{
"category_id":1,
"category_name":"Category 1",
"category_items":[
{
"id":1,
"nome":"Test",
"localizacao":"Example",
"instituicao":"Example",
"modalidade":"Example",
"frequencia_semanal":1,
"carga_horaria":2,
"quantidade_alunos":2,
"valor_unitario":"12.00",
"taxa_matricula":"12.00",
"informacoes_adicionais":""
}
]
}]
And is more easy, create using neested serializer.
https://www.django-rest-framework.org/api-guide/relations/#nested-relationships
Related
I need to get the child list under the parent list as a group.
class ServiceSerializer(serializers.ModelSerializer):
cleaning_type = serializers.CharField(source='cleaning_type.cleaning_type_name')
class Meta:
model = Service
fields = ('id', 'cleaning_type','service_name')
class ServiceTypeViewSet(ModelViewSet):
serializer_class = ServiceSerializer
http_method_names = ["get"]
queryset = Service.objects.all()
def get_queryset(self):
"""
This view should return a list of all the service types.
"""
servicename_list = Service.objects.all()
return servicename_list
It shows:
[
{
"id": 1,
"cleaning_type": "Lite service",
"service_name": "Floors",
},
{
"id": 2,
"cleaning_type": "Lite service",
"service_name": "Bathrooms",
},
{
"id": 3,
"cleaning_type": "Lite service",
"service_name": "Kitchen",
}
]
I want this to be in the following format:
[
{
id: 1,
cleaning_type: 'Lite service',
service_name: ['Floors', 'bathroom', 'kitchen'],
},
{
id: 2,
cleaning_type: 'Moving cleaning',
service_name: ['Kitchen Including All Appliances And Cabinets'],
},
]
That means all child elements will be under a separate parent list. Not separate by separate.
models.py is here:
Cleaning Type Model:
class CleaningType(models.Model):
cleaning_type_name = models.CharField(
_("Select Cleaning Type"), blank=True, null=True, max_length=255)
price = models.DecimalField(default=0,max_digits=6, decimal_places=2)
def __str__(self):
return self.cleaning_type_name
Service Model:
class Service(models.Model):
cleaning_type = models.ForeignKey(
CleaningType, on_delete=models.CASCADE)
service_name = models.CharField(
_("Service Name"), blank=True, null=True, max_length=255)
#string type added
def __str__(self):
return str(self.service_name)
I want sub categories under parent caterories. Here cleaning_type is the parent category and service is the child category of cleaning_type. i.e : cleaning_type >> service_type
I'd create a view for the parent category and then get child categories for each parent category. First, you should create a serializer for CleaningType model:
class CleaningTypeSerializer(serializers.ModelSerializer):
service_types = serializers.SerializerMethodField('get_service_types')
def get_service_types(self, cleaning_type_name):
return Service.objects.filter(cleaning_type=cleaning_type_name).values_list("service_name", flat=True)
class Meta:
model = CleaningType
fields = "__all__"
Then, create a view using the new serializer:
class CleaningTypesViewSet(ModelViewSet):
serializer_class = CleaningTypeSerializer
http_method_names = ["get"]
queryset = CleaningType.objects.all()
The response looks something like this:
[
{
"id": 1,
"service_types": [
"Moving Service 1",
"Moving Service 2",
"Moving Service 3"
],
"cleaning_type_name": "Moving Cleaning",
"price": "200.00"
},
{
"id": 2,
"service_types": [
"Another Service 1",
"Another Service 2"
],
"cleaning_type_name": "Another Cleaning",
"price": "300.00"
}
]
iam trying to count with filter and it doesn't show any error but there is no count showing
I have tried all what I know and search every where didn't find any solution :
class UsersAnswersSerializer(serializers.ModelSerializer):
Answers = serializers.SerializerMethodField('get_answers')
def get_answers(self, obj):
queryset = AnswersModel.objects.filter(Question=obj.Answer.Question.id)\
.annotate(answersCount=Count('UsersAnswer', distinct=True))
serializer = Answersserializer(instance=queryset, many=True)
return serializer.data
class Meta:
model = UsersAnswerModel
fields = ['Answer', 'APNSDevice' ,'RegistrationID','Answers']
and this is my models :
class AnswersModel(models.Model):
Question = models.ForeignKey(QuestionsModel, related_name='QuestionAnswer', on_delete=models.CASCADE)
Answer = models.CharField(max_length=200)
class UsersAnswerModel(models.Model):
Answer = models.ForeignKey(AnswersModel, related_name='UsersAnswer', on_delete=models.CASCADE)
RegistrationID = models.CharField(max_length=200)
APNSDevice = models.CharField(max_length=200,default='no name')
class QuestionsModel(models.Model):
created = models.DateTimeField(auto_now_add=True)
Question = models.CharField(max_length=200)
what is get is
{
"Answer": 12,
"APNSDevice": "byname",
"RegistrationID": "asdasdasdasdasdasdasdasdsa",
"Answers": [
{
"id": 10,
"Question": 4,
"Answer": "Answer 1",
"UsersAnswer": [
"gfgdgdfgdf",
"c748dfd8aa7dd73a6c1ef17676aa7667161ff7e0f8e2ef21ef17e964a26150e4"
]
},
{
"id": 11,
"Question": 4,
"Answer": "Answer 2",
"UsersAnswer": [
"sfgdfgdf",
"c748dfd8aa7dd73a6c1ef17676aa7667161ff7e0f8e2ef21ef17e964a26150e4",
"c748dfd8aa7dd73a6c1ef17676aa7667161ff7e0f8e2ef21ef17e964a26150e4",
"c748dfd8aa7dd73a6c1ef17676aa7667161ff7e0f8e2ef21ef17e964a26150e4"
]
}
I need to make "UsersAnswer" show a count of its array
I think what you want to do is aggregate and count.
Replace annotate with aggregate
I have two models, one related to other by foreign key like this
class CapturedPrescriptionModel(ColModel):
p_id = models.IntegerField()
p_age = models.IntegerField()
p_gender = models.CharField(max_length=10)
p_care_type = models.CharField(max_length=100)
bacteria_id = models.ForeignKey(BacteriaListModel,
on_delete=models.CASCADE, null=True)
class SuggestedAntibioticsModel(ColModel):
prescription_id = models.ForeignKey(CapturedPrescriptionModel,
related_name='antibiotics',
on_delete=models.CASCADE)
cat_ids = models.TextField()
flag = models.IntegerField(default=0)
Now I want all the prescriptions with suggested antibiotics where flag=1
I have tried with CapturedPrescriptionModel.objects.filter(antibiotics__flag=1) but that filter the prescriptions not the list of antibiotics in the queryset.
[
{
"id": 7,
"p_id": 0,
"p_age": 19,
"p_gender": "Male",
"p_care_type": "ICU",
"bacteria_id": null,
"antibiotics": [
{
"id": 188,
"cat_ids": "[]",
"flag": 0,
"antibiotic_id_id": 87,
"prescription_id_id": 7
},
{
"id": 187,
"cat_ids": "[]",
"flag": 1,
"antibiotic_id_id": 112,
"prescription_id_id": 7
},
......
]
}
....
]
My expected result will be like this
[
{
"id": 7,
"p_id": 0,
"p_age": 19,
"p_gender": "Male",
"p_care_type": "ICU",
"bacteria_id": null,
"antibiotics": [
{
"id": 187,
"cat_ids": "[]",
"flag": 1,
"antibiotic_id_id": 112,
"prescription_id_id": 7
}
]
}
....
]
You need a filtered Prefetch if you want to filter the related objects only, not the main objects:
from django.db.models import Prefetch
CapturedPrescriptionModel.objects.prefetch_related(Prefetch(
'antibiotics',
queryset=SuggestedAntibioticsModel.objects.filter(flag=1)
)
You then have to make sure that antibiotics on the individual prescription objects is only accessed with prescription.antibiotics.all(), otherwise the prefetch is not used and you'll get all antibiotics again.
Collect all Prescriptions:
prescriptions = CapturedPrescriptionModel.objects.all()
for prescription in prescriptions:
prescription.antibiotics = prescription.antibiotics.filter(flag=1)
# at this time presciptions should be prepared, just make sure to not save them...
You could also extend your model to have a property for that list.
class CapturedPrescriptionModel(ColModel):
p_id = models.IntegerField()
p_age = models.IntegerField()
p_gender = models.CharField(max_length=10)
p_care_type = models.CharField(max_length=100)
bacteria_id = models.ForeignKey(BacteriaListModel,
on_delete=models.CASCADE, null=True)
#property
def flagged_antibiotics(self):
try:
return self.antibiotics.filter(flag=1)
except Exception:
return []
class SuggestedAntibioticsModel(ColModel):
prescription_id = models.ForeignKey(CapturedPrescriptionModel,
related_name='antibiotics',
on_delete=models.CASCADE)
cat_ids = models.TextField()
flag = models.IntegerField(default=0)
Something like this would be my first take on that
Sorry for this newbie question, but I simply cannot find my way reading the manual.
models
#Subject
class TemaPai(models.Model):
subject = models.TextField()
disciplines = models.ManyToManyField(Materia)
# order = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.subject
class Meta:
verbose_name_plural = "temas-pais (subjects)"
# Order and junction
class TemaPaiOrdem(models.Model):
subject = models.ForeignKey(TemaPai, on_delete=models.CASCADE)
discipline = models.ForeignKey(Materia, on_delete=models.CASCADE)
order = models.IntegerField()
def __str__(self):
var2 = self.subject.subject
var = self.discipline.discipline
return var2 + ' - ' + var
class Meta:
verbose_name_plural = "Temas-pais-ordem"
unique_together = ('subject', 'discipline')
serializers
class TemaPaiSerializer(serializers.ModelSerializer):
disciplines = serializers.PrimaryKeyRelatedField(many=True, queryset=Materia.objects.all())
class Meta:
model = TemaPai
fields = ('id', 'subject', 'url', 'disciplines')
class TemaPaiOrdemSerializer(serializers.ModelSerializer):
discipline = serializers.PrimaryKeyRelatedField(queryset=Materia.objects.all())
subject = serializers.PrimaryKeyRelatedField(queryset=TemaPai.objects.all())
class Meta:
model = TemaPaiOrdem
fields = ('id', 'subject','discipline', 'order')
Well, TemaPaiOrdemSerializer is giving me a list like this:
[
{
"id": 1,
"subject": 1,
"discipline": 1,
"order": 1
},
{
"id": 2,
"subject": 2,
"discipline": 1,
"order": 11
}
]
It is fine. But I want to retrieve the subject string representation (from TemaPai model) as well, as a read_only field. So my desired list would be something like:
[
{
"id": 1,
"subject": 1,
"subject_name": "Introduction",
"discipline": 1,
"order": 1
},
{
"id": 2,
"subject": 2,
"subject_name": "Advanced stuff",
"discipline": 1,
"order": 11
}
]
I am trying to use
subject_name = serializers.ReadOnlyField(source:'subject')
with no success. Any hint would be appreciated.
Use ,
subject_name = serializers.StringRelatedField(source='subject',read_only=True)
hence your serializer will be like,
class TemaPaiOrdemSerializer(serializers.ModelSerializer):
discipline = serializers.PrimaryKeyRelatedField(queryset=Materia.objects.all())
subject = serializers.PrimaryKeyRelatedField(queryset=TemaPai.objects.all())
subject_name = serializers.StringRelatedField(source='subject',read_only=True)
class Meta:
model = TemaPaiOrdem
fields = ('id', 'subject', 'subject_name', 'discipline', 'order')
You can use . in source argument for lookup related model's field like this:
subject_name = serializers.ReadOnlyField(source='subject.subject')
How can i get products name and id instead of pro_id and ord_id in output ? but not in string type. for example : "name : somebook" is not a valid option for me.
I just working on this for 2 days without break and i think im missing a little detail but i cant find what is it.
Output i want
[
{
"order_id": 1,
"totalquantity": 12,
"totalprice": 56,
"userid": 1,
"customerAddress": "evka1",
"customerPhone": "539",
"trackNo": 12034,
"products": [
{
"name": "somebook",
"id": 1,
"quantity": 6
},
{
"name": "someotherbook",
"id": 2,
"quantity": 6
}
]
}
]
Output i get
[
{
"order_id": 1,
"totalquantity": 12,
"totalprice": 56,
"userid": 1,
"customerAddress": "evka1",
"customerPhone": "539",
"trackNo": 12034,
"products": [
{
"pro_id": 2,
"ord_id": 1,
"quantity": 6
},
{
"pro_id": 3,
"ord_id": 1,
"quantity": 6
}
]
}
]
Order model
class Order(models.Model):
order_id = models.AutoField(primary_key=True)
totalquantity = models.IntegerField(default=0, null=True)
totalprice = models.IntegerField(default=0, null=True)
userid = models.IntegerField(default=0, null=True)
trackNo = models.IntegerField(default=0, null=True)
billNo = models.IntegerField(default=0, null=True)
customerAddress = models.CharField(max_length=30,default="nil", null=True)
customerPhone = models.CharField(max_length=30,default="nil", null=True)
Order Serializer
class OrderSerializer(serializers.ModelSerializer):
products = ProductOrderSerializer(many=True, read_only=True)
class Meta:
model = Order
fields = ('order_id', 'totalquantity', 'totalprice', 'userid', 'customerAddress', 'customerPhone', 'trackNo', 'products')
Product Model
class Product(models.Model):
name = models.CharField(max_length=30,default="nil", null=True)
author = models.CharField(max_length=30,default="nil", null=True)
date = models.DateField(null=True)
price = models.FloatField(default=0, null=True)
quantity = models.IntegerField(default=0, null=True)
soldcount = models.IntegerField(default=0, null=True)
category = models.CharField(max_length=30,default="nil", null=True)
Product Serializer
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'name', 'author', 'date', 'price', 'quantity', 'soldcount', 'category')
ProductOrder Model
class ProductOrder(models.Model):
pro_id = models.IntegerField(default=0,null=True)
ord_id = models.ForeignKey(Order, related_name='products')
quantity = models.IntegerField(default=0, null=True)
ProductOrder Serializer
class ProductOrderSerializer(serializers.ModelSerializer):
class Meta:
model = ProductOrder
fields = ('pro_id', 'ord_id', 'quantity')
The output you desired can be achieved with nested serializers in django-rest-framework,
But, it needs some refactoring in your models,
You need to add a ForeignKey to the model ProductOrder towards the Product model, inorder to attain a ManyToMany relation,
class ProductOrder(models.Model):
pro_id = models.ForeinKey(Product, related_name='orders', default=0,null=True)
ord_id = models.ForeignKey(Order, related_name='products')
quantity = models.IntegerField(default=0, null=True)
Also, in your serializers,
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('name', 'id', 'quantity')
class ProductOrderSerializer(serializers.ModelSerializer):
details = ProductSerializer(source='pro_id', read_only=True)
class Meta:
model = ProductOrder
fields = ('details', )
class OrderSerializer(serializers.ModelSerializer):
products = ProductOrderSerializer(many=True, read_only=True)
class Meta:
model = Order
fields = ('totalquantity', 'totalprice', 'userid',
'trackNo', 'billNo', 'customerAddress', 'customerPhone',
'products')
You could call OrderSerializer and get the output as you desired,
def get(self, request, *args, **kwargs):
orders = Order.objects.all()
serializer = OrderSerializer(orders, many=True)
return Response(serializer.data)
The output will be like this,
[
{
"totalquantity": 0,
"totalprice": 0,
"userid": 0,
"trackNo": 0,
"billNo": 0,
"customerAddress": "nil",
"customerPhone": "nil",
"products": [
{
"details": {
"name": "nil",
"id": 1,
"quantity": 0
}
},
{
"details": {
"name": "nil",
"id": 1,
"quantity": 0
}
}
]
}
]
I solved the problem when i changed ProductOrderSerializer to :
class ProductListingSerializer(serializers.RelatedField):
def to_representation(self, value):
dict={}
dict['name'] = value.pro_id.name
dict['id'] = value.pro_id.pk
dict['quantity'] = value.quantity
return dict
but im in "my code works i don't know why" situation now :D