Django - Подсчет отфильтрованных экземпляров модели на строку в таблице шаблонов

Допустим, у меня есть следующие модели 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='')

И я хочу сгенерировать следующую таблицу в шаблоне:

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

В столбце "Количество мебели" подсчитываются экземпляры модели "мебель", у которых поле "комната" равно полю записи в столбце "комната" для данной строки.

Я пытаюсь понять, как это сделать, и остановился на нескольких разных способах - ранжированных от наиболее идеального/питонического к наименее идеальному/питоническому.

  1. Building some sort of mechanism into the model. This would be perfect, but I can't seem to find any obvious way to do it.
  2. Adding a function that generates a dictionary in the view in views.py. Would be easy to build (gather names of "room", make a for loop doing a filter query for each room on the model "furniture", add a counter variable, and build a dictionary) but not very flexible or pythonic.
  3. Using a third party module like datatables. Feels like overkill - but may be a better long term solution?
  4. Setting up some real shenaningans in the template language. Since you can't declare variables in the template, i imagine this would be a spider web of nested loops, conditionals, and custom template tags.

Какого подхода мне следует придерживаться?

Вам следует работать ForeignKey [Django-doc] для связывания моделей. Это часть нормализации баз данных [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 = ForeignKey(House, on_delete=CASCADE)

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

также нет необходимости хранить количество Rooms или Furniture: вы можете определить это при необходимости. В вашем представлении вы можете запросить модель Room с помощью:

from app_name.models import Room
from django.db.models import Count

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

Здесь мы, таким образом, аннотируем Rooms количеством связанных Funitures с Count('furniture'). База данных будет просто подсчитывать количество Furniture на Room: это более надежно, так как не требует логики при создании, обновлении, удалении Furniture, Room и т.д.

и в шаблоне вы можете отобразить таблицу следующим образом:

<table>
  <thead>
    <tr><th>Room</th><th>In house</th><th>Amount of furniture</th></tr>
  </thead>
  <tbody>
  {% for room in rooms %}
    <tr><td>{{ room.title }}</td><td>{{ room.house.title }}</td><td>{{ room.num_furniture }}</td></tr>
  {% endfor %}
  </tbody>
</table>
Вернуться на верх