Django空场后备

时间:2009-08-27 17:47:49

标签: python django django-models models field

我有一个包含用户地址的模型。此模型必须具有first_name和last_name字段,因为有人希望将地址设置为收件人(如他的公司等)。我想要实现的是:

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

感谢您的帮助:)

2 个答案:

答案 0 :(得分:6)

这里有两种选择。第一个是创建一个动态查找的方法,但使用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)

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

答案 1 :(得分:0)

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

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

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

从查询集中获得的每个项目都将获得一个first_name属性,该属性的值为_first_name,其备用项(如果值为null,则退回到{{1} }。

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

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

answer中提供了类似情况的详细示例(覆盖而不是后备)。