I have first made category crud, and then product crud with many-to-many relation with category.
models.py (category):
class Category(models.Model):
name = models.CharField(max_length=191, blank=False, null=False)
description = models.TextField(blank=True, null=True)
models.py (product):
class Product(models.Model):
product_code = models.CharField(max_length=191, blank=False, null=False)
name = models.CharField(max_length=191, blank=False, null=False)
description = models.TextField(blank=False, null=False)
price = models.DecimalField(max_digits=19, decimal_places=2)
photo = models.ImageField(upload_to='pictures/products/', max_length=255, null=False, blank=False)
category = models.name = models.ManyToManyField(Category)
How to achieve following result:
{
"categories": [
{
"id": 1,
"name": "Indoor Muscle Training",
"description": null,
"products":{
"name":"product_name",
"code":"product_code"
}
},
{
"id": 2,
"name": "Outdoor Muscle Training",
"description": null,
"products":{
"name":"product_name",
"code":"product_code"
}
}
]
}
using serializer-method field can be an option for this case. Our goal is get product information from category serializer. So for this
class CategorySerializer(serializers.ModelSerializer):
products = serializers.SerializerMethodField()
class Meta:
model = Category
fields = ('') # add relative fields
def get_products(self, obj):
products = obj.product_set.all() # will return product query set associate with this category
response = ProductSerializer(products, many=True).data
return response
Related
I have three models, as shown below:
class TagsModel(models.Model):
title = models.CharField(max_length=200)
def __str__(self):
return self.title
class ImagesModel(models.Model):
title = models.CharField(max_length=500, default='image')
image_cdn = models.TextField(null=True, blank=True)
image = models.ImageField(upload_to='articles/images/', null=True, blank=True)
timestamp = models.DateTimeField(auto_now=True)
update = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class ArticlesModel(models.Model):
title = models.CharField(max_length=1000)
category = models.CharField(max_length=40, choices=category_choices, default=('General', 'General'))
summary = models.TextField(blank=False, null=True, max_length=5000)
tags = models.ManyToManyField(TagsModel, blank=True)
image = models.ImageField(blank=True, null=True, upload_to='articles/article-image/')
image_cdn = models.TextField(blank=True, null=True)
image_src = models.ForeignKey(ImagesModel, related_name='Image_cdn', on_delete=models.PROTECT, null=True)
images = models.ManyToManyField(ImagesModel, blank=True)
json = models.JSONField(null=True, blank=True)
html = models.TextField(blank=True, null=True)
is_published = models.BooleanField(default=False)
update = models.DateTimeField(auto_now_add=True)
timestamp = models.DateTimeField(auto_now=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('articles:article_detail', kwargs={'article_id': self.id})
And in the view.py
class ArticlesView(APIView):
def get(self, request):
articles_list = ArticlesModel.objects.all()
images_list = ImagesModel.objects.all()
images_serializer = ImagesSerializer(images_list, many=True)
articles_serializer = ArticlesListSerializer(articles_list, many=True)
return Response({
'images':images_serializer.data,
'articles':articles_serializer.data
})
So when I send request I get results like this:
The problem here is that I get the ids of Images and tags and not the objects themselves!
I am asking if there's a way in django/DRF to get the objects (images, tags) included with the queries of Articles and not only their ids?
Solution
class ProductSerializer(serializers.ModelSerializer):
cate = serializers.SerializerMethodField('get_cate')
def get_cate(self,obj):
return [cate.name for cate in obj.cate.all()]
class Meta:
model = ProductModel
fields = "__all__"
Response output
[
{
"id": 1,
"cate": [
"Category5",
"Category6"
],
"name": "Apple",
"price": "12.00",
"released_at": "2022-10-18T13:16:01Z"
},
{
"id": 2,
"cate": [
"Category1",
"Category2",
"Category3"
],
"name": "Kiwi",
"price": "20.00",
"released_at": "2022-10-18T13:16:01Z"
},
{
"id": 3,
"cate": [
"Category2",
"Category4",
"Category5",
"Category6"
],
"name": "Tomato",
"price": "25.00",
"released_at": "2022-10-18T13:16:01Z"
}
]
This is called serializer relations, You can find the solution to your issue & more suggestions in this article https://www.django-rest-framework.org/api-guide/relations/
class School(models.Model):
name = models.CharField()
city = models.CharField()
street = models.CharField()
class Student(models.Model):
school_id = models.ForeignKey(School, on_delete=models.CASCADE)
first_name = models.CharField()
last_name = models.CharField()
I want to join two classes School and Student and get the number of students in these school, So I wrote this code in my serializers. but I got no resulte of number of students, only the two classes joined. Can someone help me?
serializers.py
from django.db.models import Count
class SchoolSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = School
fields = ['name']
class StudentSerializer(serializers.HyperlinkedModelSerializer):
school = SchoolSerializer()
school.objects.annotate(num_of_students=Count('student'))
class Meta:
model = Student
fields = ['first_name', 'last_name', 'school']
views.py
In my views I wrote the following code:
class StudentViewSet(viewsets.ModelViewSet):
serializer_class = StudentSerializer
queryset = Student.objects.all()
in your models.py add two method:
class School(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
city = models.CharField(max_length=100, null=False, blank=False)
street = models.CharField(max_length=100, null=False, blank=False)
def count_of_students(self):
return Student.objects.filter(school_id=self).count()
def students_in_school(self):
return list(Student.objects.filter(school_id=self))
def __str__(self):
return f"{self.city}->{self.street}->{self.name}"
class Student(models.Model):
school_id = models.ForeignKey(School, on_delete=models.CASCADE)
first_name = models.CharField(max_length=100, null=False, blank=False)
last_name = models.CharField(max_length=100, null=False, blank=False)
def __str__(self):
return f"{self.first_name} {self.last_name}"
and in your serializers.py
class StudentSerializer(serializers.Serializer):
first_name = serializers.CharField(max_length=100)
last_name = serializers.CharField(max_length=100)
class SchoolSerializer(serializers.Serializer):
count_of_students = serializers.IntegerField()
name = serializers.CharField(max_length=100)
students_in_school = StudentSerializer(many=True)
and in your views.py:
def get_school(request, id):
school = School.objects.get(pk=id)
serilizer = SchoolSerializer(school)
json = rest_framework.renderers.JSONRenderer().render(serilizer.data)
from django.http import HttpResponse
return HttpResponse(json, content_type='application/json')
and in your urls.py
path('schools/<int:id>',get_school)
as example data you can call enter link description here
and here is sample output:
{
"count_of_students":9,
"name":"S1",
"students_in_school":[
{
"first_name":"surname_1",
"last_name":"surname_{i}"
},
{
"first_name":"surname_2",
"last_name":"surname_{i}"
},
{
"first_name":"surname_3",
"last_name":"surname_{i}"
},
{
"first_name":"surname_4",
"last_name":"surname_{i}"
},
{
"first_name":"surname_5",
"last_name":"surname_{i}"
},
{
"first_name":"surname_6",
"last_name":"surname_{i}"
},
{
"first_name":"surname_7",
"last_name":"surname_{i}"
},
{
"first_name":"surname_8",
"last_name":"surname_{i}"
},
{
"first_name":"surname_9",
"last_name":"surname_{i}"
}
]
}
I'm using Django RestFramework to create a simple eCommerce API where one product could have many images and I would like to get the URLs of all these images on a json field.
For now, I got the first image url using "imagembicicleta_set.all.first.image.url" on the serializer, but I need all URLs list:
{
"count": 7,
"next": null,
"previous": null,
"results": [
{
"id": 1,
"nome": "Specialized Roubaix",
"marca__nome": "Specialized",
"categoria": "Bicicletas de Estrada",
"atividades": [
1
],
"terrenos": [
"Asfalto"
],
"preco": "16999.00",
"ano": 1,
"absolute_url": "/bicicletas/Specialized/specialized-roubaix-2020/",
"img_url": "/media/images/bicicletas/roubaix1.jpeg"
},
{
"id": 2,
"nome": "Specialized Roubaix Sport",
"marca__nome": "Specialized",
Following how is my setup:
Models.py
class Bicicleta(models.Model):
id = models.AutoField(primary_key=True)
nome = models.CharField(max_length=200, blank=False, null=False)
slug = models.SlugField(unique=True)
status = models.IntegerField(choices=STATUS_CHOICES, default=1, blank=False, null=False)
descricao = RichTextField(blank=True, null=True)
marca = models.ForeignKey(MarcaBicicleta, blank=True, null=True, on_delete=models.SET_NULL)
...
class ImagemBicicleta (models.Model):
bicicleta = models.ForeignKey(Bicicleta, default=None, on_delete=models.CASCADE)
image = models.ImageField(upload_to='images/bicicletas')
Serializer.py
class BicicletasSerializer(serializers.ModelSerializer):
marca__nome = serializers.CharField(source='marca.nome')
categoria = serializers.CharField(source='categoria.nome')
terrenos = serializers.StringRelatedField(many=True)
absolute_url = serializers.URLField(source='get_absolute_url', read_only=True)
img_url = serializers.URLField(source='imagembicicleta_set.all.first.image.url', read_only=True) #I could get the first image using this
class Meta:
model = Bicicleta
fields = ['id', 'nome', 'marca__nome', 'categoria', 'atividades', 'terrenos', 'preco', 'ano', 'absolute_url', 'img_url']
views.py
class BicicletasView(generics.ListAPIView):
serializer_class = BicicletasSerializer
queryset = Bicicleta.objects.all()
filter_backends = (DjangoFilterBackend, SearchFilter)
filterset_fields = ['marca', 'terrenos', 'status']
search_fields = {'nome': ['icontains'], }
How could I get all images URLs in the field?
Per example, if a product has 3 different images, I would expect to have the img field like this:
"img_url": [ "/media/images/bicicletas/roubaix1.jpeg","/media/images/bicicletas/roubaix2.jpeg","/media/images/bicicletas/roubaix3.jpeg" ],
You can add a method serializer which will collect all the urls for each individual object like this:
class BicicletasSerializer(serializers.ModelSerializer):
marca__nome = serializers.CharField(source='marca.nome')
categoria = serializers.CharField(source='categoria.nome')
terrenos = serializers.StringRelatedField(many=True)
absolute_url = serializers.URLField(source='get_absolute_url', read_only=True)
img_url = serializers.SerializerMethodField()
def get_image_url(self , instance):
return ImagemBicicleta.objects.filter(bicicleta=instance).values_list('image',flat=True)
class Meta:
model = Bicicleta
fields = ['id', 'nome', 'marca__nome', 'categoria', 'atividades', 'terrenos', 'preco', 'ano', 'absolute_url', 'img_url']
I am trying to get all the bills and their customer-related details (i.e. 'customer_code', 'email' etc.) with it.
However, source='user.customer_code does not seem to have any effect at all. What am I missing?
I have been following along this:
this stackoverflow post with no luck.
My two models:
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(db_index=True, unique=True, max_length=200)
customer_code = models.CharField(max_length=300, blank=True, null=True, default=None)
class Bill(models.Model):
customer = models.ForeignKey(
User, on_delete=models.CASCADE, blank=True, null=True, related_name="customer_bill"
)
payable_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
View:
class BillView(APIView):
def get(self, request, format=None):
q = Bill.objects.all().select_related('customer')
s = BillSerializer(q, many=True)
return JsonResponse({
"bill": s.data
})
Serializer:
class BillSerializer(serializers.ModelSerializer):
customer_code = serializers.CharField(source='user.customer_code', read_only=True)
class Meta:
model = Bill
fields = ('id','payable_amount','customer_code') # binding customer_code here
Current Output:
"bill": [
{
"id": 1,
"payable_amount": "1000.00"
},
{
"id": 2,
"payable_amount": "2000.00"
}
]
Expected Result:
"bill": [
{
"id": 1,
"payable_amount": "1000.00",
"customer_code": "CUS10001" # want this to be attached
},
{
"id": 2,
"payable_amount": "2000.00",
"customer_code": "CUS10002" # want this to be attached
}
]
I'm trying to make an API for a butcher.
With this API and the website that I will build by the next, the client will be able to make his order remotly.
Here is my probleme.
With the order form, the client send me JSON data like here :
{
"user": 8,
"orderDay": "2020-06-24",
"deliveryDay": "2020-06-30",
"deliveryAddress": "Place des FĂȘtes",
"comment": "",
"orderDetail":
[
{
"product": 2,
"byProduct": 2,
"quantity": 43
},
{
"product": 3,
"byProduct": 3,
"quantity": 5
}
]
}
These data must be saved in the database.
These are the models that I use : models.py
class order(models.Model):
user = models.ForeignKey(memberArea, on_delete=models.CASCADE)
comment = models.TextField(null=True, blank=True)
orderDay = models.DateTimeField(auto_now_add=True)
deliveryDay = models.DateField()
deliveryAddress = models.CharField(max_length=255)
state = models.CharField(max_length=255)
price = models.TextField(null=True, blank=True)
response = models.TextField(null=True, blank=True)
class orderDetail(models.Model):
order = models.ForeignKey(order, on_delete=models.CASCADE)
product = models.ForeignKey(product, on_delete=models.CASCADE)
byProduct = models.ForeignKey(byProduct, on_delete=models.CASCADE)
quantity = models.CharField(max_length=255)
class product(models.Model):
name = models.CharField(max_length=255)
prix_uni = models.TextField(null=True, blank=True)
prix_kg = models.TextField(null=True, blank=True)
dispo = models.BooleanField(null=True, blank=True)
category = models.ForeignKey(category, on_delete=models.CASCADE)
redu = models.TextField(null=True, blank=True)
class byProduct(models.Model):
product = models.ForeignKey(product, on_delete = models.CASCADE)
name = models.CharField(max_length=255)
I make a serializer file like this serializer.py
class orderDetailSerializer(serializers.ModelSerializer):
order = serializers.PrimaryKeyRelatedField(many=False, queryset = order.objects.all())
class Meta:
model = orderDetail
fields = '__all__'
class OrderSerializer(serializers.ModelSerializer):
orderDetail = orderDetailSerializer(many=True)
class Meta:
model = order
fields = ['user', 'comment', 'deliveryAddress', 'deliveryDay', 'orderDetail']
def create(self, validated_data):
order_detail_data = validated_data.pop('orderDetail')
new_order = order.objects.create(**validated_data)
new_order.save()
for product in order_detail_data:
order_detail = orderDetail.objects.create(order=new_order, **product)
new_order.orderDetail.add(order_detail.id)
return new_order
And this is my view : views.py:
#Make an order
#api_view(['POST'])
def order(request, format=None):
if request.method == 'POST':
serializer = OrderSerializer(data=request.data)
data = {}
if serializer.is_valid():
serializer.save()
data['response'] = "Your order went well"
return Response(data)
return Response(serializer.errors)
When I try to run my code, it tells me that the order data is missing :
{
"orderDetail": [
{
"order": [
"This field is required."
]
},
{
"order": [
"This field is required."
]
}
]
}
I don't know how to add this because the order_id that I need is created at the same time that the orderDetail.
Thank's by advance for helping me.
you should make order field readonly in orderDetailSerializer:
class orderDetailSerializer(serializers.ModelSerializer):
class Meta:
model = orderDetail
fields = '__all__'
read_only_fields = ('order',)