fgalvao
fgalvao

Reputation: 460

Django - Web Store Model Organization

I am starting to create a web store in Django. It will have different kinds of products, like shirts, posters, mugs, stickers. Each type of product will have different fields. For ex: shirts will have size and color options, stickers will have size option, posters and mugs will have no options.

What is the best way to do this? Inheritance? Relationships?

I'm still learning Django and want to know about that from more experienced people before i dig deeper on this kind of project.

Thanks

Upvotes: 2

Views: 303

Answers (1)

Serafeim
Serafeim

Reputation: 15084

This is an interesting problem. I believe that first of all you must find out if your users would like to add item types themselves or if there would be a predefined number of types and only a developer could add a new one if needed.

Static Item Types

If the item types are static you can use model inheritance to create your schema. So, in this case I recommend defining one or more abstract base models and concrete models for each of your item types. For instance you would do something like this:

class Item(models.Model):
  slug = models.SlugField()
  price = models.DecimalField()
  remaining = models.IntegerField()
  description = models.CharField()

  class Meta:
    abstract=True

class ClothingItem(Item):
  size = models.CharField()
  brand = models.CharField()

  class Meta:
    abstract=True

class Jacket(ClothingItem):
  has_hood = models.BooleanField()

class Hat(ClothingItem):
  hat_type = models.CharField(choices=[])  

So, the above will actually generate only two database tables: Jacket and Hat and each one will contain all the fields from the models it has inherited from. This is what most people use in django because it is very clean makes it very easy to add forms and generate queries to get Items.

Your other options is to not use abstract base classes, so you will get a database table named Item which will contain each fields, another table named ClothingItem that will contain a ForeignKey to the Item and another named Jacket that will contain a ForeignKey to the ClothingItem. This will help you in generating aggregations on Item or ClothingItem, however django will have to query three tables (with joins) whenever you want to get the properties of a Jacket. I recommend using this only if you are positive that you need it.

Dynamic Item Types In this case you have to use a different schema because the properties of the Items have to be defined by the user of the application. You may do something like this:

class Category(models.Model):
  name = models.CharField()

class Attribute(models.Model):
  category = models.ForeignKey(Category)
  name = models.CharField

class Item(models.Model):
  slug = models.SlugField()
  price = models.DecimalField()
  remaining = models.IntegerField()
  category = models.ForeignKey(Category)
  description = models.CharField()
  attributes = models.ManyToManyField(Attribute, through='ItemAttribute')

class ItemAttribute(models.Model):
  item= models.ForeignKey(Item)
  attribute = models.ForeignKey(Attribute)
  value = models.CharField()

This design is a little more complex. What we have here is a category model that will define your item type (hat, jacket, mug, shirt, poster etc) -- you could also define a hierarchy of categories which I will leave as an exercise to you. The Attribute model defines the names of attributes - each one has a name and a category it belongs to. So for the jacket category you will have a has_hood attribute, for the hat category a hat_type attribute etc.

Now, an Item model belongs also to a Category and has a many-to-many relation with the Attribute model through the ItemAttribute model. The last one means the you will have an ItemAttribute table in your database with the following fields:

item - attribute - value

So the jacket 312 will have the attribute 2(has_hood) with a value of true while the jacket 313 will have the attribute 2 withe a value of false etc.

The above design has the minor problem that there is no "type" in the attributes. You should extend it more by adding a _type attribute to the Attribute model. Also, please check the answers to this question: Django dynamic model fields which defines dynamic model fields in a more generic way.

With this design your users will be able to create new attributes, assign them to categories, so when they will add new item they would be able to fill their attributes based on their category. Of course, to enable your users to do this you also have to generate dynamic forms that will contain your dynamic attributes for each item. If you want I can tell you also how to do that - it's not as difficult as somebody believes at first (hint: use type to generate dynamic Form classes).

Upvotes: 3

Related Questions