【问题标题】:How do I display related many-to-many fields as a table in Django template?如何在 Django 模板中将相关的多对多字段显示为表格?
【发布时间】:2014-01-25 02:40:09
【问题描述】:

我有 2 个模型“Member”和“Event”。 它们处于“多对多”关系中。

现在我想创建一个视图,显示每个成员何时参加活动,何时不在,在这样的 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)

【问题讨论】:

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


    【解决方案1】:

    与您的评论相关的更新:

    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 可能不同)

    【讨论】:

    • 我修正了一个小错字 - Django 模板中的方法调用不应包含括号
    • 谢谢,但是有没有办法在成员实例在事件的ManyToMany字段中没有条目时插入空格?
    • @jteichert 我更新了我的答案,请查看:)
    猜你喜欢
    • 2012-03-29
    • 2017-09-19
    • 2015-10-03
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    • 2021-06-20
    • 2014-07-28
    • 2021-08-28
    相关资源
    最近更新 更多