modes.py
class Product(models.Model):
product_name = models.CharField(max_length=32)
quantity = models.IntegerField()
remarks = models.TextField(blank=True)
class Vendor(models.Model):
vendor_name = models.CharField(max_length=50)
address = models.CharField(max_length=100)
bill_no = models.CharField(max_length=8)
product = models.ManyToManyField(Product)
serializers.py
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class VendorSerializer(serializers.ModelSerializer):
product = ProductSerializer(many=True, read_only=False)
class Meta:
model = Vendor
fields = '__all__'
def create(self, validate_data):
product_data = validate_data.pop('product')
vendor = Vendor.objects.create(**validate_data)
for product_data in product_data:
Product.objects.create(vendor=vendor, **product_data)
return Vendor
views.py
class VendorViewset(viewsets.ModelViewset):
serializer_class = VendorSerializer
queryset = Vendor.objects.all()
How should I write product view such that It can be demonstrated that products of certain vendor can only be viewed with url routing?
you can use the #detail_route:
from rest_framework.decorators import detail_route
class VendorViewset(viewsets.ModelViewset):
serializer_class = VendorSerializer
queryset = Vendor.objects.all()
#detail_route(methods=['GET'])
def products(request, pk=None):
qs = self.get_object().product.all()
serializer = ProductSerializer(qs, many=True)
return Response(serializer.data)
and then the vendor products will be available by
YOUCURRENT_PATH_TO_DETAIL_VENDOR/products
Related
I have two models created in Django. I am trying to send post request from react frontend using axios API call.
My react is working fine and I can post request using category id but not with category name ( either hardcoded or from the dropdown list)
I tried using Postman, I get the same result.
class Category(models.Model):
name = models.CharField(max_length=50)
slug = models.SlugField(unique=True, null=True, blank=True)
def save(self,*args, **kwargs):
self.slug = slugify(self.name)
super(Category, self).save(*args, **kwargs)
def __str__(self):
return self.name
class Product(models.Model):
upc = models.CharField(max_length=30)
name = models.CharField(max_length=100)
description = models.TextField(max_length=255)
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True)
quantity = models.IntegerField()
price = models.IntegerField()
def __str__(self):
return self.name
views.py
from .models import Product
from .serializers import ProductSerializers
from rest_framework import generics
class ProductList(generics.ListCreateAPIView):
serializer_class = ProductSerializers
def get_queryset(self):
queryset = Product.objects.all()
return queryset
class ProductDetail(generics.RetrieveUpdateDestroyAPIView):
serializer_class = ProductSerializers
queryset = Product.objects.all()
Serializers.py
from .models import Product, Category
from rest_framework import serializers
class CategorySerializers(serializers.ModelSerializer):
class Meta:
model = Category
fields="__all__"
class ProductSerializers(serializers.ModelSerializer):
category_name = serializers.SerializerMethodField('get_category_name')
def get_category_name(self, obj):
if obj.category_id:
return obj.category.name
class Meta:
model = Product
fields = '__all__'
I am sending post request from react axios.
axios.post(productListURL, data)
How do I send post request with category name:
name:"Coca Cola" ,
category:"Beverage"
Instead of
name: "Coca Cola",
category: 1
Use this as the Product serializer
class ProductSerializers(serializers.ModelSerializer):
category = serializers.SlugRelatedField(
queryset=Category.objects.all(), slug_field="name"
)
class Meta:
model = Product
fields =['upc','name','description','category,'quantity','price']
i am working on ecommerce shop and in my home page i want to return all the products and 7 images for the icons for the categories , my models.py is
class Product(models.Model):
pub_date = models.DateTimeField(default=datetime.now)
price = models.DecimalField(max_digits=100,decimal_places=2,null=False,blank=False)
category = models.CharField(max_length=20 ,blank=False, null=False ,default='none', choices=cat)
product_name = models.CharField(max_length = 50, null=True)
photo = models.ImageField(upload_to = 'product_photos/%y/%m/%d',null=True)
class Category(models.Model):
icon = models.ImageField(upload_to = 'icon',null=True)
and my serializers.py is
class ProductSerializer (serializers.ModelSerializer):
class Meta :
model = Product
fields = '__all__'
class CategorySerializer (serializers.ModelSerializer):
class Meta :
model = Category
fields = '__all__'
and my views.py
#api_view(['GET'])
#permission_classes ([AllowAny] , )
def home (request):
p = Product.objects.filter(is_discount= 1).order_by('-pub_date')
serializer = ProductSerializer(p,many=True)
return Response (serializer.data)
how to return both the category and product in the same view , NOTE : my views.py is function based view
In my project, the relationship between Product and Group is ManytoOne.
When I tried to post a new product, it cannot work.
I'm sure there are more issues with this code and I will appreciate a detailed answer, because I am new to Django and Python. Thank you in advance.
models.py
class Group(models.Model):
productType = models.CharField(max_length=100)
intervalTime = models.IntegerField()
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True,editable=False)
def __str__(self):
return self.productType
class Product(models.Model):
productName = models.CharField(max_length=255)
color = models.CharField(max_length=255)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
created = models.DateTimeField(auto_now_add=True)
id = models.UUIDField(default=uuid.uuid4, unique=True, primary_key=True,editable=False)
def __str__(self):
return self.productName
serializers.py
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = ('id','productType','intervalTime')
class ProductSerializer(serializers.ModelSerializer):
group = GroupSerializer(many=False)
class Meta:
model = Product
fields = ('id','productName','color','group')
def create(self, validated_data):
group = validated_data.pop('group')
product = Product.objects.create(**validated_data)
for group_instance in group:
Group.objects.create(**group_instance, product=product)
return product
views.py
#api_view(['POST'])
def createProduct(request):
serializer = ProductSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
First change serializers.py:
class GroupSerializer(serializers.ModelSerializer):
class Meta:
model = Group
fields = ('id','productType','intervalTime')
class ProductInfoSerializer(serializers.ModelSerializer):
group = GroupSerializer(read_only=True)
class Meta:
model = Product
fields = ('id','productName','color','group')
class ProductCreationSerializer(serializers.ModelSerializer):
group = serializers.SlugRelatedField(slug_field='productType', queryset=Group.objects.all())
class Meta:
model = Product
fields = ('productName','color','group')
Then change views.py:
from rest_framework import status
#api_view(['POST'])
def createProduct(request):
serializer = ProductCreationSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
instance = serializer.save()
return Response(status=status.HTTP_200_OK, data=ProductInfoSerializer(instance=instance).data)
I have these Models Below
class Campaign(models.Model):
title = models.CharField(max_length=120)
img = models.ImageField(upload_to='products/')
def __str__(self):
return self.title
class Product(models.Model):
title = models.CharField(max_length=100)
data = models.DateField(auto_now_add=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
image = models.ImageField(upload_to="products/")
campaign = models.ForeignKey(Campaign, on_delete=models.DO_NOTHING, null=True, blank=True, related_name="products")
offer = models.ForeignKey(Offer, on_delete=models.DO_NOTHING, null=True, blank=True)
market_price = models.PositiveIntegerField()
selling_price = models.PositiveIntegerField()
description = models.TextField()
def __str__(self):
return self.title
I want to show campaign_wise products. But i cant find any solution for this. Though i tried reading the docs of DRF
Here is my Serializer
class CampaignProductsSerializer(serializers.ModelSerializer):
products = serializers.PrimaryKeyRelatedField(read_only=True, many=True)
class Meta:
model = Campaign
fields = ['title', 'products']
Whenever i try to run this i get 'Product' object has no attribute 'products'
Here is my URL
path('campaign_products/<int:id>/', CampaignProducts.as_view()),
Here is my View:
class CampaignProducts(APIView):
def get(self, request, id):
campaigns = Campaign.objects.all()
query = Product.objects.filter(campaign_id = id)
serializer = CampaignProductsSerializer(query, many=True)
return Response(serializer.data)
In that case you should make two serializers, one for the Product and one for the Campaign, so:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['title'] # etc.
class CampaignProductsSerializer(serializers.ModelSerializer):
products = ProductSerializer(read_only=True, many=True)
class Meta:
model = Campaign
fields = ['title', 'products']
In the view, you then serializer a Campaign:
from django.shortcuts import get_object_or_404
# returns the title of the campaign, and the products
class CampaignProducts(APIView):
def get(self, request, id):
campaign = get_object_or_404(Campaign, id=id)
serializer = CampaignProductsSerializer(campaign)
return Response(serializer.data)
In case you do not want to include the data of the campaign, we can work with the ProductSerializer:
# returns only the related products
class CampaignProducts(APIView):
def get(self, request, id):
products = Product.objects.filter(campaign_id=id)
serializer = ProductSerializer(products, many=True)
return Response({'data': serializer.data})
How can I filter the reverse relation queryset generated by a ModelViewSet without causing an additional n queries?
MRE:
models.py:
class Product(models.Model):
name = models.CharField(max_length=45)
image_url = models.URLField()
class Item(models.Model):
product = models.ForeignKey(Product, related_name='items', on_delete=models.CASCADE)
price = models.DecimalField(max_digits=10, decimal_places=2)
quantity = models.IntegerField()
views.py:
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.prefetch_related('items').all()
serializer_class = ProductSerializer
filter_backends = [filters.DjangoFilterBackend]
filter_class = ProductFilter
serializers.py:
class ItemSerializer(serializers.ModelSerializer):
class Meta:
model = Item
fields = '__all__'
class ProductSerializer(serializers.ModelSerializer):
items = ItemSerializer(many=True, read_only=True)
class Meta:
model = Product
fields = '__all__'
filters.py:
import django_filters as filters
class ProductFilter(filters.FilterSet):
price = filters.RangeFilter(field_name='items__price')
quantity = filters.RangeFilter(field_name='items__quantity')
class Meta:
model = Product
fields = {
'name': ['icontains'],
}
Filtering on the Product model's fields works fine, but the items reverse relation ignores the filtering completely.
I found a "solution" from this answer; ie. do the filtering via a SerializerMethodField:
item_fieldset = {'price', 'quantity'}
class ProductSerializer(serializers.ModelSerializer):
items = serializers.SerializerMethodField('get_items')
class Meta:
model = Product
fields = '__all__'
def get_items(self, product):
params = self.context['request'].query_params
filter_fields = item_fieldset.intersection(set(params))
filters = {field: params.get(field) for field in filter_fields}
serializer = ItemSerializer(instance=product.items.filter(**filters), many=True)
return serializer.data
But this cripples the performance of my app.
Is there a better way?