I'm trying to build a basic ecommerce website, as a mean to learning django. I'm trying to build my models, so that there is a Category, a Product and Product Image class to store my data in. This is my models.py:
class Category(models.Model):
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True, unique=True)
class Meta:
ordering = ('name', )
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('products:product_list_by_category', args=[self.slug])
class Product(models.Model):
category = models.ForeignKey(Category, related_name='products')
name = models.CharField(max_length=200, db_index=True)
slug = models.SlugField(max_length=200, db_index=True)
description = models.TextField(blank=True)
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.PositiveIntegerField()
available = models.BooleanField(default=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ('name', )
index_together = (('id', 'slug'), )
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('products:product_detail', args=[self.id, self.slug])
class ProductImage(models.Model):
property = models.ForeignKey('Product', related_name='images', on_delete=models.CASCADE)
image = models.ImageField(upload_to='products')
And this is my views.py:
def product_list(request, category_slug=None):
category = None
categories = Category.objects.all()
products = Product.objects.filter(available=True)
product_img = Product.images.all()
if category_slug:
category = get_object_or_404(Category, slug=category_slug)
products = products.filter(category=category)
return render(request, 'products/list.html', {'category': category, 'categories': categories, 'products': products, 'product_img': product_img})
I've seen similar post here on stack overflow, and have tried to do the same thing, but I still get the following error: AttributeError: 'ReverseManyToOneDescriptor' object has no attribute 'all'
Where am I going wrong here?
Related
I have a listview where I'm trying to filter out products by category. Some products have a subcategory. When a product has a subcategory I want the listview to display them by subcategory.
Problem is: The listview works perfect for items with a subcategory, but does not work for items who do not have a subcategory. Where am I taking a wrong turn here?
Models:
class Category(models.Model):
category_name = models.CharField(max_length=200)
sub_category = models.CharField(max_length=200,blank=True,null=True)
category_picture = ResizedImageField(upload_to='category/', null=True, blank=True)
category_info = models.TextField(blank=True, null=True)
category_video = models.CharField(max_length=250,blank=True, null=True)
def __str__(self):
if self.sub_category is None:
return self.category_name
else:
return f" {self.sub_category}"
class Meta:
ordering = ['category_name']
class Bottle(models.Model):
category_name = models.ForeignKey('Category', on_delete=models.SET_NULL,null=True,blank=True)
brand = models.ForeignKey('Brand', on_delete=models.CASCADE)
bottle_name = models.CharField(max_length=255)
bottle_info = models.TextField()
bottle_tasting_notes = models.TextField()
bottle_barcode = models.IntegerField()
bottle_image = ResizedImageField(upload_to='bottles/',null=True, blank=True)
bottle_shop_link = models.CharField(max_length=250, null=True, blank=True)
def __str__(self):
return f"{self.brand}, {self.bottle_name}"
class Meta:
ordering = ['bottle_name']
View:
class BottlesByCategoryView(ListView):
model = Bottle
context_object_name = 'bottles'
#Filter bij subcategory in the category model. If no subcategory exists, load by category_name
def get_queryset(self):
if Bottle.objects.filter(category_name__sub_category=self.kwargs['category']) is None:
return Bottle.objects.filter(category_name__category_name=self.kwargs['category'])
else:
return Bottle.objects.filter(category_name__sub_category=self.kwargs['category'])
def get_context_data(self, **kwargs):
context = super(BottlesByCategoryView, self).get_context_data(**kwargs)
if Bottle.objects.filter(category_name__sub_category=self.kwargs['category']) is None:
context['category_info'] = Category.objects.filter(category_name=self.kwargs['category'])
else:
context['category_info'] = Category.objects.filter(sub_category=self.kwargs['category'])
return context
URLS:
path('BottlesByCategory/<str:category>/',BottlesByCategoryView.as_view(template_name='academy/bottlesByCat_list.html'),name='bottlesByCat_list'),
Can i not use if statements in the get_context_data and get_query_set?
i want to fetch the item of related subcategories but i am unable to fetch the items from that subcategories it is showing me the error
AttributeError: 'Subcategories' object has no attribute 'item'
so here is my code
my models
class Subcategories(models.Model):
categories = models.ForeignKey(Categories, on_delete=models.CASCADE, related_name='our_categories')
name = models.CharField(max_length=200, blank=False)
joined_date = models.DateTimeField(default=timezone.now,editable=False)
update_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Item(models.Model):
categories = models.ForeignKey(Categories, on_delete=models.CASCADE,)
subcategories = models.ForeignKey(Subcategories, on_delete=models.CASCADE, related_name='products')
can_buy = models.ForeignKey(For, on_delete=models.CASCADE,)
name = models.CharField(max_length=200, blank=False)
contain_size = models.CharField(max_length=10, blank=True)
first = models.ImageField(upload_to='items', blank=False)
second = models.ImageField(upload_to='items', blank=True)
third = models.ImageField(upload_to='items', blank=True)
fourth = models.ImageField(upload_to='items', blank=True)
fifth = models.ImageField(upload_to='items', blank=True)
item_vedio = models.FileField(upload_to='item_vedio', blank=True)
offered_price = models.FloatField(blank=False,)
actual_price = models.FloatField(blank=False)
about = models.TextField(blank=False, default="about" )
offer = models.CharField(max_length=4, blank=True)
def __str__(self):
return self.name
my urls.py
urlpatterns = [
path('<int:subcategory_id>/products/',Product.as_view(),name='product' ),
]
my views.py
class Product(View):
def get(self, request,):
category_list = Categories.objects.all()
return render (request, 'products.html', {'category_list': category_list })
def get(self, request, subcategory_id):
subcategory = get_object_or_404(Subcategories, pk=subcategory_id)
products = subcategory.item.all()
return render (request, 'products.html',{"subcategory_list" : products })
any idea what causing the issue and thank you for your time
The related name is products for subcategories Foreign key in Item model.
subcategory.products.all()
I am trying to create an api where a user can add their products. I am sending raw json data from postman but it is giving this error.
IntegrityError at /api/addproducts
(1048, "Column 'brand_id' cannot be null")
I am sending brand id in the data. I am not sure what is happening.
Here I am sending merchant_id as well as categories ids but why brand field is creating an error I am not sure.
My models:
class Category(models.Model):
name = models.CharField(max_length=100, unique=True)
image = models.ImageField(null=True, blank=True)
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.name
class Brand(models.Model):
brand_category = models.ForeignKey(Category,on_delete=models.CASCADE,blank=True,null=True)
name = models.CharField(max_length=100, unique=True)
image = models.ImageField(null=True, blank=True)
class Meta:
verbose_name_plural = "Brands"
def __str__(self):
return self.name
class Collection(models.Model):
name = models.CharField(max_length=100, unique=True)
image = models.ImageField(null=True, blank=True)
class Meta:
verbose_name_plural = "Collections"
def __str__(self):
return self.name
class Variants(models.Model):
SIZE = (
('not applicable', 'not applicable',),
('S', 'Small',),
('M', 'Medium',),
('L', 'Large',),
('XL', 'Extra Large',),
)
AVAILABILITY = (
('available', 'Available',),
('not_available', 'Not Available',),
)
product_id = models.CharField(max_length=70,default='OAXWRTZ_12C',blank=True)
price = models.DecimalField(decimal_places=2, max_digits=20,default=500)
size = models.CharField(max_length=50, choices=SIZE, default='not applicable',blank=True,null=True)
color = models.CharField(max_length=70, default="not applicable",blank=True,null=True)
variant_image = models.ImageField(upload_to="products/images", blank=True)
thumbnail = ImageSpecField(source='variant_image',
processors=[ResizeToFill(100, 50)],
format='JPEG',
options={'quality': 60})
quantity = models.IntegerField(default=10,blank=True,null=True) # available quantity of given product
variant_availability = models.CharField(max_length=70, choices=AVAILABILITY, default='available')
class Meta:
verbose_name_plural = "Variants"
def __str__(self):
return self.product_id
class Product(models.Model):
merchant = models.ForeignKey(Seller,on_delete=models.CASCADE,blank=True,null=True)
category = models.ManyToManyField(Category, blank=False)
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
collection = models.ForeignKey(Collection, on_delete=models.CASCADE)
featured = models.BooleanField(default=False) # is product featured?
best_seller = models.BooleanField(default=False)
top_rated = models.BooleanField(default=False)
My serializers:
class BrandSerializer(serializers.ModelSerializer):
# id = serializers.IntegerField()
class Meta:
model = Brand
fields = '__all__'
class AddProductSerializer(serializers.ModelSerializer):
merchant = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Product
fields = ['id','merchant','category','brand', 'collection','featured', 'top_rated',
'name','description', 'picture','main_product_image','best_seller',
'rating','availability','warranty','services','variants']
# depth = 1
def create(self, validated_data):
product = Product.objects.create()
return product
My views:
class ProductAddAPIView(CreateAPIView):
permission_classes = [AllowAny]
queryset = Product.objects.all()
serializer_class = AddProductSerializer
i think the problem is in the create function in serializer
class AddProductSerializer(serializers.ModelSerializer):
merchant = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Product
fields = ['id','merchant','category','brand', 'collection','featured', 'top_rated',
'name','description', 'picture','main_product_image','best_seller',
'rating','availability','warranty','services','variants']
# depth = 1
def create(self, validated_data):
product = Product.objects.create()
return product
as you didn't pass the validated data so it create an empty object use this instead
def create(self, validated_data):
return Product.objects.create(**validated_data)
how can i get in between first and last product image set in django restframework
i have maximum ten product image set, in my case i am able to get first and last product image set. how can i get in between first and last product image set. any help, would be appreciated.
how can i get in between first and last product image set
models.py
class Product(models.Model):
title = models.CharField(max_length=30)
slug= models.SlugField(blank=True, null=True)
sku = models.CharField(max_length=30)
description = models.TextField(max_length=200, null=True, blank=True)
instruction = models.TextField(max_length=200, null=True, blank=True)
price = models.DecimalField(decimal_places=2, max_digits= 10,)
discount_price= models.DecimalField(decimal_places=2, max_digits= 10, null=True, blank=True)
category = models.ManyToManyField('Category', )
default = models.ForeignKey('Category', related_name='default_category', null=True, blank=True, on_delete=models.CASCADE)
created_on = models.DateTimeField(default=timezone.now)
updated_on = models.DateTimeField(null=True, blank=True)
status = models.BooleanField(default=True)
class Meta:
ordering = ["-id"]
def __str__(self): #def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("product_detail", kwargs={"pk": self.pk})
def get_first_image_url(self):
img = self.productimage_set.first()
if img:
return img.image.url
return img #None
def pre_save_post_receiver(sender, instance, *args, **kwargs):
if not instance.slug:
instance.slug = unique_slug_generator(instance)
pre_save.connect(pre_save_post_receiver, sender=Product)
def image_upload_to(instance, filename):
title = instance.product.title
slug = slugify(title)
basename, file_extension = filename.split(".")
new_filename = "%s-%s.%s" %(slug, instance.id, file_extension)
return "products/%s/%s" %(slug, new_filename)
class ProductImage(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
image = models.ImageField(upload_to=image_upload_to)
created_on = models.DateTimeField(default=timezone.now)
status = models.BooleanField(default=True)
def __unicode__(self):
return self.product.title
views.py
class ProductUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
model = Product
queryset = Product.objects.all()
serializer_class = DemoAppProductUpdateDestroySerializer
permission_classes = [IsAdminUser]
authentication_classes = [BasicAuthentication]
serializers.py
class DemoAppProductUpdateDestroySerializer(serializers.ModelSerializer):
image = serializers.SerializerMethodField()
image2 = serializers.SerializerMethodField()
class Meta:
model = Product
fields=[
"id",
"title",
"slug",
"sku",
"price",
"discount_price",
"image",
"image2",
]
def get_image(self, obj):
return obj.productimage_set.first().image.url
def get_image2(self,obj):
return obj.productimage_set.last().image.url
Change your serializer as,
class DemoAppProductUpdateDestroySerializer(serializers.ModelSerializer):
images = serializers.SerializerMethodField()
class Meta:
model = Product
fields = [
"id",
"title",
"slug",
"sku",
"price",
"discount_price",
"images",
]
def get_images(self, obj):
return [product_image.image.url for product_image in obj.productimage_set.all()]
You can do this in Serializer:
def get_between_images(self,obj):
images = obj.productimage_set.all().values_list('image', flat=True)
return images[1:len(images)-1]
I want to have a url pattern that takes 2 slugs. I'm trying to make it look like http://127.0.0.1:8000/category/model but I'm having difficulties understanding how to do this.
Below is what I have so far:
models.py
def model_detail_view(request, category_slug, model_slug):
model = Model.objects.get(
category__slug=category_slug, model_slug=model_slug)
context = {
"model": model,
}
return render(request=request, template_name='main/model_detail.html', context=context)
urls.py
path("<str:category_slug>/<str:model_slug>/", views.model_detail_view, name="model_detail_view"),
models.py
class Category(models.Model):
title = models.CharField(max_length=50)
featured_image = models.ImageField(upload_to="categories")
category_slug = AutoSlugField(null=True, default=None,
unique=True, populate_from='title')
class Meta:
verbose_name_plural = "Categories"
def __str__(self):
return self.title
class Model(models.Model):
title = models.CharField(max_length=80)
category = models.ManyToManyField(Category)
featured_image = models.ImageField(upload_to=image_dir)
model_slug = AutoSlugField(null=True, default=None,
unique=True, populate_from='title')
class Meta:
verbose_name_plural = "Models"
def __str__(self):
return self.title
Try this,
model = model = Model.objects.get(category__category_slug=category_slug, model_slug=model_slug)
Reference:
Django:Lookups that span relationships---(Django Doc)