2012-02-26 25 views
3

私はDjangoの新人です。私はこれまでのところ、その能力に感銘を受けました。私はより複雑なモデルで遊んでいるし、それらを適切に使うのに問題がある。 Django 1.3を使用して、以下の3つのモデルを以下の構造で提示する要約ページを作成しようとしています。言い換えれば、目的地とアクティビティのある旅行のリスト。Djangoと複数の外部キーを持つモデル

  • 旅行1
    • 先1
    • 先2
    • アクティビティ1
  • 旅行2
    • 先1
    • 活動2

モデル

  • トリップ< - > TripDestination < - >宛先(トリップが複数の宛先を持つことができます)
  • 活動 - >トリップ、活動 - >宛先(活動です特定の場所/目的地での旅行のために定義される)
class Destination(models.Model): 
     city_name=models.CharField() 

    class Trip(models.Model): 
     departing_on=models.DateField() 
     returning_on=models.DateField() 
     destinations=models.ManyToManyField(Destination) 

    class Activity(models.Model): 
     destination=models.ForeignKey(Destination, null=False) 
     trip=models.ForeignKey(Trip, null=False)

私は上記の構造を持つページを生成するビューを作成しようとしています。私が今直面している主な問題は、特定の旅行と目的地の活動を表示することです。あなたが下のコードで見ることができるように、私は辞書を構築しており、それは正しいことだとは思っていません。また、ビューは、簡単に言うと

ビュー

def list_trip(request, template_name = 'trip-list.html'): 
    trips = Trip.objects.all() 

    # Build a dictionary for activities -- Is this the right thing to do? 
    activities = Activity.objects.filter(trip__in=trips) 
    activities_by_trips = dict() 
    for activity in activities: 
     if activity.trip_id not in activities_by_trips: 
      activities_by_trips[activity.trip_id] = dict() 

     if activity.destination_id not in activities_by_trips[activity.trip_id]: 
      activities_by_trips[activity.trip_id][activity.destination_id] = [] 

     activities_by_trips[activity.trip_id][activity.destination_id].append(activity) 

    return render_to_response(template_name, { 
     'page_title': 'List of trips', 
     'trips': trips, 
     'activities_by_trips': activities_by_trips, 
    })

テンプレート


{% block content %} 
    {% for trip in trips %} 
     {{ trip.id }} - {{ trip.name }} 

     {% for destination in trip.destinations.all %} 
      {{ destination.city_name }} 

      ** This is terrible code -- How to fix that ** 
      {% for key, value in activities_by_trips|dict_lookup:trip.id %} 
       {% if value %} 
        {% for key_prime, value_prime in value|dict_lookup:destination.id %} 
         {{ value_prime.description }} 
        {% endfor %} 
       {% endif %} 
      {% endfor %} 
     {% endfor %} 
    {% endfor %} 
{% endblock %} 

なり、誰かがすべての旅行や活動の概要を得るために私を助けてくださいことができますか?それを達成するための最良の方法は何ですか?モデルは正しいですか?

ありがとうございます!

答えて

13

改善の余地が十分にあります。 ManyToManyFieldのthroughを使用することで、特定の旅行中に都市への単一の訪問として便利に考えることができる結合テーブルを明示的に定義することができます。その訪問の間、私たちは活動をしていたので、アクティビティには外来の訪問が必要です。

テーブル内の各外部キーについて、Djangoは関係の反対側にあるオブジェクトセットに対してAPIコンビニエンスマネージャを追加します。 Destinationvisit_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は別のdbコールを発生しません。しかしこれは逆のManyToMany関係(この場合、activity_setのすべてのメンバー)では機能しません。 Django 1.4にはprefetch_relatedという新しいメソッドが追加され、これも同様に解決されます。

さらに、DBヒット数をさらに減らす方法については、Efficient reverse lookupsをお読みください。コメントでは、すぐに利用可能な解決法もいくつか挙げられています。

+0

digivampireありがとうございました!これはまさに私が探していたものです。 – Martin

関連する問題