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