Django Rest Framework relationship queries in nested serializer - python

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.

Related

How to GET multipule ModelSrializer in one APIVIEW using Django Rest Framework

I have UserModel each user has multiple package and each package have price and program.
model.py:
class User(models.Model):
name= models.CharField(max_length=100)
class Package(models.Model):
package_name = models.CharField(max_length=100)
user= models.ForeignKey(User, on_delete=models.CASCADE,related_name='user_package')
class Program(models.Model):
title = models.CharField(max_length=100)
user_package = models.ForeignKey(Package, on_delete=models.CASCADE)
class Price(models.Model):
price = models.FloatField()
user_package = models.ForeignKey(Package, on_delete=models.CASCADE)
serializer look like:
class UserSerializer(NestedCreateMixin, NestedUpdateMixin,serializers.ModelSerializer):
program = ProgramSerializer(source='user_program', many=True, read_only=True)
package = PackageSerializer(source='user_package', many=True, read_only=True)
price = PriceSerializer(source='price', many=True, read_only=True)
class Meta:
model = User
fields= ("__all__")
views.py:
class user_apiView(APIView):
def get(self, request):
user= user.objects.all()
serializer = UserSerializer(user, many = True)
return Response(serializer.data)
and that what I get:
{
"id": 1,
"package": [
{
"id": 1,
"package_name": "wfe",
"user": 1
},
{
"id": 2,
"package_name": "wfe",
"user": 1
}
]
}
how can GET this RESULT?
{
"id": 1,
"package": [
{
"id": 1,
"package_name": "wfe",
"user": 1
},
{
"id": 2,
"package_name": "wfe",
"user": 1
}
],
"price": [
{
"id": 1,
"price": "wfe",
"package": 1
},
{
"id": 2,
"price": "wfe",
"package": 2
}
]
"program": [
{
"id": 1,
"title": "wfe",
"package": 1
},
{
"id": 2,
"title": "wfe",
"package": 2
}
]
}
The problem is that your price and program models are not directly related to your user model. If you consider the relations it is like price -> package -> user, so you will have to get those relations in the package serializer instead like this
serializers.py
class ProgramSerializer(serializers.ModelSerializer):
class Meta:
model = Program
fields= ("__all__")
class PriceSerializer(serializers.ModelSerializer):
class Meta:
model = Price
fields= ("__all__")
class PackageSerializer(serializers.ModelSerializer):
program = ProgramSerializer(source='program_set', many=True, read_only=True)
price = PriceSerializer(source='price_set', many=True, read_only=True)
class Meta:
model = Package
fields= ("__all__")
class UserSerializer(serializers.ModelSerializer):
package = PackageSerializer(source='user_package', many=True, read_only=True)
class Meta:
model = User
fields= ("__all__")
Note that this will however not give you the output in the format you mentioned though, the price and program fields will instead be nested under package.
[
{
"id": 1,
"package": [
{
"id": 1,
"program": [
{
"id": 1,
"title": "program1",
"user_package": 1
}
],
"price": [
{
"id": 1,
"price": 1000.0,
"user_package": 1
}
],
"package_name": "package1",
"user": 1
},
{
"id": 2,
"program": [
{
"id": 2,
"title": "program2",
"user_package": 2
}
],
"price": [
{
"id": 2,
"price": 1500.0,
"user_package": 2
}
],
"package_name": "package2",
"user": 1
}
],
"name": "user1"
}
]
If you really want the format in the way you posted you might instead want to take a look at https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

ManyToManyField value in Django REST Framework

So when I am routing to api/ to view my models I am not seeing what I expected to see.
I wanted to see the names of the strats that I grouped in Strat_Basket model in the variable basket but instead I see their ids which is generated by DJANGO automatically.
I want to see the names rather than numbers in the strat_basket view. It is more informative that's why.
models.py
class Strats(models.Model):
name = models.CharField(max_length=64)
class Strats_Basket(models.Model):
name = models.CharField(max_length=64)
basket = models.ManyToManyField(Strats, blank=True, related_name='list')
serializers.py:
class StratsSerializer(serializers.ModelSerializer):
class Meta:
model = Strats
fields = ('id', 'name')
class Strats_BasketSerializer(serializers.ModelSerializer):
class Meta:
model = Strats_Basket
fields = ('id', 'name', 'basket')
views.py:
class StratsView(viewsets.ModelViewSet):
serializer_class = StratsSerializer
queryset = Strats.objects.all()
class Strats_BasketView(viewsets.ModelViewSet):
serializer_class = Strats_BasketSerializer
queryset = Strats_Basket.objects.all()
urls.py:
router = routers.DefaultRouter()
router.register(r'strats', views.StratsView, 'strats')
router.register(r'strats_basket', views.Strats_BasketView, 'strats_basket')
API OUTPUT:
strats:
[
{
"id": 1,
"name": "strat1"
},
{
"id": 2,
"name": "strat2"
},
{
"id": 3,
"name": "strat3"
},
{
"id": 4,
"name": "strat4"
},
{
"id": 5,
"name": "strat5"
},
{
"id": 6,
"name": "strat6"
}
]
strats_basket:
Instead of 1,2,4 I want to see strat1, strat2, strat4.
[
{
"id": 1,
"name": "Basket 1",
"basket": [
1,
2,
4
]
},
{
"id": 2,
"name": "Basket 2",
"basket": [
3,
5,
6
]
}
]
You can use SerializerMethodField and inside the method return names list using values_list with flat=True
class Strats_BasketSerializer(serializers.ModelSerializer):
basket = serializers.SerializerMethodField()
def get_basket(self, obj):
return obj.basket.all().values_list('name', flat=True)
class Meta:
model = Strats_Basket
fields = ('id', 'name', 'basket')

