Related
I am using django and rest api. And I have two models:
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100)
images = models.ImageField(upload_to="photos/categories")
category = models.ForeignKey("Category", on_delete=models.CASCADE, related_name='part_of', blank=True, null=True)
date_create = models.DateTimeField(auto_now_add=True)
date_update = models.DateTimeField(auto_now=True)
description = models.TextField(max_length=1000, blank=True)
legislation = models.TextField(max_length=1000, blank=True)
review = models.TextField(max_length= 000, blank=True)
eaza = models.TextField(max_length=1000, blank=True)
class Meta:
verbose_name = "category"
verbose_name_plural = "categories"
def __str__(self):
return self.name
class Animal(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(max_length=100)
images = models.ImageField(upload_to="photos/categories")
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='animals')
date_create = models.DateTimeField(auto_now_add=True)
date_update = models.DateTimeField(auto_now=True)
description = models.TextField(max_length=1000, blank=True)
legislation = models.TextField(max_length=1000, blank=True)
review = models.TextField(max_length=1000, blank=True)
eaza = models.TextField(max_length=1000, blank=True)
class Meta:
verbose_name = "animal"
verbose_name_plural = "animals"
def __str__(self):
return self.name
And my serializer looks:
class AnimalSerializer(serializers.ModelSerializer):
class Meta:
model = Animal
fields = ['id','name', 'description']
class CategorySerializer(serializers.ModelSerializer):
animals = AnimalSerializer(many=True)
class Meta:
model = Category
fields = ['id','category_id','name', 'description', 'animals']
and views.py:
class CategoryViewSet(viewsets.ModelViewSet):
serializer_class = CategorySerializer
queryset = Category.objects.all()
#action(methods=['get'], detail=False)
def mainGroups(self,request):
mainGroups = Category.objects.filter(category_id__isnull=True)
serializer = self.get_serializer(mainGroups, many=True)
return Response(serializer.data)
and urls.py:
router = routers.DefaultRouter()
router.register('groups', CategoryViewSet)
urlpatterns = [
path('', include(router.urls))
]
So if I go to: http://127.0.0.1:8000/djangoadmin/groups/
I get as output:
[
{
"id": 11,
"category_id": null,
"name": "zoogdieren",
"description": "hoi",
"animals": []
},
{
"id": 12,
"category_id": null,
"name": "amfibieen",
"description": "kujhkjh",
"animals": []
},
{
"id": 13,
"category_id": null,
"name": "vogels",
"description": "kljhkjh",
"animals": []
},
{
"id": 16,
"category_id": 13,
"name": "roofvogels",
"description": "kljhkljjl",
"animals": []
},
{
"id": 17,
"category_id": 12,
"name": "kikkers",
"description": "kjhkjh",
"animals": []
},
{
"id": 21,
"category_id": null,
"name": "reptielen",
"description": "reptielen",
"animals": []
},
{
"id": 22,
"category_id": 21,
"name": "slangen",
"description": "slangen",
"animals": []
},
{
"id": 24,
"category_id": 11,
"name": "honden",
"description": "hhhh",
"animals": []
},
{
"id": 25,
"category_id": 11,
"name": "katten",
"description": "kjhkjh",
"animals": []
},
{
"id": 26,
"category_id": 11,
"name": "olifanten",
"description": "kjhkjhkjh",
"animals": []
},
{
"id": 27,
"category_id": 21,
"name": "krokodillen",
"description": "l;l;'ll;;'l",
"animals": []
},
{
"id": 28,
"category_id": 22,
"name": "cobra",
"description": "cobra",
"animals": [
{
"id": 4,
"name": "indian cobra",
"description": "cobra"
},
{
"id": 5,
"name": "cape cobra",
"description": "cape cobra"
},
{
"id": 6,
"name": "Chinese cobra",
"description": "Chinese cobra"
}
]
},
{
"id": 29,
"category_id": 16,
"name": "valken",
"description": "valken",
"animals": []
},
{
"id": 30,
"category_id": 16,
"name": "gieren",
"description": "Gieren",
"animals": []
},
{
"id": 31,
"category_id": 21,
"name": "aligatoren",
"description": "aligatoren",
"animals": []
},
{
"id": 32,
"category_id": 13,
"name": "meeuwen",
"description": "meeuwen",
"animals": []
},
{
"id": 33,
"category_id": 22,
"name": "droppel slangen",
"description": "droppel slangen",
"animals": []
}
]
So for example zoogdieren with id 11 has many linked categories:
honden category_id = 11
katten category_id = 11
Question:
How to make a query that will filter for example on name zoogdieren and then the api call will filter the referenced id's?
So for example you fill in: http://127.0.0.1:8000/djangoadmin/groups?name=zoogdieren and as output:
{
"id": 24,
"category_id": 11,
"name": "honden",
"description": "hhhh",
"animals": []
},
{
"id": 25,
"category_id": 11,
"name": "katten",
"description": "kjhkjh",
"animals": []
},
if I do this: http://127.0.0.1:8000/djangoadmin/groups/11/
I get the main category:
{
"id": 11,
"category_id": null,
"name": "zoogdieren",
"description": "hoi",
"animals": []
}
But I want to have the related entities with category_id 11
Now in http://127.0.0.1:8000/djangoadmin/groups/11/ you just getitem with id = 11. If you eant to get all items with category_id = 11, you just have to make smth like that: http://127.0.0.1:8000/djangoadmin/groups?category_id=11.
Models.py
class Cat_Breed_Detail(models.Model):
id = models.AutoField(primary_key=True,verbose_name="id")
key_name = models.CharField(max_length=35,default='',null=True,verbose_name="key_name")
display_name= models.CharField(max_length=35,default='',null=True,verbose_name="display_name")
def __str__(self):
return self.key_name
class Cat_Image(models.Model):
image=models.ImageField(upload_to="ImagesCat/")
cat=models.ForeignKey(Cat_Breed_Detail,on_delete=models.CASCADE,null=True,related_name='images')
def image_preview(self):
if self.image:
return mark_safe('<img src="{0}" width="150" height="150" />'.format(self.image.url))
else:
return '(No image)'
Selializer.py
class CatImageSerializer(serializers.ModelSerializer):
class Meta:
model = Cat_Image
fields = '__all__'
class CatDataSerializer(serializers.ModelSerializer):
class Meta:
model = Cat_Breed_Detail
fields = ['id','key_name','display_name','images']
View.py
class CatListCreate(ListAPIView):
queryset = CatBreedDetails.objects.all().order_by('key_name')
serializer_class = CatDataSerializer
pagination_class = CustomPagination
response i am getting here i am getting nested response i dont want it i just want image url in images as a list not like the response i am currently getting :
{
"id": 9,
"key_name": "abyssinian",
"display_name": "Abyssinian",
"image": [
{
"id": 3,
"image": "/media/Abyssinian_0006.jpg",
"cat": 9
},
{
"id": 4,
"image": "/media/Abyssinian_0092.jpg",
"cat": 9
}
]
},
{
"id": 18,
"key_name": "american_bobtail",
"display_name": "American Bobtail",
"image": [
{
"id": 5,
"image": "/media/American_Bobtail_0004.jpg",
"cat": 18
},
{
"id": 6,
"image": "/media/American_Bobtail_0057.png",
"cat": 18
}
]
},
{
"id": 19,
"key_name": "american_curl",
"display_name": "American Curl",
"image": [
{
"id": 7,
"image": "/media/American_Curl_0078.jpg",
"cat": 19
},
{
"id": 8,
"image": "/media/American_Curl_0083.png",
"cat": 19
}
]
}
i want to get all the images in one list not like image:{image:"...."
,image:"......"} i am new to djnago and still learning is there any way to make it done .
is there any way i can get response like that :
{
"id": 9,
"key_name": "abyssinian",
"display_name": "Abyssinian",
"image": ["/media/Abyssinian_0006.jpg","/media/Abyssinian_0092.jpg",]
}
[
{
"id": 1,
"key_name": "first cat",
"display_name": "first cat",
"images": [
{
"image": "http://localhost:8000/ImagesCat/Screenshot_from_2022-12-21_18-16-28.png"
},
{
"image": "http://localhost:8000/ImagesCat/Screenshot_from_2022-12-29_13-41-31.png"
}
]
}
]
this is how I get response if you want to make like yours then you have to override list method
from rest_framework import serializers
from app.models import Cat_Image, Cat_Breed_Detail
class CatImageSerializer(serializers.ModelSerializer):
class Meta:
model = Cat_Image
fields = '__all__'
class CatImageSerializer2(serializers.ModelSerializer):
class Meta:
model = Cat_Image
fields = ['image']
class CatDataSerializer(serializers.ModelSerializer):
images = CatImageSerializer2(read_only=True, many=True)
class Meta:
model = Cat_Breed_Detail
fields = ['id', 'key_name', 'display_name', 'images']
My serializers class
class ConditionSerializers(serializers.ModelSerializer):
class Meta:
model = TblCondition
fields = ['id','operator','condition','relation']
class ConditionSerializers(serializers.ModelSerializer):
relation_with=ConditionSerializers(many=False)
class Meta:
model = TblCondition
fields = ['id','operator','relation_with','condition','relation']
class RuleSerializers(serializers.ModelSerializer):
conditiontbl=ConditionSerializers(many=True)
class Meta:
model = TblRule
fields = ['rule_table_no','rule_no','rule_name','columns','data_file','true','conditiontbl' ]
My model class
class TblRule(models.Model):
rule_table_no=models.AutoField(primary_key=True)
rule_no=models.IntegerField(blank=False)
rule_name=models.CharField(max_length=100,blank=False)
columns=models.CharField(max_length=100)
data_file=models.CharField(max_length=100)
true=models.CharField(max_length=100)
class TblCondition(models.Model):
rule=models.ForeignKey(TblRule, on_delete=models.CASCADE,related_name='conditiontbl')
operator=models.CharField(max_length=100)
condition=models.CharField(max_length=100)
relation=models.CharField(max_length=50,blank=True)
relation_with=models.OneToOneField(to='self',null=True,blank=True,on_delete=models.CASCADE)
Getting these results in postman API by calling ruletbl models
[
{
"rule_table_no": 2,
"rule_no": 1,
"rule_name": "Age Discritization",
"columns": "Age",
"data_file": "Data1",
"true": "Teen",
"conditiontbl": [
{
"id": 4,
"operator": ">",
"relation_with": null,
"condition": "15",
"relation": ""
},
{
"id": 5,
"operator": "<=",
"relation_with": {
"id": 4,
"operator": ">",
"condition": "15",
"relation": ""
},
"condition": "25",
"relation": "and"
}
]
},
{
"rule_table_no": 3,
"rule_no": 1,
"rule_name": "Age Discritization",
"columns": "Age",
"data_file": "Data1",
"true": "Young",
"conditiontbl": []
}
]
Results I want :
[
{
"rule_table_no": 2,
"rule_no": 1,
"rule_name": "Age Discritization",
"columns": "Age",
"data_file": "Data1",
"true": "Teen",
"conditiontbl": [
{
"id": 7,
"operator": ">",
"relation_with": null,
"condition": "15",
"relation": ""
},
{
"id": 6,
"operator": "<=",
"relation_with": {
"id": 7,
"operator": ">",
"relation_with":
{
"id": 7,
"operator": ">",
"relation_with": null,
"condition": "15",
"relation": ""
},
"condition": "15",
"relation": "or"
},
"condition": "25",
"relation": "and"
}
]
},
{
"rule_table_no": 3,
"rule_no": 1,
"rule_name": "Age Discritization",
"columns": "Age",
"data_file": "Data1",
"true": "Young",
"conditiontbl": []
}
]
You can see conditiontbl list fileds in ruletbl model (e.g. in JASON results), inside conditiontbl filed we have objects of tblcondition models with fileds ("relation_with"), and this relation_with filed is again refering to its own tblcondition model you can see its second object. I want this refering in relation_with fileds to its own conditiontbl model to be recursive. Any solution ?
In Django, recursive serialization can be implemented by creating a custom serializer class that extends the BaseSerializer class and overrides the to_representation() method
from django.core.serializers import serialize
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from rest_framework import serializers
class Node(models.Model):
parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
value = models.CharField(max_length=255)
class NodeSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Node
fields = ('url', 'parent', 'value')
root = Node.objects.get(pk=1)
serialized_data = serialize('json', [root], cls=DjangoJSONEncoder)
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
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.