考虑一个房间预订系统。您可能有建筑物、楼层、房间模型以及预订。我们根据房间的建筑和楼层给房间命名:
class Room(models.Model):
number = models.PositiveIntegerField()
name = models.CharField(..)
floor = models.ForeignKey('Floor')
def __str__(self):
return '%s, #%d Floor %d, %s' % (
self.name,
self.number,
self.floor.number,
self.floor.building.name
)
当你在做数百个(例如管理列表、大报告等)时,这效率非常低,所以我开始编写这样的管理器:
class RoomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
roomname=Concat(
'name',
V(', #'),
'number'
V(' Floor '),
'floor__number'
V(', '),
'floor__building__name',
output_field=models.CharField()
),
)
那行得通。它做了我想做的一切。它的速度很快,而且在它执行可怕的多查询字符串构建器之前,我已经对其进行了重新设计__str__
。if hasattr(self, 'roomname'): return self.roomname
但现在最重要的是,我有预订。每个 Booking 实例都链接到一个房间。很多情况下要列出 Bookings,我其实也列出了房间名称。
我所做的是写了一个BookingManager:
class RoomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
roomname=Concat(
'room__name',
V(', #'),
'room__number'
V(' Floor '),
'room__floor__number'
V(', '),
'room__floor__building__name',
output_field=models.CharField()
),
)
但到底是什么?我在重复自己。Django 是关于 DRY 的,在这里我复制并粘贴了一个巨大的混乱注释。那真令人恶心。
我的问题是......还有其他方法吗?