Source field in DRF serializer with multiple foreign keys to the same model

I have a Django model as follows:
class Team(models.Model):
name = models.CharField(max_length=100, unique=True)
managers = models.ManyToManyField(User, through=MgrToTeam, related_name='mng')
users = models.ManyToManyField(User, through=UsrToTeam,related_name='usr')
I now have a serializer where i need to display all the users and managers associated with a team:
class TeamDetailSerializer(serializers.ModelSerializer):
managers = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='name')
users = serializers.SlugRelatedField(queryset=User.objects.all(), slug_field='name')
class Meta:
model = Team
fields = ['id', 'name', 'managers', 'users']
However, this gives me the same output for both the users and managers.How do i fix this ?
I'm curious as to why you want to use a SlugRelatedField. Assuming you do have a UserSerializer of some sort, would it work for you to do it like this?
class TeamDetailSerializer(serializers.ModelSerializer):
managers = UserSerializer(many=True)
users = UserSerializer(many=True)
class Meta:
model = Team
fields = ['id', 'name', 'managers', 'users']
if you just want Just primary key as below
[
{
"id": 1,
"name": "helo",
"users": [
1,
2
],
"managers":[
1,
2,
]
}
]
class TeamDetailSerializer(serializers.ModelSerializer):
class Meta:
model = Team
fields = ['id', 'name', 'users','managers']
if you want return object properties as below
[
{
"id": 1,
"name": "helo",
"users": [
{
"email": "admin#gmail.com",
"first_name": ""
},
{
"email": "admin1#gmail.com",
"first_name": ""
}
],
"managers": [
{
"email": "admin#gmail.com",
"first_name": ""
},
{
"email": "admin1#gmail.com",
"first_name": ""
}
]
}
]
class TeamDetailSerializer(serializers.ModelSerializer):
users = UserDetailSerializer(many=True)
managers = UserDetailSerializer(many=True)
class Meta:
model = Team
fields = ['id', 'name', 'users', 'managers']

Serializer get RelatedField

Below is code of my serializers.py and model.py class
serializers.py
class SliderImageSerializers(serializers.ModelSerializer):
class Meta:
model=SliderImage
fields='url','rank'
class ItemVariationsSerializer(serializers.ModelSerializer):
# items = ItemsSerializer(many=True, read_only=True)
class Meta:
model = ItemVariation
fields ='price','item_code','image'
class RestaurantSerializers(serializers.ModelSerializer):
items = ItemVariationsSerializer(many=True, read_only=True)
sliders = SliderImageSerializers(many=True, read_only=True)
class Meta:
model=Restaurant
fields=('__all__')
models.py
class ItemVariation(models.Model):
restaurant=models.ForeignKey(Restaurant,on_delete=models.CASCADE)
item=models.ForeignKey(Item,on_delete=models.CASCADE)
price=models.IntegerField(blank=True,null=True,default=0)
item_code=models.CharField(max_length=500)
keyword= models.ManyToManyField(Keyword)
image=models.ImageField(upload_to='dishes/', blank=True, null=True)
def __str__(self):
return str(self.id)
Below is response that i received
response:
{
"id": 1,
"sliders": [
{
"url": "/media/restaurant/download_2.jpeg",
"rank": 1
}
],
"name": "Haveli",
"email": "test#tet.com",
"web": "wdew",
"short_description": "dsfsdf",
"description": "fsdfsd",
"phone": 21315,
"lat": 30.704649,
"lng": 76.717873,
"address1": "dsff",
"address2": "vfdg",
"city": "sdfds",
"state": "fs",
"postalcode": "sdfsd",
"avg_rating": 1,
"price": 0,
"restaurant_type": 1,
"keywords": [
1,
2,
3
]
}
I need to add ItemVariationsSerializer to RestaurantSerializers response
but i need response like below
{
"id": 1,
"sliders": [
{
"url": "/media/restaurant/download_2.jpeg",
"rank": 1
}
],
"name": "Haveli",
"email": "test#tet.com",
"items":[
{
"price":"213"
"item_code":"testr"
}
]
"keywords": [
1,
2,
3
] }
I need your help to get needed response. Thanks

Django Rest Framework: Get related specific model field in serializer from another model

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

Categories