I want to show meal based on the meal categories. I am using django rest framework for Rest API. I can show meat but not based on categories. The models are Restaurant, Meal and Meal Cateogies.
here is my model
class Restaurant(models.Model):
name = models.CharField(max_length=150, help_text="name of restaurant")
slug = models.SlugField(max_length=150)
class Meal(models.Model):
restaurant = models.ForeignKey(Restaurant)
meal_category = models.ForeignKey('MealCategory')
name = models.CharField(max_length=120, help_text="name of the meal")
def __str__(self):
return self.name
class MealCategory(models.Model):
name = models.CharField(max_length=80, help_text="name of the category of meal")
slug = models.SlugField(max_length=80)
Serializers.py
class MealCategorySerializer(ModelSerializer):
# meal = SerializerMethodField()
class Meta:
model = MealCategory
class MealSerializer(ModelSerializer):
meal_category = MealCategorySerializer(read_only=True)
class Meta:
model = Meal
def get_meal(self, obj):
print('object of meal',obj)
instance = MealCategory.objects.get(slug=str(obj.slug))
meal_qs = instance.meal_set.filter(available=True)
meal = MealSerializer(meal_qs, many=True).data
return meal
class RestaurantSerializer(ModelSerializer):
owner = SerializerMethodField()
meal = SerializerMethodField()
class Meta:
model = Restaurant
read_only = ('id',)
def get_owner(self, obj):
return str(obj.owner)
def get_meal(self, obj):
print('object of meal',obj)
restaurant = Restaurant.objects.get(slug=str(obj.slug))
meal_qs = restaurant.meal_set.filter(available=True)
meal = MealSerializer(meal_qs, many=True).data
return meal
my API right now looks like this
"meal": [
{
"id": 1,
"meal_category": {
"id": 1,
"name": "veg",
"slug": "veg"
},
"name": "Mushroom drumstick",
"slug": "mushroom-drumstick",
},
{
"id": 2,
"meal_category": {
"id": 2,
"name": "Non-veg",
"slug": "non-veg"
},
"name": "Ham Cheesy Burger",
"slug": "ham-cheesy-burger",
"restaurant": 1
}
],
"name": "Kathmandu Fast Food Center",
"slug": "kathmandu-fast-food-center",
But I want meal to be shown like this
{
"id":1,
"name":"kathmandu fast food center",
"slug": "kathmandu-fast-food-center",
"meal_category":[
{
"Non veg":[
"meal":[
{
"name":"Ham Burger"
},
{
"name":"Chicken BBQ"
}
]
],
"Veg":[
"meal":[
{
"name":"mushroom soup"
},
{
"name":"Aloo Drumstick"
}
]
]
}
]
}
Please guide me how can i design such API.
Related
I have the following models
class Product(models.Model):
name = models.CharField(null=True, blank=True, max_length=500)
category = models.CharField(null=True, blank=True, max_length=120)
class SpecificationName(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE, null=True, related_name='specifications')
name = models.CharField(max_length=125)
class Attribute(models.Model):
spec_name = models.ForeignKey(SpecificationName, on_delete=models.CASCADE, null=True, related_name='attributes')
index = models.CharField(max_length=200, blank=True, null=True)
value = models.CharField(max_length=250, blank=True, null=True)
after saving objects in Django admin I have an example
{
"name": "Apple Smart Watch",
"category": "IT",
"specifications": [
{
"name": "Test Data",
"attributes": [
{
"index": "test",
"value": "test2"
},
{
"index": "test7",
"value": "test8"
},
{
"index": "test9",
"value": "test10"
}
]
},
{
"name": "Test Data Continued",
"attributes": [
{
"index": "bla",
"value": "bla1"
},
{
"index": "bla 2",
"value": "bla 4"
},
{
"index": "test9",
"value": "test10"
}
]
},
{
"name": "Test Spec",
"attributes": []
}
]
}
I need to save this kind of object with one request but I am failing to do this
my serializer looks like this
class ProductSerializer(serializers.ModelSerializer):
specifications = SpecNameSerializer(many=True)
# attributes = AttributeSerializer(many=True, required=False)
class Meta:
model = Product
fields = ['name', 'category', 'brand', 'price', 'specifications']
def create(self, validated_data):
specs = validated_data.pop('specifications')
instance = Product.objects.create(**validated_data)
for spec in specs:
SpecificationName.objects.create(product=instance, **spec)
print(spec)
return instance
with this code, I am getting the following result but not as expected
{
"name": "Appel watch series",
"specifications": [
{
"name": "Test Data",
"attributes": []
},
{
"name": "Test Data comn",
"attributes": []
},
{
"name": "Test Spec",
"attributes": []
}
]
}
it cannot write into attributes
I searched for many answers but I did not find or applied some of them, again it did not help me. I am using just ListCreateView in the views. Please is there anybody who can help solve this problem. Thanks in advance!
SOLVED
I am using here ModelSerializer instead I used Serializer and added some changes here my answer and it worked
class AttributeSerializer(serializers.Serializer):
index = serializers.CharField(max_length=200)
value = serializers.CharField(max_length=200)
class SpecNameSerializer(serializers.ModelSerializer):
attributes = AttributeSerializer(many=True)
class Meta:
model = SpecificationName
fields = '__all__'
class ProductSerializer(serializers.ModelSerializer):
specifications = SpecNameSerializer(many=True)
class Meta:
model = Product
fields = ['name', 'category', 'brand', 'price', 'specifications']
def create(self, validated_data):
specs = validated_data.pop('specifications')
instance = Product.objects.create(**validated_data)
for spec in specs:
SpecificationName.objects.create(product=instance, **spec)
attrs = spec.pop('attributes')
for attr in attrs:
Attribute.objects.create(spec_name=spec, **attr)
return instance
I am having difficulties in implementing nested serializers in Django REST Framework.
I'm building an Online score board, for which I currently have three models and I'm trying to serialize it into a single response.
models.py
class Player(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
def __str__(self):
return self.first_name
class Event(models.Model):
user = models.ManyToManyField("Player")
name = models.CharField(max_length=50)
desc = models.CharField(max_length=225)
def __str__(self):
return self.name
class LeadBoard(models.Model):
"""model for LeadBoard"""
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='leadboard_player', null=True, blank=True)
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='leadboard_event', null=True, blank=True)
score = models.IntegerField()
def __str__(self):
return self.score
The event model represent some kind of sports events and each Event can have multiple Players (user filed in Event model), the LeadBoard model stores the score of players in each event.
serializer.py
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('id','first_name', 'last_name', 'bio')
class EventSerializer(serializers.ModelSerializer):
user = PlayerSerializer(read_only=True, many=True)
class Meta:
model = Event
fields = ('id', 'name', 'user', 'desc')
class LeadBoardSerializer(serializers.ModelSerializer):
event = EventSerializer(read_only=True)
class Meta:
model = LeadBoard
fields = ('id', 'event', 'score')
I have added two Players
[
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe"
}
]
and their scores in LeadBoard model
[
{
"id": 1,
"player": 1,
"event": 1,
"score": 20
},
{
"id": 2,
"player": 3,
"event": 1,
"score": 90
}
]
This is the response of LeadBoard,
[
{
"id": 1,
"event": {
"id": 1,
"name": "event2020",
"user": [
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe"
}
],
"desc": "event description"
},
"score": 20
},
{
"id": 2,
"event": {
"id": 1,
"name": "event2020",
"user": [
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe"
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe"
}
],
"desc": "event description"
},
"score": 90
}
]
But what I'm expecting to get is a response like this, which returns the Players(users) of events and their scores correctly.
[
{
"id": 1,
"event": {
"id": 1,
"name": "event2020",
"user": [
{
"id": 1,
"first_name": "Jhon",
"last_name": "Doe",
"score": 20
},
{
"id": 3,
"first_name": "Anna",
"last_name": "Doe",
"score": 90
}
],
"desc": "event description"
}
}
]
What am I missing here?
I'm new to Django and Django Rest Framework.
You need make response by event not by leadboard.
class PlayerSerializer(serializers.ModelSerializer):
class Meta:
model = Player
fields = ('id','first_name', 'last_name', 'bio')
class LeadBoardSerializer(serializers.ModelSerializer):
player = PlayerSerializer(read_only=True)
class Meta:
model = LeadBoard
fields = ('id', 'player', 'score')
class EventSerializer(serializers.ModelSerializer):
leadboard_event = LeadBoardSerializer(read_only=True, many=True)
class Meta:
model = Event
fields = ('id', 'name', 'desc', 'leadboard_event')
now use view to get event list
Update 1
if you want get score in player.
class PlayerSerializer(serializers.Serializer):
player_id = serializers.IntegerField()
first_name = serializers.CharField(max_length=256)
last_name = serializers.CharField(max_length=256)
score = serializers.IntegerField()
class LeadBoardSerializer(serializers.ModelSerializer):
player = serializers.SerializerMethodField()
class Meta:
model = LeadBoard
fields = ('id', 'player')
def get_player(self,obj):
player_dict = {'player_id': obj.player.id, 'first_name': obj.player.first_name, 'last_name': obj.player.last_name, 'score': obj.score}
result = PlayerSerializer(data=player_dict)
return result
class EventSerializer(serializers.ModelSerializer):
leadboard_event = LeadBoardSerializer(read_only=True, many=True)
class Meta:
model = Event
fields = ('id', 'name', 'desc', 'leadboard_event')
Try it.
I'm having a problem with displaying the data during serialization.
This is my model:
from django.db import models
class Paradigmn(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Language(models.Model):
name = models.CharField(max_length=50)
paradigm = models.ForeignKey(Paradigmn, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Programmer(models.Model):
name = models.CharField(max_length=50)
languages = models.ManyToManyField(Language, related_name='languages')
def __str__(self):
return self.name
And this is my serializer:
from languages.models import Language, Paradigmn, Programmer
class LanguageSerializer(serializers.ModelSerializer):
paradigms = serializers.ReadOnlyField(source='paradigm.name')
class Meta:
model = Language
fields = ('id', 'name', 'paradigms')
class ParadigmnSerializer(serializers.ModelSerializer):
class Meta:
model = Paradigmn
fields = ('id', 'name',)
class ProgrammerSerializer(serializers.ModelSerializer):
languages = LanguageSerializer(many=True, read_only=True)
class Meta:
model = Programmer
fields = ('id', 'name', 'languages')
And this is the result:
[
{
"id": 1,
"name": "Ryan",
"languages": [
{
"id": 1,
"name": "Java",
"paradigms": "Object-Oriented"
}
]
},
{
"id": 2,
"name": "Jean",
"languages": [
{
"id": 3,
"name": "Python",
"paradigms": "Object-Oriented"
}
]
},
{
"id": 3,
"name": "Michael",
"languages": [
{
"id": 2,
"name": "Elixir",
"paradigms": "Functional"
}
]
}
I just want to show on the languages array, the name of the language instead of the all the details of the language array. What is the best solution for this?
One solution:
from rest_framework.serializers import SerializerMethodField
class ProgrammerSerializer(serializers.ModelSerializer):
languagelist = SerializerMethodField()
def get_languagelist(self, obj):
return [{'name': i.name} for i in obj.languages.all()]
class Meta:
model = Programmer
fields = ('id', 'name', 'languagelist')
I'm trying to return a Response including data from 2 linked models, where I can get a specific field value from another model. The models are:
class Author(models.Model):
author = models.CharField(max_length=200)
author_created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('author_created',)
class Book(models.Model):
book_name = models.CharField(max_length=200)
author_name = models.ForeignKey(Author, on_delete=models.CASCADE)
book_created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('book_created',)
Serializers are:
class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = Author
fields = ('id', 'author')
class BookSerializer(serializers.ModelSerializer):
name = AuthorSerializer(source='author_name')
class Meta:
model = Book
fields = ('id', 'book_name','name')
My response shows like this:
[
{
"id": 1,
"book_name": "Himu",
"name": {
"id": 1,
"author": "Humayun Ahmed"
}
},
{
"id": 2,
"book_name": "Shanta's family",
"name": {
"id": 2,
"author": "Jafar Iqbal"
}
}
]
But i want to show it like this:
[
{
"id": 1,
"book_name": "Himu",
"name": {
"author": "Humayun Ahmed"
}
},
{
"id": 2,
"book_name": "Shanta's family",
"name": {
"author": "Jafar Iqbal"
}
}
]
How can i get this output?
Try something like this name = AuthorSerializer(source='author_name.author')
Reference : http://www.django-rest-framework.org/api-guide/fields/#source
I am having problems serializing my items/orders with quantity.
Results I am getting:
{
"id": 1,
"_current_status": null,
"orderitem_set": [
{
"item_id": 2,
"quantity": 5
},
{
"item_id": 1,
"quantity": 1
}
],
"items": [
{
"id": 2,
"name": "Blue Shoe",
"description": "Sweet blue shoe bro",
"weight": "99.99",
"price": "99.99"
},
{
"id": 1,
"name": "Red Shoe",
"description": "sweet red shoe bro",
"weight": "1.00",
"price": "100.00"
}
],
"_last_modified": "2015-06-10T22:32:08.007833Z",
"_weight": "500.95",
"_total_price": "599.95",
"placed": false,
"date_placed": null
}
Results I want:
{
"id": 1,
"_current_status": null,
"items": [
{
"id": 2,
"name": "Blue Shoe",
"description": "Sweet blue shoe bro",
"weight": "99.99",
"price": "99.99",
"quantity": 5
},
{
"id": 1,
"name": "Red Shoe",
"description": "sweet red shoe bro",
"weight": "1.00",
"price": "100.00",
"quantity": 1
}
],
"_last_modified": "2015-06-10T22:32:08.007833Z",
"_weight": "500.95",
"_total_price": "599.95",
"placed": false,
"date_placed": null
}
Classes
class Order(models.Model):
_current_status = models.ForeignKey("main.Status", blank=True, null=True)
_last_modified = models.DateTimeField(auto_now=True)
_weight = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
_total_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
user = models.ForeignKey("main.ShopUser")
items = models.ManyToManyField("main.Item", through='main.OrderItem')
placed = models.BooleanField(default=False)
date_placed = models.DateTimeField(null=True, blank=True)
class OrderItem(models.Model):
order = models.ForeignKey('main.Order')
item = models.ForeignKey('main.Item')
quantity = models.IntegerField(default=1)
Serializers
I realize that my serializer is what is putting the orderitem_set into my json but I couldn't figure out how to get the quantity data into items other than in a custom view that loops through the items and the orderitem_set and adds a quantity to items. But that is just terrible and I was hoping there was a way to do this with the built in stuff with the framework or at least make it so I don't have to do that for every view.
class OrderItemField(serializers.RelatedField):
def to_representation(self, value):
return {'item_id': value.item_id, 'quantity': value.quantity}
class OrderSerializer(serializers.ModelSerializer):
_current_status = StatusSerializer(required=False, many=False)
orderitem_set = OrderItemField(read_only=True, many=True)
items = ItemSerializer(required=True, many=True)
class Meta:
model = Order
exclude = ('user',)
The view
This view gives me what I am looking for, but it is just terrible. Especially when I have other views that would be giving me a list of orders vs just a single order.
def set_quantities(data):
# Gets the quantity for each item and then appends it to each item instead of having 'orderitem_set'
for order_item in data['orderitem_set']:
for item in data['items']:
if item['id'] == order_item['item_id']:
item['quantity'] = order_item['quantity']
del data['orderitem_set']
return data
def get(self, request, *args, **kwargs):
serializer = self.get_serializer(self.get_object())
data = set_quantities(serializer.data)
return Response(data, status=status.HTTP_200_OK)
By changing the OrderSerializer items field to be an OrderItemField I was able to get back to root Order by using self.root.instance and then using that in conjuction with the value, which is an Item instance, build a query to find the OrderItem object to get the quantity. Then I can get a serialized Item using my ItemSerializer and just append the quantity to that data.
Doing it this way applies to all of my order views and it is a lot less messy. If there is a better way please let me know!
Serializers
class OrderItemField(serializers.RelatedField):
def to_representation(self, value):
if type(self.root.instance) == list:
self.root.instance = self.root.instance[0]
order_item = OrderItem.objects.filter(item=value, order=self.root.instance).first()
quantity = order_item.quantity
value = ItemSerializer(value).data
value['quantity'] = quantity
return value
class OrderSerializer(serializers.ModelSerializer):
_current_status = StatusSerializer(required=False, many=False)
items = OrderItemField(many=True, read_only=True)
class Meta:
model = Order
exclude = ('user',)
You can just use it like this:
class OrderItemSerializer(serializers.ModelSerializer):
class Meta:
model = Order.items.through
fields = ('order', 'item', 'quantity')
class OrderSerializer(serializers.ModelSerializer):
items = OrderItemSerializer(source='orderitem_set', many=True)
class Meta:
model = Order
fields = ('your_order_fields', 'items')
Note: you have to add items field into OrderSerializer.