0

考虑一个房间预订系统。您可能有建筑物、楼层、房间模型以及预订。我们根据房间的建筑和楼层给房间命名:

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 的,在这里我复制并粘贴了一个巨大的混乱注释。那真令人恶心。

我的问题是......还有其他方法吗?

4

2 回答 2

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__')

它更干净,我会在其他地方使用它,但感觉不是很聪明。

于 2016-09-24T20:59:45.900 回答
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
        )
于 2016-09-24T21:42:52.310 回答