Reputation: 171
Let's say I have the following django models:
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='')
And I want to generate the following table in a template:
Room | In house | Amount of furniture |
---|---|---|
Living Room | Summer house | 5 |
Kitchen | Summer house | 8 |
Bedroom | Summer house | 2 |
Bathroom | Main house | 3 |
Where the column "Amount of furniture" counts the instances of the "furniture" model where the field "room" is equal to that of the entry in the column "room" for that row.
I'm trying to figure out how to do this, and I've landed on a few different ways - ranked from most ideal/pythonic to least ideal/pythonic.
Which approach should I go for here?
Upvotes: 1
Views: 317
Reputation: 477284
You should work a ForeignKey
[Django-doc] to link models. This is part of database normalization [wiki] to prevent data duplication and making databases more manageable:
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)
there is also no need to store the number of Room
s or Furniture
: you can determine that when necessary. In your view you can query the Room
model with:
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})
here we thus annotate the Room
s with the number of related Funiture
with Count('furniture')
. The database will simply count the number of Furniture
s per Room
: this is more robust since it does not require logic when creating, updating, removing a Furniture
, Room
, etc.
and in the template, you then can render the table with:
<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>
Upvotes: 2