Django 模型对此反向外键的最佳解决方案

Django models' best solution for this reverse ForeignKey

我正在做一个管理餐厅的个人项目。 我的两个模型面临问题,这些模型是 DiningRoom 和 Table.

DiningRoom 表示餐厅可能拥有的任何区域(例如,我们可以在建筑物内部有一个区域,而在建筑物的露台上有其他区域)。 在每个 DiningRoom 中,我们可以设置 Tables.

的布局

因此,我发现映射它的更面向对象的方法是通过多对一关系 (ForeignKey)。由于一个DiningRoom可以有多个Table,而一个Table只能在一个DiningRoom中。对吗?

所以我的模型是:

class DiningRoom(models.Model):
    account = models.ForeignKey(Account, on_delete=models.CASCADE, null=False)
    name = models.CharField(max_length=50, null=False, blank=False)
    rows = models.IntegerField(max=15, null=False)
    cols = models.IntegerField(max=15, null=False)  # rows and columns are for the room's grid layout.


class Table(models.Model):
    row = models.IntegerField(max=15, null=False)  # The row in the room's grid where the table is at.
    col = models.IntegerField(max=15, null=False)  # the column in the room's grid where the table is at.
    dining_room = models.ForeignKey(DiningRoom, on_delete=models.CASCADE, null=False)  # Here is the problem.

问题是,当我在视图中查询帐户的 DiningRoom 时,我还需要获取与查询集结果中每个 DiningRoom 相关的 Tables。

def dining_rooms(request):
    try:
        account = Account.objects.get(id=request.session['account_id'])
    except Account.DoesNotExists:
        return response(request, "error.html", {'error': 'Account.DoesNotExists'})

    dining_rooms = DiningRoom.objects.filter(account=account)

但我还需要 dining_rooms!

中的 Table 个结果

我找到了两个可能的解决方案,但 none 对我来说似乎是 "correct"。一种是建立多对多关系并验证任何 Table 仅在视图中的一个 DiningRoom 中。第二个也是更糟糕的一个可能是为查询集中获得的每个 DiningRoom 获取一次 Tables(但想象一家有 5 或 6 个不同区域(DiningRooms)的餐厅,它需要获取数据库六次每次)。

反之亦然,获取所有 Tables 和 select_related DiningRooms 是不可能的,因为可能有一个没有 Tables 的 DiningRooms(并且在这种情况下,我们将缺少 DiningRooms)。

处理此问题的最佳方法是什么?谢谢!

您可以使用 related_name 或反向关系,一个可接受的解决方案是在 DiningRoom 模型中创建一个名为 associated_tables() 和 return 的方法,使用 related_name(modelname_set,在本例中为 table_set)。是小写子模型的名字后面加上后缀_set

class DiningRoom(models.Model):
    #your fields

    def associated_tables(self):
        return self.table_set.all()

此外,此视频教程可以让您清空一天,让您更好地了解反向关系: https://youtu.be/7tAZdYRA8Sw