如何在Django模板中将相关的多对多字段显示为表格?

时间:2014-01-07 12:06:41

标签: django django-models django-templates django-views django-queryset

我有2个模特' 会员'和' 活动'。 他们在“很多人”中。关系。

现在我想创建一个视图,显示每个成员在一个事件时和不在时,在这样的html表中显示:

Name    Event1    Event2    Event3   ...
Member1   x                   x      ...
Member2   x         x         x      ...
Member3   x         x
Member4             x         x      ...
   .
   .
   .

等等。

现在问题是事件的数量在不断增加。 我唯一的想法是在视图中创建一个html表,但这不是最优的。

是否有可能手动创建查询集,其中首先包含一个成员,然后是所有事件,然后是下一个成员,然后是所有事件?等等.. 或者有一个由Django管理的真正简单方法来访问模板中的manytomany字段

进一步参考我的模型:

class Member(models.Model):
    KAPELLMEISTER='KM'
    FLOETE='FL'
    KLARINETTE='KL'
    SAXOPHON='SX'
    FLUEGELHORN='FH'
    TENORHORN='TH'
    HORN='HR'
    TROMPETE='TR'
    POSAUNE='PS'
    TUBA='TU'
    SCHLAGZEUG='SZ'

    INSTRUMENTS=(
                 (KAPELLMEISTER,'Kapellmeister'),
                 (FLOETE,'Floete'),
                 (KLARINETTE,'Klarinette'),
                 (SAXOPHON,'Saxophon'),
                 (FLUEGELHORN,'Fluegelhorn'),
                 (TENORHORN,'Tenorhorn'),
                 (HORN,'Horn'),
                 (TROMPETE,'Trompete'),
                 (POSAUNE,'Posaune'),
                 (TUBA,'Tuba'),
                 (SCHLAGZEUG,'Schlagzeug')
                 )


    name = models.CharField('Name',max_length=200)
    instrument = models.CharField('Instrument',
                                  max_length=2,
                                  choices=INSTRUMENTS,
                                  null=False)
    bool_musikschueler =  models.BooleanField('Musikschueler')
    bool_student = models.BooleanField('Student')

    def __unicode__(self):
        return self.name

    @classmethod
    def create(cls, name, instrument, musikschueler, student):
        member = cls(name=name, instrument=instrument, bool_musikschueler=musikschueler, bool_student = student)
    return member


class Event(models.Model):
    PROBE='PR'
    BEGRAEBNIS='BG'
    MARSCHMUSIK='MM'
    KONZERT='KO'
    WECKRUF='WR'

    TYPES=(
           (PROBE,'Probe'),
           (BEGRAEBNIS,'Begraebnis'),
           (MARSCHMUSIK,'Marschmusik'),
           (KONZERT,'Konzert'),
           (WECKRUF,'Weckruf')
          )

    date = models.DateField('Datum')
    type = models.CharField(max_length=2,
                            choices=TYPES,
                            default=PROBE)
    description =  models.TextField(max_length=200, blank=True)
    anwesend = models.ManyToManyField(Member)#TODO: Widget fuer Django Admin aendern

    def __unicode__(self):
        return str(self.date.strftime("%Y-%m-%d"))+" , "+self.type

    @classmethod
    def create(cls, date, type, description):
        event = cls(date=date, type=type, description=description)
        return event

和我的html模板:

<table>
<tr><th>Name</th>
{% for event in all_events %}
    <th>{{event}}</th>
    {% endfor %}
</tr>
    {% for member in all_members %}
    <tr>
        <td>{{ member.name }}</td>
        <td>{{ event.anwesend }}</td>
    </tr>
    {% endfor %}
</table>

和我的实验观点:

def statistiken(request):
    all_members = Member.objects.all()
    all_events = Event.objects.all()
    for member in all_members:
        anwesend=member.name+": "
        for event in member.event_set.all():
            anwesend+=str(event)
            print(anwesend)

    context = {'all_members': all_members,
               'all_events' : all_events}
    return render(request, 'anwesenheitsapp/statistiken.html', context)

1 个答案:

答案 0 :(得分:0)

与您的评论相关的更新:

from itertools import count, repeat

def statistiken(request):
    # Get all members
    members = Member.objects.all()

    # Get maximum number of related events
    max_n_events = max(member.event_set.all().count() for member in members)

    # Create a list to hold table data
    table_data = []
    for member in members:
        # Get all related events for the member
        events = member.event_set.all()
        # Get number of events
        n = events.count()

        # Append a iterator with member instance, event instances, and
        # repeating empty strings to fill up the table
        table_data.append(chain([member], events, repeat('', max_n_events-n)))

    context = {'table_data': table_data}
    return render(request, 'anwesenheitsapp/statistiken.html', context)

和你的模板:

<table>
<tr>
{% for row in table_data %}
    {% for col in row %}
        <td>{{ col }}</td>
    {% endfor %}
{% endfor %}
</tr>
</table>

表中的字符串将是您的成员和事件的__unicode__()结果,后跟空单元格。


(旧答案)

要从成员实例访问所有相关事件,请使用event_set.all()

您的模板可能如下所示:

<table>
{% for member in all_members %}
    <td>{{ member }}</td>
    {% for event in member.event_set.all %}
        <td>{{ event }}</td>
    {% endfor %}
{% endfor %}
</table>

哪个应该生成这个表

| member0 | related_event00 | related_event01 | ... | related_event_0n|
| member1 | related_event10 | related_event11 | ... | related_event_1n|
| .... |
| memberm | related_eventm0 | related_eventm1 | ... | related_event_mn|

(当然,n可能与成员不同)