Seeking for best approach for complex product model that involves multiple Database Table

Hi everyone,
I am loving using Django for last 6 months. Already built 2 web application and 100% satisfied with the performance and quality. The database was straight forward and simple for both application.

This is the time, I am trying to build a mid-level complex application where an admin user will upload product to promote in the wholesale market. Again I choose django for this application because the application require a very good SEO ranking.

However, I am struggling with find the best way of managing [uploading and editing] products. My product models are as follows

class Category(models.Model):
    name = models.CharField(max_length=20)
    logo = models.ImageField(upload_to=f'{LOGOS_DIR}/', blank=True, null=True)
    description = models.TextField(blank = True, null = True)
    def __str__(self):
        return self.name
    
    def product_count(self):
        """
        return number of products this category has
        """
        return self.products.count()
    
    def products(self):
        """
        return all products in that category
        """
        return self.products.all()


class PriceTag(models.Model):
    tag = models.CharField(max_length=20)

    def __str__(self):
        return self.tag


# This model is used to store information about the products available.
class Product(models.Model):
    name = models.CharField(max_length=200)
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True, related_name='products')
    image0 = models.ImageField(upload_to=f'{PRODUCT_IMAGE_DIR}/', blank=True, null=True)
    image1 = models.ImageField(upload_to=f'{PRODUCT_IMAGE_DIR}/', blank=True, null=True)
    image2 = models.ImageField(upload_to=f'{PRODUCT_IMAGE_DIR}/', blank=True, null=True)
    image3 = models.ImageField(upload_to=f'{PRODUCT_IMAGE_DIR}/', blank=True, null=True)
    image4 = models.ImageField(upload_to=f'{PRODUCT_IMAGE_DIR}/', blank=True, null=True)
    short_desc = models.TextField()
    description = CKEditor5Field()
    base_cost = models.DecimalField(max_digits=10, decimal_places=2)
    raw_material_cost = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    base_sale = models.DecimalField(max_digits=10, decimal_places=2)
    rsp = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    active = models.BooleanField(default=True)

    def __str__(self):
        return self.name
    
    def profit_margin(self):
        """
        return profit margin of the product
        margin = ((selling price - cost price)/revenue)*100 %
        """
        margin = ((self.base_sale - self.base_cost) / self.base_sale) * 100
        return f"{margin}%"
    
    def uom_price_table(self):
        """
        Generate a price table for the product's UOMs and prices.
        Returns a list of dictionaries containing UOM name, quantity, and price.
        """
        price_table = []
        for uom in self.uoms.all(): 
            price_table.append({
                "uom_name": uom.uom,
                "uom_qty": f"1x{uom.qty}",
                "price": float(self.base_sale) * uom.qty 
            })
        return price_table

    
class ProductPrice(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="price_tiers")
    price_tag = models.ForeignKey(PriceTag, on_delete=models.CASCADE, related_name="product_prices")
    price = models.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        unique_together = ("product", "price_tag")

    def __str__(self):
        return f"{self.product.name} - {self.price_tag.tag} - {self.price}"


class ProductUom(models.Model):
    uom = models.CharField(max_length=10)  # e.g., 'Unit', 'Pack', 'Carton'
    product = models.ForeignKey(Product, on_delete=models.CASCADE, related_name="uoms")
    qty = models.PositiveIntegerField()  # Number of items in this UOM

    def __str__(self):
        return f"{self.product.name} - {self.uom} x {self.qty}"

My products need to have these features

  1. separate uom table [many]
  2. separate price tags table. [because prices could be different for different customer group]

So , when creating a new product user need to able to add multiple UOM entries for the product. and should able to give price for each “price tags”.

I am trying for last 3-4 days already, yet could not find a proper way to do the job.

Can anybody suggest me the way? I am a learner, so, I learn and I code.

Have you tried using model formsets (or regular formsets)? They allow you to create and edit multiple instances of related models at once.

I think in it would be better for your database design if you created a separate `Image` model with a `ForeignKey` to `Product` so that images have a separate table in the database. This would allow you to do away with the sequential naming and to be able to deal with an arbitrary number of images (if you wish). You could also design the `Image` model to allow adding extra information on the images too, like alt text and image title.
1 Like

Yes, this worked. Thank you, Now I can do more advance thing with Formsets. Needed little bit of jQuery as well.