web-dev-qa-db-ja.com

Djangoテンプレートから多対多「スルー」テーブルのプロパティにアクセスするにはどうすればよいですか?

Django documentation ...

ピザやトッピングの混合やマッチングなど、単純な多対多のリレーションシップのみを処理する場合は、標準のManyToManyFieldで十分です。ただし、2つのモデル間の関係にデータを関連付ける必要がある場合があります。

たとえば、ミュージシャンが属する音楽グループを追跡するアプリケーションの場合を考えてみましょう。人とそのメンバーであるグループとの間には多対多の関係があるため、ManyToManyFieldを使用してこの関係を表すことができます。ただし、グループに参加した日付など、収集したいメンバーシップについては多くの詳細があります。

これらの状況では、Djangoを使用すると、多対多の関係を管理するために使用するモデルを指定できます。その後、中間モデルに追加のフィールドを配置できます。中間モデルは関連付けられます媒介として機能するモデルを指すためにthrough引数を使用するManyToManyFieldを使用します。ミュージシャンの例では、コードは次のようになります。

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

中間モデル(この場合はメンバーシップ)を使用するためにManyToManyFieldを設定したので、多対多の関係を作成する準備が整いました。これを行うには、中間モデルのインスタンスを作成します。

ringo = Person.objects.create(name="Ringo Starr")
paul = Person.objects.create(name="Paul McCartney")
beatles = Group.objects.create(name="The Beatles")

m1 = Membership(person=ringo, group=beatles,
...     date_joined=date(1962, 8, 16),
...     invite_reason= "Needed a new drummer.")

m1.save()

beatles.members.all()
[<Person: Ringo Starr>]

ringo.group_set.all()
[<Group: The Beatles>]

m2 = Membership.objects.create(person=paul, group=beatles,
...     date_joined=date(1960, 8, 1),
...     invite_reason= "Wanted to form a band.")

beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

ソース: http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany

私の質問は、これらの追加属性にアクセスするためのビューとテンプレートの設定方法です。バンドページがあり、バンド名を表示し、メンバーシップレコードを繰り返し処理し、名前とdate_joinedを表示するとします。

テンプレートにバンドオブジェクトを渡す必要がありますか?または、何らかの方法でメンバーシップオブジェクトを渡しますか?

そして、テンプレートにforループをどのように作成しますか?

ありがとう。

44
Alex

最も簡単な方法は、バンドをテンプレートに渡すことです。テンプレートはモデル間の関係をナビゲートすることができ、グループにはメンバーとmembership_setクエリセットマネージャーの両方があります。だからここに私がそれをする方法があります:

見る:

def group_details(request, group_id):
    group = get_object_or_404(Group, pk=group_id)
    return render_to_response('group_details.html',
                              {'group': group})

テンプレート:

<h2>{{ group.name }}</h2>
{% for membership in group.membership_set.all %}
    <h3>{{ membership.person }}</h3>
    {{ membership.date_joined }}
{% endfor %}
37
Rory Hart

それが唯一の解決策かどうかはわかりませんが、関係オブジェクトをテンプレートに渡すことは確かに機能します。ビューで、MembershipオブジェクトのQuerySetを取得します。

_rel = Membership.objects.filter( group = your_group ).select_related()
_

それをテンプレートに渡し、そこで_{% for %}_で繰り返し処理できます

_{% for r in rel %}
     {{ r.person.name }} joined group {{ r.group.name }} on {{ r.date_joined }}<br />
{% endfor %}
_

select_related()のため、これは追加のクエリを実行しないことに注意してください。

6
cji