1

I develop an app for creating products in online shop. Let's suppose I have 50 categories of products and each of these has some required parameters for product (like color, size, etc.). Some parameters apper in all categories, and some are unique. That gives me around 300 parameters (fields) that should be defined in Django model.

I suppose it is not good idea to create one big database with 300 fields and add products that have 1-15 parameters there (leaving remaining fields empty). What would be the best way to handle it?

What would be the best way to display form that will ask only for parameters required in given category?

o_damian
  • 33
  • 2

2 Answers2

2

1-1. Create Models for each category

You can build 50 classes for describing your products in shop.

This is a simple and basic solution. It can also be an optimal solution if the domain logic varies from category to category.

class Furniture(Model):
    price
    size
    color
    ...
class Clothes(Model):
    price
    gender
    texture
    ...

1-2. Aggregate common fields into base class

If you have many common fields, introducing inheritance would be a great idea.

class Base(Model):
    price
    ...

    class Meta:
        abstract = True
class Furniture(Base):
    size
    color
    ...
class Clothes(Base):
    gender
    texture
    ...

2-1. One BigTable

I guess this is what you were going to do.

I suppose it is not good idea to create one big database with 300 fields and add products that have 1-15 parameters there (leaving remaining fields empty).

Like you said, the rest of the field will remain, but it's a not bad idea unless domain logic is different by category.

class Product(Model):
    price
    size
    color
    gender
    texture
    ...

2-2. One Table, but several models

Tables are in the data layer and models are in the domain layer. It does not have to be considered the same as the model.

You can build a proxy model to describe each category type.

Pros

  • simple data layer
  • available to deal with complex domain logic across different categories

Cons

  • code complexity due to proxy processing
  • various difficulties arising from the table and model not being one-on-one
class ProductProxyManager(Manager):
    def get_queryset(self):
        return (
            super()
            .get_queryset()
            .filter(type=self.model.product_type)
            .only(*(self.model.required_fields + self.model.base_fields))
        )
class ProductType(enum.Enum):
    Furniture = "furniture"
    Clothes = "clothes"
class Product(Model):
    type: ProductType
    price
    size
    color
    gender
    texture
    ...

    def __new__(cls, *args, **kwargs):
        # get proxy name, either from kwargs or from args
        type: ProductType = kwargs.get("type")
        if type is None:
            type_field_index = cls._meta.fields.index(cls._meta.get_field("type"))
            proxy_name = args[type_field_index]
        else:
            proxy_name = type
        # get proxy class, by name, from the block formwork
        instance_class = Product.get_instance_class(proxy_name)

        o = super().__new__(instance_class)
        return o

    @staticmethod
    def get_instance_class(type: ProductType) -> Type["ProductType"]:
        return {
            ProductType.Furniture: Furniture,
            ProductType.Clothes: Clothes,
        }[type]
class Furniture(Product):
    class Meta:
        proxy = True

    required_fields = ("size", "color")

    objects = ProductProxyManager()
class Clothes(Product):
    class Meta:
        proxy = True

    required_fields = ("gender", "texture")

    objects = ProductProxyManager()

You can see further steps here. (I followed up to step 3.) https://stackoverflow.com/a/60894618/8614565

Jaewoo Pyo
  • 156
  • 6
1

If you have to keep the Model structure as you have defined it here, I would create a "Product" "Category" "ProductCategory" tables.

Product table is as follows:

ProductID ProductName
1 Shirt
2 Table
3 Vase

Category table is following

CategoryID CategoryName
1 Size
2 Color
3 Material

ProductCategory

ID ProductID CategoryID CategoryValue
1 1 (Shirt) 1 (Size) Medium
2 2 (Table) 2 (Color) Dark Oak
3 3 (Vase) 3 (Material) Glass
3 3 (Vase) 3 (Material) Plastic

This would be the easiest way, which wouldn't create 300 columns, would allow you to reuse categories across different types of products, but in the case of many products, would start to slowdown the database queries, as you would be joining 2 big tables. Product and ProductCategory

You could split it up in more major Categories such as "Plants", "Kitchenware" etc etc.

pevecg
  • 198
  • 9