Home > Mobile >  How to implement Category, SubCategory and Product in django
How to implement Category, SubCategory and Product in django

Time:03-19

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

django mptt docs

For reference

  • Related