考虑一个房间预订系统。您可能拥有建筑物,楼层,房间模型以及预订。我们根据房屋的建筑和楼层给房间命名:
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
之前做了一个可怕的多查询字符串构建器。
但现在最重要的是,我有预订。每个预订实例都链接到一个房间。在许多情况下,列出预订,我实际上也列出了房间名称。
我所做的就是写一个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的,在这里我复制并粘贴一个巨大的杂乱注释。这太恶心了。
我的问题是......还有其他办法吗?
答案 0 :(得分:1)
写这篇文章的时候我有一个想法,我可以编写一个方法,允许传递前缀用于与房间的关系。这样我可以从任何与房间相关的东西中调用它,它会得到正确的东西:
class RoomManager(models.Manager):
def get_queryset(self):
return super().get_queryset().annotate(
roomname=RoomManager.roomname()
)
@staticmethod
def roomname(prefix=''):
return Concat(
prefix + 'name',
V(', #'),
prefix + 'number'
V(' Floor '),
prefix + 'floor__number'
V(', '),
prefix + 'floor__building__name',
output_field=models.CharField()
)
在BookingManager中,我可以在RoomManager.roomname('room__')
它比较干净,我会在别处使用它,但它感觉不是很聪明。
答案 1 :(得分:0)
这样的事情怎么样?
class Room(models.Model):
number = models.PositiveIntegerField()
name = models.CharField(..)
floor = models.ForeignKey('Floor')
def __str__(self):
return '%s, %s %s' % (
self.name,
self.number,
self.floor
)
class Floor(models.Model):
number = models.PositiveIntegerField()
building = models.ForeignKey('Building')
def __str__(self):
return 'Floor %d, %s' % (
self.number,
self.building
)
class Building(models.Model):
name = models.CharField(...)
def __str__(self):
return '%s' % (
self.name
)