Как получить доступ к свойствам таблицы «сквозные» «многие ко многим» из шаблона django? - PullRequest
43 голосов
/ 30 июля 2010

Из документации Django ...

Когда вы имеете дело только с простыми отношениями "многие ко многим", такими как смешивание и сопоставление пиццы и начинки, вам необходим стандартный ManyToManyField.Однако иногда вам может потребоваться связать данные с отношениями между двумя моделями.

Например, рассмотрим случай, когда приложение отслеживает музыкальные группы, к которым принадлежат музыканты.Между человеком и группами, членами которых он является, существует отношение «многие ко многим», поэтому вы можете использовать ManyToManyField для представления этого отношения.Тем не менее, есть много подробностей о членстве, которые вы, возможно, захотите получить, например, о дате вступления человека в группу.

В этих ситуациях Django позволяет вам указать модель, которая будетиспользуется для управления отношениями многих ко многим.Затем вы можете поместить дополнительные поля в промежуточную модель.Промежуточная модель связана с ManyToManyField, использующей аргумент through, указывающий на модель, которая будет выступать в качестве посредника.В нашем примере с музыкантом код будет выглядеть примерно так:

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>]

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

Мой вопрос: как мне настроить мойпросмотреть и шаблон для доступа к этим дополнительным атрибутам.Скажем, у меня есть страница группы, и я хочу отобразить имя группы, перебрать записи о членстве и отображаемые имена и date_joined.

Должен ли я передать объект группы в шаблон?Или я как-то передаю объекты членства?

А как бы создать циклы for в шаблоне?

Спасибо.

Ответы [ 2 ]

36 голосов
/ 30 июля 2010

Самый простой способ - просто передать группу шаблону. Шаблоны способны перемещаться по отношениям между моделями, и в Group есть как менеджеры наборов членов, так и members_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 %}
6 голосов
/ 30 июля 2010

Я не уверен, является ли это только решением или нет, но передача объектов отношения в шаблон, безусловно, работает. По вашему мнению, получите объекты QuerySet of Membership:

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().

...