如何在 Django 中构建模型?

Posted

技术标签:

【中文标题】如何在 Django 中构建模型?【英文标题】:How to structure models in Django? 【发布时间】:2021-04-26 14:32:57 【问题描述】:

我正在使用 Python(3.7) 和 Django(3) 开发一个项目,我必须在其中创建一些模型来存储报告。有 4 种不同的模型来表示每种类型的报告,只有 2 个公共字段(RequestIdInstCode),但其余字段不同。最后,我必须在主页上显示最近的 10 份报告(来自所有模型的混合)。

以下是我目前实现模型的方式:

来自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

构建这些模型的最佳方法是什么,以便我可以查询最近的报告(可以是任何类型)?

【问题讨论】:

我可以看到 2 种可能性:1)创建一个使用 generic foreign relations 到不同报表模型的基本报表类或 2)使用 django polymorphic 进行模型继承 【参考方案1】:

查看标准化的工作原理,因为所有模型都有 2 个公共字段,假设您有一个名为 Report 的表,它具有字段 RequestIdInstCode。现在可以说您所有其他模型都处于XYZReport is a Report 类的关系中。 您可以使用 OneToOne 字段来实现这一点,如下所示:

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

现在,每当制作任何类型的报告对象时,也可以制作Report 的对象并将其分配给模型的报告属性。保存这两个模型,还可以确定 Report 实例的报告类型,将相关的 report_type 添加到报告实例中,如下所示:

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

要确定 Report 的实例是否属于特定类型:

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

要获取特定类型对象,请使用 OneToOne 字段中设置的相关名称:

distribution_report = report.distribution_report

【讨论】:

以上是关于如何在 Django 中构建模型?的主要内容,如果未能解决你的问题,请参考以下文章

Django - 如何构建适合的中间 m2m 模型? / 最佳实践

ArcGIS中用模型构建器如何批量添加字段

如何通过 HTML 中的 JavaScript 在 Django 中保存模型实例

如何在 Django 中呈现单个单选按钮选项?

Django:如何使用多个数据库?

如何在 django admin 中组合两个或多个 ModelAdmin