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 )
How can I now add subcategory to this heirarchy
CodePudding user response:
You can reference the model itself using 'self'
, e.g.:
class Foo(models.Model):
parent = models.ForeignKey('self', related_name='children', ...)
Depending on your needs, if your sub-categories can have only one parent, then you can do:
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
)
But if your sub-categories can have more than one parent category, then you can reference them using many-to-many relation:
class Category(models.Model):
name = models.CharField(max_length=50)
sub_categories = models.ManyToManyField(
'self', related_name='parent_categories',
)
CodePudding user response:
Assuming that one category can have more than one subcategory and one subcategory can be related to more than one category.
One way(messy) is creating three tables(hope you can see the relationship),
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)
Another way(convenient) is relating to itself, ManyToManyField.symmetrical This is the best way.
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
If you don't specify a related_name, Django automatically creates one using the name of your model with the suffix _set
. Documentation has more details
CodePudding user response:
Use mptt model is the best option to work on this use case
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
For reference