Abdul Rehman
Abdul Rehman

Reputation: 5654

How to structure models in Django?

I'm working on a project using Python(3.7) and Django(3) in which I have to create some models to store reports. There are 4 different models to represents each type of report with only 2 common fields(RequestId, InstCode) but the rest of the fields are different. In the end, I have to display the 10 recent reports (mixed from all models) on the home page.

Here's how I have implemented my models at the moment:

From models.py:

class DistributionReport(models.Model):
    RequestId = models.CharField(max_length=256, blank=False, default=0)
    InstCode = models.CharField(max_length=3, blank=False)
    Currency = models.CharField(max_length=3, blank=False)
    Denomination = models.IntegerField(blank=False, default=0)decimal_places=2)
    date = models.DateField(default=datetime.date.today)

    class Meta:
        verbose_name = 'Distribution Report'

    def __str__(self):
        return self.RequestId


class ExpenditureReport(models.Model):
    RequestId = models.CharField(max_length=256, blank=False, default=0)
    InstCode = models.CharField(max_length=3, blank=False)
    StaffExpenditure = models.DecimalField(max_digits=12, decimal_places=2)
    Month = models.IntegerField(blank=False, default=0)
    Quarter = models.IntegerField(blank=False, default=0)
    Year = models.IntegerField(blank=False, default=0)

    class Meta:
        verbose_name = 'Expenditure Report'

    def __str__(self):
        return self.RequestId


class StorageReport(models.Model):
    RequestId = models.CharField(max_length=256, blank=False, default=0)
    InstCode = models.CharField(max_length=3, blank=False)
    Currency = models.CharField(max_length=5, blank=False)
    Denomination = models.IntegerField(blank=False, default=0)
    date = models.DateField(default=datetime.date.today)

    class Meta:
        verbose_name = 'Processing Report'

    def __str__(self):
        return self.RequestId


class AssetsReport(models.Model):
    RequestId = models.CharField(max_length=256, blank=False, default=0)
    InstCode = models.CharField(max_length=3, blank=False)
    AssetClassificationId = models.IntegerField(blank=False, default=0)
    VaultCapacity = models.DecimalField(max_digits=10, decimal_places=2)
    Year = models.IntegerField(blank=False, default=0)
    HalfOftheYear = models.IntegerField(blank=False, default=0)

    class Meta:
        verbose_name = 'Assets Report'

    def __str__(self):
        return self.RequestId

What is the best way to structure these models, so I can query the recent reports ( It can be of any type)?

Upvotes: 0

Views: 95

Answers (1)

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21807

Look into how normalization works, since all models have 2 common fields lets say you have a table called Report and it has the fields RequestId and InstCode. Now all your other models can be said to be in a XYZReport is a Report kind of relationship.
You can achieve this using a OneToOne Field like so:

class Report(models.Model):
    RequestId = models.CharField(max_length=256, blank=False, default=0)
    InstCode = models.CharField(max_length=3, blank=False)
    DISTRIBUTION = 'DI'
    EXPENDITURE = 'EX'
    STORAGE = 'ST'
    ASSETS = 'AS'
    REPORT_TYPE_CHOICES = [
        (DISTRIBUTION, 'Distribution Report'),
        (EXPENDITURE, 'Expenditure Report'),
        (STORAGE, 'Storage Report'),
        (ASSETS, 'Assets Report'),
    ]
    report_type = models.CharField(
        max_length=2,
        choices=REPORT_TYPE_CHOICES,
        default=DISTRIBUTION,
    )
    # Any more common fields

class DistributionReport(models.Model):
    report = models.OneToOneField(
        Report,
        on_delete=models.CASCADE,
        related_name = 'distribution_report'
    )
    # Other fields

# Other Report models in similar fashion

Now whenever making an object of any kind of report also make an object of Report and assign it to report attribute of the models. Save both the models, also to figure out what kind of report an instance of Report is add the relevant report_type to the report instance like so:

report.report_type = Report.DISTRIBUTION # In case of Distribution Report

To figure out whether an instance of Report is of a particular type:

report.report_type == report.DISTRIBUTION # will get whether Report is a DistributionReport

To get the specific types object use the related_name set in the OneToOne Field:

distribution_report = report.distribution_report

Upvotes: 2

Related Questions