Django 空字段回退
我有一个模型用来保存用户地址。这个模型必须包含 first_name
(名字)和 last_name
(姓氏)这两个字段,因为我们需要把地址设置给收件人(比如他的公司等等)。我想实现的目标是:
- 如果地址中的
first_name
或last_name
字段有值,就直接返回这个字段的值。 - 如果地址中的
first_name
或last_name
字段是空的,就从一个外键中获取相应的字段数据,这个外键指向一个合适的django.auth.models.User
。 - 我希望这个字段能像普通的 Django 字段一样,可以在字段查找中使用。
- 我不想创建一个方法,因为这是重构,而
Address.first_name
和last_name
在应用的多个地方都有用(比如在模型表单中等等),所以我希望这个过程尽可能顺利,否则我就得在很多地方进行修改。
2 个回答
2
虽然这并不能完全满足提问者的所有需求,但在某些情况下,如果需要在数据库查询中使用备用值,可以考虑使用Django的 Coalesce()
类(文档)。
在这种情况下,最简单的解决方案可能是使用查询集注释(参考@daniel-roseman的回答中的例子):
queryset = MyModel.objects.annotate(first_name=Coalesce('_first_name', 'user__first_name'))
这样,从查询集中得到的每个项目都会有一个 first_name
属性,它的值是 _first_name
,如果这个值是 null
,就会使用 user.first_name
作为备用。
也就是说,假设你的模型中有一个 user
关系。
这可以在自定义管理器中实现,也可以与 property
方法结合使用。
关于类似情况的详细示例(覆盖而不是备用)可以参考这个回答。
13
这里有两个选择。第一个是创建一个方法来动态查找,但使用 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)
这样你就不需要更改数据库,但它只在保存时刷新——所以如果相关的用户对象发生了变化,而这个对象没有变化,它将引用旧的用户值。