Как реализовать категорию, подкатегорию и продукт в django
class Category(models.Model):
name= models.CharField(max_length=50)
@staticmethod
def get_all_categories():
return Category.objects.all()
def __str__(self):
return self.name
class Products(models.Model):
name = models.CharField(max_length=60)
price= models.IntegerField(default=0)
category= models.ForeignKey(Category,on_delete=models.CASCADE,default=1 )
Как мне теперь добавить подкатегорию в эту иерархию
Вы можете ссылаться на саму модель, используя 'self', например:
class Foo(models.Model):
parent = models.ForeignKey('self', related_name='children', ...)
В зависимости от ваших потребностей, если ваши подкатегории могут иметь только одного родителя, то вы можете сделать:
class Category(models.Model):
name = models.CharField(max_length=50)
parent_category = models.ForeignKey(
'self', related_name='sub_categories',
on_delete=models.SET_NULL, null=True
)
Но если ваши подкатегории могут иметь более одной родительской категории, то вы можете ссылаться на них, используя отношение "многие ко многим":
class Category(models.Model):
name = models.CharField(max_length=50)
sub_categories = models.ManyToManyField(
'self', related_name='parent_categories',
)
Предполагается, что одна категория может иметь более одной подкатегории, а одна подкатегория может быть связана с более чем одной категорией.
Одним из способов () является создание трех таблиц (надеюсь, вы видите взаимосвязь),
class Category(models.Model):
name= models.CharField(max_length=50)
@staticmethod
def get_all_categories():
return Category.objects.all()
def __str__(self):
return self.name
class SubCategory(models.Model):
name = models.TextField(max_length=50)
categories = models.ManyToManyField(Category)
class Products(models.Model):
name = models.CharField(max_length=60)
price = models.IntegerField(default=0)
category= models.ManyToManyField(SubCategory)
Другой способ ( удобный) относится к самому себе, ManyToManyField.symmetrical Это лучший способ.
class Category(models.Model):
name = models.CharField(max_length=50)
sub_categories = models.ManyToManyField("self")
@staticmethod
def get_all_categories():
return Category.objects.all()
def __str__(self):
return self.name
Если вы не указываете имя related_name, Django автоматически создает его, используя имя вашей модели с суффиксом _set. В Документации есть более подробная информация
Использование модели mptt является лучшим вариантом для работы над этим сценарием использования
class Category(MPTTModel):
name = models.CharField(max_length=128)
slug = models.SlugField(max_length=128)
description = models.TextField(blank=True)
is_active = models.BooleanField(default=True)
parent = models.ForeignKey(
"self", null=True, blank=True, related_name="children", on_delete=models.CASCADE
)
background_image = VersatileImageField(
upload_to="category-backgrounds", blank=True, null=True
)
background_image_alt = models.CharField(max_length=128, blank=True)
category_icon = models.FileField(upload_to="category-icons", max_length=200, blank=True, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
objects = TreeManager()
def __str__(self):
return self.name
def save(self, *args, **kwargs):
if not self.slug:
self.slug = slugify(self.name)
super().save(*args, **kwargs)
class Product(models.Model):
name = models.CharField(max_length=200)
weight = models.FloatField(default=0)
length = models.FloatField(default=0)
width = models.FloatField(default=0)
height = models.FloatField(default=0)
price = models.DecimalField(max_digits=10, decimal_places=2)
discounted_price = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=True)
category = models.ForeignKey(
Category, related_name="products", on_delete=models.CASCADE
)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
@property
def get_featured_image(self):
image = self.images.filter(is_featured=True).first()
return image.image.url if image else None
@property
def get_price(self):
if self.discounted_price:
return self.discounted_price
return self.price
Для справки