I am trying to get data in a particular format but i'm not able to get the desired output.
My Model:
class Category(models.Model):
name = models.CharField(max_length=40)
class Expense(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name="category_name")
description = models.CharField(max_length=200)
total_amount = models.IntegerField()
class Expense_Details(models.Model):
expense = models.ForeignKey(Expense, on_delete=models.CASCADE, related_name="payment")
user = models.IntegerField()
amount = models.FloatField()
type = models.CharField(max_length=100) ---->type is owe or lend
When I request /api/expenses/:
Expected Output
{
“total_expenses”: 10,
“Expenses”:
[{
“id”: 1,
“category”: 1,
“created_by”: 1, ------> user logged id
“description”: “lunch”,
“total_amount”: “105”,
“owe”: [{
“user_id”: 1,
“amount”: 10
},
{
“user_id”: 2,
“amount”: 95
}],
“lend”: [{
“user_id”: 3,
“amount”: 10
},
{
“user_id”: 4,
“amount”: 95
}],
}, ...
]
}
My output:
{
"results": [
{
"id": 1,
"category": 1,
"description": "lunch at the burj al arab",
"total_amount": 105,
"payment": [
{
"user": 1,
"amount": -10
},
{
"user": 2,
"amount": -95
},
{
"user": 3,
"amount": 10
},
{
"user": 4,
"amount": 95
}
]
}
]
}
My Serializer:
class ExpenseDetailsSerializer(serializers.ModelSerializer):
class Meta:
model = Expense_Details
fields = ['user', 'amount']
class ExpenseSerializer(serializers.ModelSerializer):
payment = serializers.SerializerMethodField()
def get_payment(self, obj):
return ExpenseDetailsSerializer(obj.payment.all(), many=True).data
class Meta:
model = Expense
fields = ['id', 'category', 'description', 'total_amount', 'payment',]
What Query should I use to get Output in the above format? How will my serializer look like? How can I separate own and lend? Also I have stored own and lend with + and - sign to differentiate between them.
Use a ListField for the same.
Documentation: https://www.django-rest-framework.org/api-guide/fields/#listfield
Also refer How to serialize an 'object list' in Django REST Framework
Here you can try something like:
class ExpenseSerializer(serializers.Serializer):
payment = serializers.ListField(child=ExpenseDetailsSerializer())
def get_payment(self, obj):
return ExpenseDetailsSerializer(obj.payment.all(), many=True).data
class Meta:
model = Expense
fields = ['id', 'category', 'description', 'total_amount', 'payment',]
Related
I have two related models (Product and Recipe). There is a many-to-many relationship defined between them (with a through model). I am able to query the 'through' model fields using the below serializer, but I am unable to make this work the other way around (from Product to Recipe)
models.py:
class Product(models.Model):
version = models.CharField(max_length=4)
displayname = models.CharField(max_length=50,validators=[alphanumeric])
...
class Recipe(models.Model):
...
ingredients = models.ManyToManyField(Product, through='RecipeInput', related_name='recipe_input')
products = models.ManyToManyField(Product, through='RecipeOutput',related_name='recipe_output')
class RecipeInput(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
amount = models.IntegerField(default=1)
amount_min = models.FloatField(blank=True, null=True)
class RecipeOutput(models.Model):
recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
amount = models.IntegerField(default=1)
amount_min = models.FloatField(blank=True, null=True)
mj = models.FloatField(blank=True, null=True)
serializers.py:
class RecipeInputSerializer(serializers.HyperlinkedModelSerializer):
product_id = serializers.ReadOnlyField(source='product.id')
product_name = serializers.ReadOnlyField(source='product.displayname')
class Meta:
model = RecipeInput
fields = ('product_id',"product_name", 'amount', 'amount_min', )
class RecipeOutputSerializer(serializers.HyperlinkedModelSerializer):
product_id = serializers.ReadOnlyField(source='product.id')
product_name = serializers.ReadOnlyField(source='product.displayname')
class Meta:
model = RecipeOutput
fields = ('product_id',"product_name", 'amount', 'amount_min', 'mj', )
class ProductInputSerializer(serializers.HyperlinkedModelSerializer):
recipe_id = serializers.ReadOnlyField(source='recipe.id')
recipe_name = serializers.ReadOnlyField(source='recipe.displayname')
class Meta:
model = RecipeInput
fields = ('recipe_id','recipe_name', 'amount_min', 'amount', )
class RecipeSerializer(serializers.ModelSerializer):
ingredients = RecipeInputSerializer(source='recipeinput_set', many=True)
products = RecipeOutputSerializer(source='recipeoutput_set', many=True)
class Meta:
model = Recipe
fields = "__all__"
depth = 1
class ProductSerializer(serializers.ModelSerializer):
products_in = ProductInputSerializer(source='recipe_input', many=True)
class Meta:
model = Product
fields = "__all__"
depth = 1
Now, this works for Recipe, I get the following output:
[
{
"id": 1239,
"ingredients": [
{
"product_id": 1787,
"product_name": "Automated Wiring",
"amount": 15,
"amount_min": 7.5
},
{
"product_id": 1799,
"product_name": "Circuit Board",
"amount": 10,
"amount_min": 5.0
}
],
"products": [
{
"product_name": "Adaptive Control Unit",
"amount": 2,
"amount_min": 1.0,
"mj": 3300.0
}
],
...
},
{
"id": 1240,
"ingredients": [
{
"product_id": 1809,
"product_name": "Copper Sheet",
"amount": 5,
"amount_min": 25.0
},
{
"product_id": 1871,
"product_name": "Quickwire",
"amount": 20,
"amount_min": 100.0
}
],
"products": [
{
"product_name": "AI Limiter",
"amount": 1,
"amount_min": 5.0,
"mj": 180.0
}
],
...
}
]
But, for Product, I am not able to query the related model (Recipe) and the values of the through model. In the serializers.py I defined products_in but it doesnt show recipe_id, recipe_name, etc.
[
{
"id": 2541,
"products_in": [
{
"amount_min": null
}
],
...
},
{
"id": 2542,
"products_in": [
{
"amount_min": null
},
{
"amount_min": null
}
],
...
}
]
im filtering that user whoes order_status is completed and who have listing_id 5001. But im getting output data repeated
Here is my Code:
models.py
class Users(models.Model):
name = models.CharField(max_length=100)
phone = models.CharField(max_length=20, blank=True, null=True)
'''
class Meta:
managed = False
db_table = 'users'
class UserOrder2(models.Model):
order_id = models.AutoField(primary_key=True)
order_status = models.CharField(max_length=30,default='None')
listing_id = models.CharField(max_length=250,default='None')
user_id = models.ForeignKey(Users, on_delete=models.CASCADE, db_column="user_id")
'''
class Meta:
managed = False
db_table = 'user_order'
class UserOrderProduct2(models.Model):
order_id = models.ForeignKey(UserOrder2, on_delete=models.CASCADE, db_column="order_id")
product_name = models.CharField(max_length=100)
...
class Meta:
managed = False
db_table = 'user_order_product'
Views.py
class UserPurchaseQuantityView(generics.GenericAPIView):
def post(self, request):
listing_id= request.data.get('listing_id')
kwargs = {}
kwargs['userorder2__listing_id'] = listing_id
kwargs['userorder2__order_status'] = 'Order Delivered'
queryset = Users.objects.filter(**kwargs)
data = UsersSerializer(queryset, many=True).data
return Response(data)
serializers.py
class UserOrderProductSerializer2(serializers.ModelSerializer):
class Meta:
fields = ["product_id", "product_quantity", "product_price", "sub_total",
"product_name"]
model = UserOrderProduct2
class UserOrderSerializer(serializers.ModelSerializer):
product_detail = UserOrderProductSerializer2(source="userorderproduct2_set", many=True)
class Meta:
fields = ["user_id", "order_date", "product_detail"]
model = UserOrder2
class UsersSerializer(serializers.ModelSerializer):
user_detail = UserOrderSerializer(source="userorder2_set", many=True)
class Meta:
fields = "__all__"
model = Users
I'm getting repeated output like this:
[
{
"id": 51238,
"name": "aaa",
"phone": "123456789",
"email": "aaa#gmail.com",
"user_detail": [
{
"user_id": 51238,
"order_date": "2021-07-27 15:55:56"
"product_detail": [
{
"product_id": 20767,
"product_quantity": 1,
"product_price": 150.0,
"sub_total": 150.0,
"product_name": "EMINAZ 2mg Tablet 10's"
]
},
{
"id": 51238,
"name": "aaa",
"phone": "123456789",
"email": "aaa#gmail.com",
"user_detail": [
{
"user_id": 51238,
"order_date": "2021-07-27 15:55:56"
"product_detail": [
{
"product_id": 20767,
"product_quantity": 1,
"product_price": 150.0,
"sub_total": 150.0,
"product_name": "EMINAZ 2mg Tablet 10's"
] },
{
"id": 51238,
"name": "aaa",
"phone": "123456789",
"email": "aaa#gmail.com",
"user_detail": [
{
"user_id": 51238,
"order_date": "2021-07-27 15:55:56"
"product_detail": [
{
"product_id": 20767,
"product_quantity": 1,
"product_price": 150.0,
"sub_total": 150.0,
"product_name": "EMINAZ 2mg Tablet 10's"
] } ]
I think the issue is in **kwargs. Try this
class UserPurchaseQuantityView(generics.GenericAPIView):
def post(self, request):
listing_id= request.data.get('listing_id')
queryset = Users.objects.filter(userorder2__listing_id=listing_id,
userorder2__order_status='Order Delivered')
data = UsersSerializer(queryset, many=True).data
return Response(data)
Add distinct() to make unique.
queryset = Users.objects.filter(**kwargs).distinct()
I have the following Django model structure:
class TypeOfIngredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
class Ingredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
typeofingredient = models.ForeignKey(TypeOfIngredient, related_name='typeof_ingredient',null=True, blank=True,on_delete=models.PROTECT)
Serializer:
class IngredientListSerializer(ModelSerializer):
class Meta:
model = Ingredient
fields = '__all__'
With the above serializer i see the following api output:
"results": [
{
"id": 1,
"name": "adrak",
"slug": "adrak",
"typeofingredient": null
},
{
"id": 2,
"name": "banana",
"slug": "banana",
"typeofingredient": 1
},
How to get "typeofingredient": "fruit" where fruit is the name field of the typeofingredient. What i am getting is the id.
I tried nested:
class IngredientListSerializer(ModelSerializer):
class Meta:
model = Ingredient
fields = '__all__'
depth = 1
Then i get the api output as:
"results": [
{
"id": 1,
"name": "adrak",
"slug": "adrak",
"typeofingredient": null
},
{
"id": 2,
"name": "banana",
"slug": "banana",
"typeofingredient": {
"id": 1,
"name": "fruit",
"slug": "fruit"
}
},
Here is showing all the details of the typeofingredient. Rather than this can i have directly "typeofingredient": "fruit"
Use serializers.ReadOnlyField
class IngredientListSerializer(ModelSerializer):
typeofingredient = serializers.ReadOnlyField(source='typeofingredient.name')
class Meta:
model = Ingredient
fields = '__all__'
You can add str method on models.py
class TypeOfIngredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
def __str__(self):
return str(self.name)
class Ingredient(models.Model):
name = models.CharField(max_length=200,unique=True,null=False)
slug = models.SlugField(unique=True)
typeofingredient = models.ForeignKey(TypeOfIngredient, related_name='typeof_ingredient',null=True, blank=True,on_delete=models.PROTECT)
I want to perform some data manipulations before sending back a JSON response with DRF.
Situation
My model is:
class ThirdParty(models.Model):
label = models.CharField(verbose_name=_("Third party label"), null=False, blank=False, default=DEFAUT_LABEL, max_length=255)
class CashFlow(TimeStampedModel):
date = models.DateField(verbose_name=_("Due date"), null=True, blank=True)
forecasted_value = models.DecimalField(verbose_name=_("Forecasted value"), null=True, blank=True, max_digits=11, decimal_places=2)
third_party = models.ForeignKey(ThirdParty, null=False, blank=False, related_name='cashflows')
Currently I have two serializers:
class CashFlowSerializer(serializers.ModelSerializer):
third_party = serializers.PrimaryKeyRelatedField(many=False, read_only=True, allow_null=True)
class Meta:
model = CashFlow
fields = ('id', 'date', 'forecasted_value', 'edited_value', 'third_party')
class ThirdPartyReadSerializer(serializers.ModelSerializer):
cashflows = CashFlowSerializer(many=True, read_only=True)
class Meta:
model = ThirdParty
fields = ('id', 'label', 'category', 'cashflows',)
And my ThirdParty view is correctly returning a nice JSON as:
{
"id": 15,
"label": "Adeo",
"category": 7,
"cashflows": [
{
"id": 1,
"date": "2016-11-01",
"forecasted_value": "2000.00",
"edited_value": null,
"third_party": 15
},
{
"id": 2,
"date": "2017-01-17",
"forecasted_value": "3000.00",
"edited_value": null,
"third_party": 15
},
{
"id": 3,
"date": "2017-01-31",
"forecasted_value": "1000.00",
"edited_value": null,
"third_party": 15
}
]
}
Question
I want to group the cash flows by month and add their values.
Question is: what is the best way to do it?
The expected result is:
{
"id": 15,
"label": "Adeo",
"category": 7,
"cashflows": [
{
"date": "2016-11-01",
"forecasted_value": "2000.00",
"edited_value": null,
"third_party": 15
},
{
"date": "2017-01-01",
"forecasted_value": "4000.00",
"third_party": 15
}
]
}
And that will be a read-only serializer.
Use the serializer's to_representation:
def to_representation(self, obj):
data = super().to_representation(obj)
# manipulate data['cashflows'] to group by month
return data
I have two serializers like this.
class CourseSerializer(serializers.ModelSerializer):
pk = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=True, max_length=30, allow_blank=False)
chapters = serializers.SerializerMethodField()
def get_chapters(self, obj):
queryset = Chapter.objects.all().filter(course=obj.pk)
serializer_class = ChapterSerializer(queryset, many=True)
return serializer_class.data
class ChapterSerializer(serializers.ModelSerializer):
pk = serializers.IntegerField(read_only=True)
name = serializers.CharField(required=True, max_length=30, allow_blank=False)
course = serializers.StringRelatedField()
cards_count = serializers.SerializerMethodField()
cards_learned_count = serializers.SerializerMethodField()
cards_still_to_go = serializers.SerializerMethodField()
cards_not_learned = serializers.SerializerMethodField()
def get_cards_learned_count(self, obj):
user = None
request = self.context.get("request")
if request and hasattr(request, "user"):
user = request.user
queryset = Card.objects.all().filter(chapter=obj.pk)
card_count = 0
for q in queryset:
card_detail = UserCardDetail.objects.all().filter(card=q, user=user, learned=True)
card_detail.count()
card_count += card_detail.count()
return card_count
Now when I get the course serializer instead of getting the proper values in the chapter field, I get zeroes, but when I call the chapter serializer I get the right values.
I noticed that the MethodField works with obj - however shouldn't that be passed already?
Is there something extra I have to pass to the chapters field?
Edit: Output and Expected Output
OUTPUT
{
"name": "Example 1",
"pk": 32,
"locked": false,
"chapters": [
{
"pk": 15,
"name": "Transformatori",
"course": "Tesit",
"cards_count": 5,
"cards_learned_count": 0,
"cards_still_to_go": 0,
"cards_not_learned": 0,
"favorite_cards": 0
},
],
},
expected output
{
"name": "Example 1",
"pk": 32,
"locked": false,
"chapters": [
{
"pk": 15,
"name": "Transformatori",
"course": "Tesit",
"cards_count": 5,
"cards_learned_count": 3,
"cards_still_to_go": 0,
"cards_not_learned": 2,
"favorite_cards": 1
},
],
},