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})
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']
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'm building a small webstore , in the product page i put the order form using FormMixin and TemplateView, when i submit the order i get a "Direct assignment to the forward side of a many-to-many set is prohibited. Use product.set() instead." error
Bellow you can check the code
Models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255, unique=True, )
description = models.TextField(max_length=1500)
class Meta:
verbose_name_plural = "categories"
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
nominal_price = models.PositiveIntegerField(verbose_name='prix normal',)
reduced_price = models.PositiveIntegerField(blank=True, null=True)
quantity = models.PositiveIntegerField(default=10)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
photo = models.ImageField(upload_to="img/products/", default="img/products/user_default.png")
def __str__(self):
return self.name
class Customer(models.Model):
full_name = models.CharField(max_length=150)
address = models.CharField(max_length=1500, null=True)
phone = models.IntegerField()
city = models.CharField(max_length=100)
email = models.EmailField(null=True)
class Order (models.Model):
product = models.ManyToManyField(Product, through='OrderProduct')
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class OrderProduct(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
Views.py
class ProductDetailView(FormMixin, TemplateView):
model = Product
template_name = 'product.html'
form_class = OrderForm
def get_success_url(self):
return reverse('index')
def post(self, request, *args, **kwargs):
context = self.get_context_data()
form = OrderForm(request.POST)
if context['form'].is_valid():
product = get_object_or_404(Product, name=self.kwargs['product_name'])
customer = form.save()
Order.objects.create(product=product, customer=customer)
return super(TemplateView, self)
def get_context_data(self, **kwargs):
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['product'] = Product.objects.get(name=self.kwargs['product_name'])
context['form'] = self.get_form()
return context
urls.py
path('', views.ProductListView.as_view(), name='index'),
Did i missed something
For handling many-to-many relations, you cannot directly set the product from Order. Also you would need to create the order first before you can set or add a product:
order = Order.objects.create(customer=customer)
order.product.add(product)
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
Following are my files. It is simply adding products based on subcategories and categories. Everything is working fine but the data is not being saved in the database. I am not sure where I am going wrong.
models.py
from django.db import models
class Category(models.Model):
category = models.CharField(max_length=200)
parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
class Meta:
unique_together = ('parent' , 'category')
def __str__(self):
return self.category
class SubCategory(models.Model):
subcategory = models.CharField(max_length=200)
category = models.ForeignKey('Category', null=True, blank=True)
parent = models.ForeignKey('self', blank=True, null=True, related_name='subchilren')
class Meta:
unique_together = ('parent' , 'subcategory')
def __str__(self):
return self.subcategory
class Product(models.Model):
name = models.CharField(max_length=200)
category = models.ForeignKey('Category', null=True, blank=True)
subcategory = models.ForeignKey('SubCategory', null=True, blank=True)
def __str__(self):
return self.name
views.py
class AddProducts(APIView):
serializer_class = AddProductsSerializer
def post(self, request, format=None):
data = request.data
serializer = AddProductsSerializer(data=data)
if serializer.is_valid(raise_exception=True):
new_data = serializer.data
return Response(new_data)
return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)
serializers.py
class AddProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'name', 'category', 'subcategory')
def create(self, validated_data):
return Product.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name)
instance.category = validated_data.get('category', instance.category)
instance.subcategory = validated_data.get('subcategory', instance.subcategory)
instance.save()
return instance
if serializer.is_valid(raise_exception=True):
serializer.save()
new_data = serializer.data
return Response(new_data)
add serializer.save() will call serializer create method when serializer has no instance.