0

Say you're a publisher and have multiple types of article.

Standard article, sponsored article, and review

And sponsored article has some sponsored-only fields, say sponsor and promotion_end_date

And review has some other review only fields, like product return address

How would you design this?

I've come across this problem a few times, and I always end up doing it in one model with all the fields available but not required. But it just feels bad because it leaves room for mistakes with the administrators. What if they fill in product return address but its not a review? etc.

And most of the time you want it in one model, to query the very similar objects together since 90% of the fieldset is the same between them. ANd its very helpful for things like finding most popular

EDIT:

These models will almost always be queried together. So it makes no sense to put them in different tables and then work around that. They should be in the same table and indexed. Otherwise every single request would be doing 3x queries, not one. And then having to merge and sort the queries computationally afterwards.

straykiwi
  • 538
  • 6
  • 23
  • Possible duplicate of [Display objects from different models at the same page according to their published date](http://stackoverflow.com/questions/37747427/display-objects-from-different-models-at-the-same-page-according-to-their-publis) – e4c5 Jul 21 '16 at 07:15
  • Its not a duplicate, because that post presumes you are using 3 different models, and THEN optimising the query. I'm asking whats the best way to design very similar model(s) to minimize database queries, which most likely means having them all in one table, as 3 models means 3x the queires – straykiwi Jul 24 '16 at 23:00

2 Answers2

2

Use abstract base classes:

class ArticleBase(models.Model):
    # fields

    class Meta:
        abstract = True

class Article(ArticleBase):
    pass

class SponsoredArticle(ArticleBase):
    # additional fields

class Review(ArticleBase):
    # additional fields

Or multi-table inheritance:

class Article(models.Model):
    # fields

class SponsoredArticle(Article):
    # additional fields

class Review(Article):
    # additional fields

In the latter case you can query all articles with Article.objects.select_related('sponsoredarticle', 'review').all() (you may create custom manager to avoid typing select_related(...) each time). select_related() is necessary to avoid DB query when accessing child class, e. g. aricle.review.

Vladimir Danilov
  • 2,338
  • 14
  • 15
2

You can always have one base model which can be inherited by other subsequent models that you named. In your case.

class BaseArticle(models.Model):
    class Meta:
        abstract = True
    fields that are common to the models that will be inheriting this


class StandardArticle(BaseArticle):
    fields specific to StandardArticle

You can have your other models in same fashion as StandardArticle

Rajesh Yogeshwar
  • 2,111
  • 2
  • 18
  • 37