Существует много возможностей для совершенствования. Используя через ManyToManyField, вы можете явно определить таблицу соединений, которую мы можем удобно рассматривать как одно посещение города во время конкретной поездки. Во время этого визита у нас были мероприятия, поэтому активность должна быть чужой для посещения.
Для каждого внешнего ключа в таблице, Django добавит API-менеджер удобства для наборов объектов на противоположной стороне отношения. Destination
будет иметь visit_set
, но будет Trip
. Аналогично, из-за visit
иностранного ключа в Activity
каждое посещение будет иметь activity_set
.
Первый запуск с моделями:
from django.db import models
# Create your models here.
class Destination(models.Model):
city_name=models.CharField(max_length=50)
class Trip(models.Model):
departing_on=models.DateField()
returning_on=models.DateField()
destinations=models.ManyToManyField(Destination, through='Visit')
class Visit(models.Model):
destination=models.ForeignKey(Destination)
trip=models.ForeignKey(Trip)
class Activity(models.Model):
name=models.CharField(max_length=50)
visit=models.ForeignKey(Visit)
Затем давайте немного изменим list_trip
, добавил print_trip для ясности того, что происходит в шаблоне:
def list_trip(request, template_name = 'trip-list.html'):
return render_to_response(template_name, {
'page_title': 'List of trips',
'trips': Trip.objects.all(),
})
def print_trips():
for trip in Trip.objects.all():
for visit in trip.visit_set.select_related().all():
print trip.id, '-', visit.destination.city_name
for act in visit.activity_set.all():
print act.name
И, наконец, улучшенный шаблон:
{% block content %}
{% for trip in trips %}
{{ trip.id }} - {{ trip.name }}
{% for visit in trip.visit_set.select_related.all %}
{{ visit.destination.city_name }}
{% for act in visit.activity_set.all %}
{{ act.name }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endblock %}
Еще есть возможности для улучшения производительности. Обратите внимание, что я использовал select_related. Это будет выполнять предварительную выборку всех адресатов во время выборки посещений, так что для visit.destination.city_name не потребуется повторный вызов БД. Однако это не работает для обратных отношений ManyToMany (в нашем случае все члены activity_set). В Django 1.4 появится новый метод prefetch_related, который также разрешит это.
А пока прочитайте Эффективный обратный поиск , чтобы узнать, как еще больше сократить количество обращений к БД. В комментариях также упоминаются несколько доступных решений.