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
Related
I am trying to achieve is to get all comments based on photo_id, and count the total replies at the same time.
models.py:
class PhotoComment(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
photo = models.ForeignKey(UserPhoto,on_delete=models.CASCADE)
comment_text = models.TextField(max_length = 500)
comment_reply = models.ForeignKey('self',related_name='replies',blank=True,null=True,on_delete = models.CASCADE)
...
def __str__(self):
return '%s(photo_%s)' %(self.user,self.photo)
views.py:
class PhotoCommentView(APIView):
def patch(self,request,formate=None):
photo_id = request.data.get('photo_id')
all_comment = list(PhotoComment.objects.filter(photo__id = photo_id,comment_reply = None).values('id','user__username','comment_text','user__profile__profile_pic','vote_upvote').annotate(total_reply = Count('comment_reply')))
return Response({"Data" : all_comment},status=status.HTTP_200_OK)
Real result is like this:
{
"Data": [
{
"id": 12,
"user__username": "pradip",
"comment_text": "this is awesome pic bro....",
"user__profile__profile_pic": "profile_pic/gyroscope_HUq0uJ0.png",
"vote_upvote": 2,
"total_reply": 0⬅⬅⬅⬅
},
...
]
}
What I want for result is like this(Here comment id 12 contain total 3 replies.):
{
"Data": [
{
"id": 12,
"user__username": "pradip",
"comment_text": "this is awesome pic bro....",
"user__profile__profile_pic": "profile_pic/gyroscope_HUq0uJ0.png",
"vote_upvote": 2,
"total_reply": 3⬅⬅⬅⬅
},
....
]
}
I have no idea with this problem I need some help.
If you know any other easy or recommended solution to achieve this please tell me.
Thank you.
As stated by others, properties are refering to a specific object instance. Querysets are used to do things on a range of objects.
Therefore to replicate for a queryset the property you defined for an object instance, you need to setup an annotation:
from django.db.models import Count
all_comment = list(PhotoComment.objects.annotate(total=Count('comment_reply')
).filter(photo__id = request.data.get('photo_id')
).values('id','comment_text','total'))
Hope the general principle explained here will enable you to get to where you want to go
I use SerializerMethodField() in serializer to count comment reply.
serializers.py:
class ShowCommentSerializer(serializers.ModelSerializer):
total_reply = SerializerMethodField()
user_name = serializers.CharField(source='user.username')
profile_pic = serializers.CharField(source='user.profile.profile_pic')
class Meta:
model = PhotoComment
fields = ('id','user_name','profile_pic','comment_text','total_reply','created_date')
read_only_fields = fields
def get_total_reply(self, obj):
total = obj.replies.count()
return total
views.py:
class PhotoCommentView(APIView):
def patch(self,request,formate=None):
photo_id = request.data.get('photo_id')
comment_inst = PhotoComment.objects.filter(photo = photo_id,comment_reply=None)
serializer = ShowCommentSerializer(comment_inst,many=True)
return Response({"Data" : serializer.data},status=status.HTTP_200_OK)
Output:
{
"Data": [
{
"id": 29,
"user_name": "admin",
"profile_pic": "profile_pic/Airbus.png",
"comment_text": "good bro....",
"total_reply": 3,
"created_date": "2021-03-10T02:25:43.940127+05:30"
},
]
}
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
I'm struggling to write a Django GET that returns the following looking response:
{
"lists": [
{
"id": "123",
"list_order": [
{
"id": "123_1",
"order": 1,
"list_id": "123",
"item_id": 9876,
"item": {
"id": 9876,
"name": "item1",
"location": "California"
}
},
{
"id": "123_2",
"order": 2,
"list_id": "123",
"item_id": 2484,
"item": {
"id": 2484,
"name": "item2",
"location": "California"
}
}
],
"updated_date": "2018-03-15T00:00:00Z"
}
]
}
Given a list_id, the response returns the basic information on the list ("id", "updated_date"), as well as the order of items in the list. Inside each item in the list order, it also grabs the related item details (nested in "item"). I'm able to get this response without the "item" details ("id", "name", "location" fields) and with no error:
{
"lists": [
{
"id": "123",
"list_order": [
{
"id": "123_1",
"order": 1,
"list_id": "123",
"item_id": 9876
},
{
"id": "123_2",
"order": 2,
"list_id": "123",
"item_id": 2484
}
],
"updated_date": "2018-03-15T00:00:00Z"
}
]
}
Again there is no error, and I can retrieve the first nested level without any issue. The problem is getting the "item" information to show within each "list_order". Below are my models, serializers, and views.
models.py
class Lists(models.Model):
id = models.CharField(null=False, primary_key=True, max_length=900)
updated_date = models.DateTimeField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tbl_lists'
class Items(models.Model):
id = models.BigIntegerField(primary_key=True)
name = models.TextField(blank=True, null=True)
location = models.TextField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tbl_items'
class ListOrder(models.Model):
id = models.CharField(null=False, primary_key=True, max_length=900)
list_id = models.ForeignKey(Lists, db_column='list_id', related_name='list_order')
item_id = models.ForeignKey(Items, db_column='item_id', related_name='items')
order = models.BigIntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'tbl_list_order'
serializers.py
class ItemsSerializer(serializers.ModelSerializer):
class Meta:
model = Items
fields = '__all__'
class ListOrderSerializer(serializers.ModelSerializer):
item = ItemsSerializer(many=False, read_only=True)
class Meta:
model = ListOrder
fields = '__all__'
class ListsSerializer(serializers.ModelSerializer):
list_order = ListOrderSerializer(many=True, read_only=True)
class Meta:
model = Lists
fields = '__all__'
views.py
class ListsViewSet(generics.ListCreateAPIView):
"""
API endpoint that returns a list with its meta-information
"""
queryset = Lists.objects.all()
serializer_class = ListsSerializer
def get_queryset(self):
list_id = self.kwargs['list_id']
filters = [Q(id=list_id)]
return Lists.objects.filter(*filters)
def list(self, request, list_id):
queryset = self.get_queryset()
list_serializer = ListsSerializer(queryset, many=True)
return Response({ 'lists': list_serializer.data })
I'm pretty new to Django and like what it offers so far, though maybe I'm thinking of doing this in too much of a "SQL" way. I've read about select_related() and prefetch_related(), but not sure how I would apply it to this case. Any assistance is greatly appreciated and let me know if there's any other information I can provide.
In your ListOrderSerializer you are trying to serialize item. while in ListOrder model you used the field name item_id
Solution:
In ListOrderSerializer:
class ListOrderSerializer(serializers.ModelSerializer):
item_id = ItemsSerializer(many=False, read_only=True)
...
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')
I have two serializers: one for the Restaurant model, another for the MainMenu model:
class RestaurantSerializer(serializers.ModelSerializer):
class Meta:
model = Restaurant
class MainMenuSerializer(serializers.ModelSerializer):
restaurant = RestaurantSerializer()
main_menu_items = serializers.StringRelatedField(many=True)
class Meta:
model = MenuMain
fields = ('id', 'restaurant', 'main_menu_items')
The current output of the MainMenuSerializer is
[
{
"id": 1,
"restaurant": {
"id": 1,
"name": "Restaurant A",
"location": "Street B"
},
"main_menu_items": [
"Fried Rice"
]
},
{
"id": 2,
"restaurant": {
"id": 1,
"name": "Restaurant A",
"location": "Street B",
},
"main_menu_items": [
"Noodles"
]
}
]
But I want the RestaurantSerializer to only output once, something like this:
[
{
"restaurant": {
"id": 1,
"name": "Restaurant A",
"location": "Street B"
}
},
[
{
"id": 1,
"main_menu_items": [
"Fried Rice",
"Meat Balls"
]
},
{
"id": 2,
"main_menu_items": [
"Noodles"
]
}
]
]
EDIT:
models used
class Restaurant(models.Model):
name = models.CharField(max_length=100, default='')
location = models.CharField(max_length=100, default='')
class MenuMain(models.Model):
price = models.IntegerField()
restaurant = models.ForeignKey(Restaurant, related_name='main_menus')
class MenuMainItems(models.Model):
menu_main = models.ForeignKey(MenuMain, related_name='main_menu_items')
item = models.CharField(max_length=150, default='')
The more "Django REST" way of doing this is to set up a url node for each restaurant that returns all the menu items in the restaurant. For instance,
urls.py
url(r'restaurant-menu/(?P<pk>[0-9]+)$', MenuItemViewset.as_view())
In your viewset class
class MenuItemViewset(viewsets.ModelViewSet):
serializer_class = MainMenuSerializer
def retrieve(self, request, pk=None):
return Restaurant.objects.get(pk=pk).menumain_set.all()[0].menumainitems_set.all()
This of course assumes one menu per restaurant. If there are multiple menus and you want to get all of them, it's probably best practice to break it up into two calls: one for the restaurant's menu, and to get a particular menu's items. Otherwise too many assumptions are being made about the organization of the data, and that's a rather fragile design pattern.
Link to docs on fetching related objects
If you still are intent on getting a response like you originally asked for, you just need to reverse the serializer nesting, i.e. add a menu field to the RestaurantSerializer.
Here is the very simplest approach I came with. I know this can be improved.
Please comment if you have any query or improvement suggestion.
class RestaurantSerializer(serializers.ModelSerializer):
menu = serializers.SerializerMethodField()
def get_menu(self, obj):
dict_l = {}
res = MainMenu.objects.all() # filter as per your requirement
'''
flds = MainMenu._meta.local_fields
for ins in res:
for f in flds:
print f.name
'''
for ins in res:
dict_l['id'] = ins.id
dict_l['name'] = ins.name
dict_l['restaurant'] = ins.restaurant_id
# return {1: 1, 2: 2}
return dict_l
class Meta:
model = Restaurant
fields = ('id', 'name', 'menu',)