Django - 计算模板中每行过滤后的模型实例 table

Django - Counting filtered model instances per row in a template table

假设我有以下 Django 模型:

class House(Model):
    author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    title = CharField(max_length=200, default='')
    text = TextField(default='')
    rooms = IntegerField(null=True)

class Room(Model): 
    author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    title = CharField(max_length=200, default='')
    text = TextField(default='')
    house = CharField(max_length=200, default='')
    furniture = IntegerField(null=True)

class Furniture(model): 
    author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    title = CharField(max_length=200, default='')
    text = TextField(default='')
    room = CharField(max_length=200, default='')

我想在模板中生成以下 table:

Room In house Amount of furniture
Living Room Summer house 5
Kitchen Summer house 8
Bedroom Summer house 2
Bathroom Main house 3

其中“家具数量”列计算“家具”模型的实例,其中字段“房间”等于该行“房间”列中的条目。

我正在尝试弄清楚如何做到这一点,我找到了几种不同的方法 - 从最多 ideal/pythonic 到最少 ideal/pythonic。

  1. 在模型中构建某种机制。这将是完美的,但我似乎找不到任何明显的方法来做到这一点。
  2. 在 views.py 的视图中添加一个生成字典的函数。很容易构建(收集“房间”的名称,制作一个 for 循环,对模型“家具”上的每个房间进行过滤查询,添加一个计数器变量,并构建一个字典)但不是很灵活或 pythonic。
  3. 使用数据tables 等第三方模块。感觉有点矫枉过正 - 但可能是更好的长期解决方案?
  4. 在模板语言中设置一些真正的恶作剧。由于您不能在模板中声明变量,我想这将是一个由嵌套循环、条件和自定义模板标签组成的蜘蛛网。

我应该选择哪种方法?

您应该 ForeignKey [Django-doc] to link models. This is part of database normalization [wiki] 来防止 数据重复 并使数据库更易于管理:

class House(Model):
    author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    title = CharField(max_length=200, default='')
    text = TextField(default='')

class Room(Model): 
    author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    title = CharField(max_length=200, default='')
    text = TextField(default='')
    house = <strong>ForeignKey(</strong>House, on_delete=CASCADE<strong>)</strong>

class Furniture(model): 
    author = ForeignKey(settings.AUTH_USER_MODEL, on_delete=CASCADE)
    title = CharField(max_length=200, default='')
    text = TextField(default='')
    room = <strong>ForeignKey(Room</strong>, on_delete=CASCADE<strong>)</strong>

也不需要存储RoomFurniture的数量:您可以在需要时确定。在您看来,您可以使用以下方式查询 Room 模型:

from <em>app_name</em>.models import Room
from django.db.models import Count

def some_view(request):
    rooms = Room.objects.select_related('house').annotate(
        <strong>num_furniture=Count('furniture')</strong>
    )
    return render(request, '<em>app_name</em>/some_template.html', {'rooms': rooms})

因此我们在这里用 FunitureCount('furniture') 的相关数量注释 Rooms。数据库将简单地计算每个 RoomFurniture 的数量:这更健壮,因为它在创建、更新、删除 FurnitureRoom 时不需要逻辑,等等

然后在模板中,您可以使用以下方式呈现 table:

<table>
  <thead>
    <tr><th>Room</th><th>In house</th><th>Amount of furniture</th></tr>
  </thead>
  <tbody>
  {% for <strong>room in rooms</strong> %}
    <tr><td>{{ room.title }}</td><td>{{ room<strong>.house.title</strong> }}</td><td>{{ room<strong>.num_furniture</strong> }}</td></tr>
  {% endfor %}
  </tbody>
</table>