【问题标题】:How to make my models follow DRY principles如何让我的模型遵循 DRY 原则
【发布时间】:2017-03-18 18:03:12
【问题描述】:

我有一个模型,我需要在其中代表一个劳工申请的不同工作,例如:

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)

您可以立即看到我在重复 titledescriptioncreated_at,我只是在更改字段的名称,它不是 DRY 并且代码开始有味道。这样做的原因是因为我想在django admin中单独注册每个工作,所以我会在站点管理中明确情况。

使它们干燥的一种方法是使用Abstract base classes,但我有一个问题,因为来自文档:

此模型将不会用于创建任何数据库表。 相反,当它用作其他模型的基类时,它的字段 将被添加到子类中。

在这种情况下正确的方法是什么,有人可以帮助我理解这一点。

【问题讨论】:

    标签: python django python-3.x django-models django-rest-framework


    【解决方案1】:

    使用抽象基础模型:

    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
    

    这将创建 3 个表。基类 JobAd 在数据库中没有表。

    由于您似乎有 3 个不同的模型使用完全相同的代码,您应该质疑您是否真的需要 3 个不同的模型。另一种选择是将它们全部存储在一个表中,并为“其他”事物添加另一个字段。

    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)
    

    pos 的整数字段也是可能的。

    【讨论】:

    • 我在质疑,我需要代表六个不同的工作,我希望它们分开的原因是,因为我想在 admin 内部有明确的情况,我不希望我的申请人申请一个模型,所以每个工作一个申请,我希望你理解我
    • 重新思考您的设计。你真的不需要单独的模型。
    【解决方案2】:

    首先,抽象模型可能就是您需要的。根据业务需求,您可能需要更加仔细地考虑架构。

    如果您确实需要使用抽象基类:

    class BaseJob(models.Model):
        title = models.CharField(max_length=255)
        # etc...
    
        class Meta:
            abstract = True
    
        def method_1(self):
            # base methods that work for instance data
    

    一旦定义好,您就可以在具体模型中实现基类。具体模型是不使用abstract = True 元类属性(或代理等)的模型,如下所示:

    class Job(BaseJob):
        pass
    

    如果您需要其他字段,您可以像定义任何其他模型字段一样定义它们,但是当您运行 makemigrations 时,您会发现这些字段已添加到生成的迁移中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-04-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-11
      • 1970-01-01
      相关资源
      最近更新 更多