【问题标题】:Django empty field fallbackDjango空字段回退
【发布时间】:2010-11-23 11:34:31
【问题描述】:

我有一个保存用户地址的模型。该模型必须具有first_namelast_name 字段,因为人们想为收件人(如他的公司等)设置地址。我想要实现的是:

  • 如果地址中的first_name/last_name 字段已填写 - 只需返回该字段
  • 如果地址中的first_name/last_name 字段为空 - 从指向正确django.auth.models.User 的外键中获取相应的字段数据
  • 我希望将其视为将出现在字段查找中的普通 Django 字段
  • 我不想创建一个方法,因为它是一种重构,Address.first_name/last_name 在应用程序的各个地方(也以模型形式等)使用,所以我需要这个尽可能顺利,否则我将不得不在很多地方修补。

【问题讨论】:

    标签: python django django-models model field


    【解决方案1】:

    这里有两个选项。第一种是创建一个动态查找的方法,但使用property 装饰器,以便其他代码仍然可以使用直接属性访问。

    class MyModel(models.Model):
        _first_name = models.CharField(max_length=100, db_column='first_name')
    
        @property
        def first_name(self):
            return self._first_name or self.user.first_name
    
        @first_name.setter
        def first_name(self, value):
           self._first_name = value
    

    这将始终引用 first_name 的最新值,即使相关用户已更改。您可以像获取属性一样获取/设置属性:myinstance.first_name = 'daniel'

    另一种选择是覆盖模型的 save() 方法,以便在您保存时进行查找:

    def save(self, *args, **kwargs):
        if not self.first_name:
            self.first_name = self.user.first_name
        # now call the default save() method
        super(MyModel, self).save(*args, **kwargs)
    

    这样您不必更改数据库,但它只会在保存时刷新 - 因此,如果相关的用户对象已更改但此对象未更改,它将引用旧的用户值。

    【讨论】:

    • 您可以指定 db_column='first_name' 以防止架构更改:docs.djangoproject.com/en/dev/ref/models/fields/#db-column
    • 所以在 @first_name.setter 之后添加 first_name.db_column="first_name" ?我能做到:address = Address.objects.get(first_name="blah") 吗?
    • 我已根据 piquadrat 的评论更新了代码和解释。
    • 感谢您的帮助 :) 它可以完美运行(属性方法),我唯一担心的是 - 我有一个模型表单,它不会用 self.user 填充空白字段。名。设置属性和获取是完美的。
    • 还有一个小问题 - 在进行查找时 django orm 无法解析属性信息字段,它需要原始的 _first_name 字段。
    【解决方案2】:

    虽然这不能满足所有 OP 的要求,但在某些需要在查询集过滤器(数据库级别)中回退的用例中,可以使用 Django 的 Coalesce() 类 (docs)。

    在这种情况下,最简单的解决方案可能是查询集注释(使用来自@daniel-roseman 的answer 的示例):

    queryset = MyModel.objects.annotate(first_name=Coalesce('_first_name', 'user__first_name'))

    从查询集中获得的每个项目将获得一个first_name 属性,其值为_first_name,并回退(如果值为null)到user.first_name

    也就是说,假设您的模型具有 user 关系。

    这可以实现,例如在自定义管理器中,也可以与property 方法结合使用。

    this SO answer 中提供了类似情况的详细示例(覆盖而不是回退)。

    【讨论】:

      猜你喜欢
      • 2015-05-12
      • 2012-06-22
      • 2015-08-09
      • 1970-01-01
      • 1970-01-01
      • 2013-07-02
      • 2018-10-14
      • 2021-06-19
      • 1970-01-01
      相关资源
      最近更新 更多