【问题标题】:Django: queryable computed fieldsDjango:可查询的计算字段
【发布时间】:2018-08-08 11:52:03
【问题描述】:

是否有一种“最好”的方式来处理可以查询的计算字段?

例如:

from django.db import models

class Person(models.Model):
    given_name = models.CharField(max_length=30)
    family_name = models.CharField(max_length=30)

    NAME_ORDER_CONVENTION_CHOICES = (
        # "Eastern" name order: family name followed by given name
        ('E', 'Eastern'),
        # "Western" name order: given name followed by family name
        ('W', 'Western')
    )

    name_order_convention = models.CharField(
        length=1, 
        choices=NAME_ORDER_CONVENTION_CHOICES,
    )

    @property
    def full_name(self):
        """
        Return full name, calculated on the basis of given name,
        family name and name order convention.
        """
        template = "{} {}"
        if self.name_order_convention == "W":
            return template.format(self.given_name, self.family_name)
        return template.format(self.family_name, self.given_name)

这使您能够获取任何Personfull_name,但是如果您想根据全名进行数据库查询,您需要编写一个隐含知道如何计算此属性的查询.这似乎违反了 DRY,因为不再有任何中心位置可以更改计算字段的计算方式 - 您必须更改 full_name 属性以及基于查询的任何位置关于full_name 工作原理的隐含知识。

我能想到的主要替代方法是覆盖 save() 方法以在每次更新时更新这些字段。

from django.db import models

class Person(models.Model):
    given_name = models.CharField(max_length=30)
    family_name = models.CharField(max_length=30)

    NAME_ORDER_CONVENTION_CHOICES = (
        ('E', 'Eastern'),
        ('W', 'Western')
    )

    name_order_convention = models.CharField(
        length=1, 
        choices=NAME_ORDER_CONVENTION_CHOICES,
    )

    # Computed fields
    full_name = models.CharField(max_length=60)

    def _calculate_full_name(self):
        template = "{} {}"
        if self.name_order_convention == "W":
            self.full_name = template.format(self.given_name, self.family_name)
        else:
            self.full_name = template.format(self.family_name, self.given_name)

    def save(self, *args, **kwargs):
        self._calculate_full_name()
        super(Model, self).save(*args, **kwargs)

对于我可能遗漏的可查询计算字段,是否有通用的“最佳实践”解决方案?

【问题讨论】:

    标签: python django django-models computed-properties computed-field


    【解决方案1】:

    我可以看到的一种方式:在数据库中创建 view 并在 django 中使用连接的 full_name 而不是托管模型,用于查询(Person 模型也应该存在于 crud 操作):

    查看(postgresql)

    CREATE OR REPLACE VIEW appname_viewperson AS 
        SELECT id,
            given_name,
            family_name,
            given_name || ' ' || family_name AS full_name,
        FROM appname_person
    

    非托管模型:

    class ViewPerson(models.Model):
        given_name = models.CharField(max_length=30)
        family_name = models.CharField(max_length=30)
        full_name = models.CharField(max_length=60)
    
        class Meta:
            managed = False
    

    【讨论】:

      【解决方案2】:

      答案可能在于 django 相当新的查询注释:

      https://docs.djangoproject.com/en/1.11/ref/models/expressions/#using-f-with-annotations

      company = Company.objects.annotate(
          chairs_needed=F('num_employees') - F('num_chairs'))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-01-26
        • 2010-12-11
        • 1970-01-01
        • 1970-01-01
        • 2018-10-11
        • 1970-01-01
        • 1970-01-01
        • 2017-04-28
        相关资源
        最近更新 更多