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 |
В столбце "Количество мебели" подсчитываются экземпляры модели "мебель", у которых поле "комната" равно полю записи в столбце "комната" для данной строки.
Я пытаюсь понять, как это сделать, и остановился на нескольких разных способах - ранжированных от наиболее идеального/питонического к наименее идеальному/питоническому.
- 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.
- 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.
- Using a third party module like datatables. Feels like overkill - but may be a better long term solution?
- 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>