Django空字段回退
Posted
技术标签:
【中文标题】Django空字段回退【英文标题】:Django empty field fallback 【发布时间】:2010-11-23 11:34:31 【问题描述】:我有一个保存用户地址的模型。该模型必须具有first_name
和last_name
字段,因为人们想为收件人(如他的公司等)设置地址。我想要实现的是:
first_name
/last_name
字段已填写 - 只需返回该字段
如果地址中的first_name
/last_name
字段为空 - 从指向正确django.auth.models.User
的外键中获取相应的字段数据
我希望将其视为将出现在字段查找中的普通 Django 字段
我不想创建一个方法,因为它是一种重构,Address.first_name
/last_name
在应用程序的各个地方(也以模型形式等)使用,所以我需要这个尽可能顺利,否则我将不得不在很多地方修补。
【问题讨论】:
【参考方案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 中提供了类似情况的详细示例(覆盖而不是回退)。
【讨论】:
以上是关于Django空字段回退的主要内容,如果未能解决你的问题,请参考以下文章