I'm creating an ecommerce store that sells T-shirts, hoodies, mugs, shot glasses, etc. For the t-shirts and hoodies there are sizes and sometimes color associated with each product. I'm trying to add multiple variations for each product. Here's my model.py code:
class Category(models.Model):
name = models.CharField(max_length = 255, db_index=True, null=True, blank=True)
slug = models.SlugField(max_length=255, unique=True, default='')
class Meta:
verbose_name_plural = 'categories'\
def get_absolute_url(self):
return reverse('main:category_list', args=[self.slug])
def __str__(self):
return self.name
class Attribute(models.Model):
name = models.CharField(max_length = 255, default='')
def __str__(self):
return self.name
class ProductAttribute(models.Model):
attribute = models.ManyToManyField(Attribute, through='Product')
value = models.CharField(max_length = 255, null=True, blank=True)
def __str__(self):
return self.value
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length = 255, default='')
description = models.TextField(blank=True)
image = models.ImageField(upload_to='products/', null=True, blank=True)
slug = models.SlugField(max_length = 255, default='')
price = models.DecimalField(max_digits=4,decimal_places=2)
has_attributes = models.BooleanField(default=False)
attribute = models.ForeignKey(Attribute, on_delete=models.CASCADE, null=True, blank=True)
value = models.ForeignKey(ProductAttribute, on_delete=models.CASCADE, null=True, blank=True)
class Meta:
ordering=(['name'])
def get_absolute_url(self):
return reverse('main:product_detail', args=[self.slug])
def __str__(self):
return self.name
The way it appears right now in my admin interface there is a name, attribute, value, and price (only named relevant fields for clarity). If I add a product like such: "t-shirt_1, size, sm, 17.98", then the next item I need to add is "t-shirt_1, size, med, 17.98" and so forth (2xl and above, price goes up). Is there a way to simplify this where I just enter the product name once, then add all sizes and associated pricing, as well as inventory tracking (haven't created field yet) for each size within the product?
Thanks in advance for some guidance
CodePudding user response:
Remove corresponding attribute fields from Product
model and create OneToMany
relationship between Product
and ProductAttribute
. Then create separate Size and Color models, and relate them to ProductAttribute
with ManyToMany
relationship:
class Product(models.Model):
category = models.ForeignKey(Category, on_delete=models.CASCADE, null=True, blank=True)
name = models.CharField(max_length = 255, default='')
description = models.TextField(blank=True)
image = models.ImageField(upload_to='products/', null=True, blank=True)
slug = models.SlugField(max_length = 255, default='')
price = models.DecimalField(max_digits=4,decimal_places=2)
has_attributes = models.BooleanField(default=False)
...
class ProductAttribute(models.Model):
product = models.ForeignKey('Product', related_name="product_attrs", on_delete=models.CASCADE)
sizes = models.ManyToManyField('Size', related_name="product_sizes", null=True, blank=True)
colors = models.ManyToManyField('Product', related_name="product_colors", null=True, blank=True)
...
class Size(models.Model):
size_num = models.CharField(max_length=10)
...
class Color(models.Model):
color_name = models.CharField(max_length=15)
...
Now you can create Product
object, then go to ProductAttribute
to relate corresponding product object with product attribute model and add each attribute of that product (sizes or colors). Whenever you need to get product size or color you can do it as follows:
# let's say you need to get sizes of last product
p = Product.objects.last()
sizes = p.product_attrs.sizes.all()
# ↑ returns queryset containing all sizes of product
CodePudding user response:
Not required
class Attribute(models.Model):
name = models.CharField(max_length = 255, default='')
def __str__(self):
return self.name