PetarP PetarP - 1 month ago 17
Python Question

How to make my models follow DRY principles

I have a model in which I need to represent different jobs for a labor application, for example:

from django.db import models

class PostFirstJobAd(models.Model):
fist_job_ad_title = models.CharField(max_length=225)
first_job_ad_description = models.TextField()
created_at = models.DateTimeField(auto_now=True)

class PostSecondJobAd(models.Model):
second_job_ad_title = models.CharField(max_length=225)
second_job_ad_description = models.TextField()
created_at = models.DateTimeField(auto_now=True)

class PostThirdJobAd(models.Model):
third_job_ad_title = models.CharField(max_length=225)
third_job_ad_description = models.TextField()
created_at = models.DateTimeField(auto_now=True)


Instantly you can see that I'm repeating
title
,
description
and
created_at
, I'm just changing field's name, it's not DRY and code is starting to smell. The reason for this is because I want to register every job separately inside
django admin
, so I will have clear situation inside site administration.

One way to make them DRY is to use
Abstract base classes
but I have a problem because from the docs:


This model will then not be used to create any database table.
Instead, when it is used as a base class for other models, its fields
will be added to those of the child class.


What will be the right approach in this case, can someone help me understand this.

wim wim
Answer

Using abstract base models:

class JobAd(models.Model):
    title = models.CharField(max_length=225)
    description = models.TextField()
    created_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class PostFirstJobAd(JobAd):
    pass

class PostSecondJobAd(JobAd):
    pass

class PostThirdJobAd(JobAd):
    pass

This would create 3 tables. The base class JobAd does not have a table in the db.

Since you appear to have 3 different models with the exact same code, you should question whether you really need 3 different models at all. Another option is to just store them all in one table, and add another field for the "other" thing.

class JobAd(models.Model):
    pos = models.CharField(max_length=100, choices=['first', 'second', 'third'])
    title = models.CharField(max_length=225)
    description = models.TextField()
    created_at = models.DateTimeField(auto_now=True)

An integer field for pos is also possible.