首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Django/SQL模板双条目表

Django/SQL模板双条目表
EN

Stack Overflow用户
提问于 2017-09-21 02:32:28
回答 1查看 210关注 0票数 2

我的django应用程序中有以下模型:

代码语言:javascript
复制
from django.contrib.auth.models import User

class Poll(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(User)

class Choice(models.Model):
    poll = models.ForeignKey(Poll, on_delete=models.CASCADE)
    text = models.CharField(max_length=200)

class Vote(models.Model):
    choice = models.ForeignKey(Choice)
    user = models.ForeignKey(User)

对于给定的Poll,我需要在模板中显示一个双条目表,如下所示,列出在此Poll中投票的所有用户,并为用户投票的每个选项放置一个“x”:

代码语言:javascript
复制
       [choice1] [choice2] [choice3]
[user1]                        x
[user2]    x                   x
[user3]              x          
[user4]              x         x
  1. 使用django ORM实现这一点的最佳方法是什么,以便在填充表时尽量减少数据库的命中?
  2. 哪个对象应该传递给上下文变量中的模板,以便在视图中而不是模板中执行逻辑?

我所知道的问题:

代码语言:javascript
复制
# get all votes for the given Poll (pk)
votes = Vote.objects.filter(choice__poll__pk=pk)
# get all users that has voted
usernames = votes.values('user__username')
# get the choices for the Poll
choices = Poll.objects.get(pk=pk).choice_set.all()
EN

回答 1

Stack Overflow用户

发布于 2017-10-10 07:52:38

我用以下方法解决了这个问题:

代码语言:javascript
复制
# yourapp/models.py
from django.utils.functional import cached_property
from django.db.models import Case, When, BooleanField

class Poll(models.Model):
    title = models.CharField(max_length=200)
    author = models.ForeignKey(User)

    @cached_property
    def choices(self):
        return self.choice_set.order_by('id')

    @cached_property
    def users_choices(self):
        users = User.objects.filter(vote__choice__poll=self)

        for choice  in self.choices:
            users = users.annotate(
                **{str(choice.id): Case(When(vote__choice_id=choice.id, then=True), output_field=BooleanField())}
            )

        return users

例如,在PostgreSQL用户中,在这种sql查询中转换的qs:

代码语言:javascript
复制
SELECT
  "yourapp_user"."id",
  "yourapp_user"."username",
  CASE WHEN "yourapp_vote"."choice_id" = 1
    THEN TRUE
  ELSE NULL END AS "1",
  CASE WHEN "yourapp_vote"."choice_id" = 2
    THEN TRUE
  ELSE NULL END AS "2",
  CASE WHEN "yourapp_vote"."choice_id" = 3
    THEN TRUE
  ELSE NULL END AS "3"
FROM "yourapp_user"
  LEFT OUTER JOIN "yourapp_vote" ON ("yourapp_user"."id" = "yourapp_vote"."user_id")
  LEFT OUTER JOIN "yourapp_choice" ON ("yourapp_vote"."choice_id" = "yourapp_choice"."id")
WHERE "yourapp_choice"."poll_id" = 1

视图和模板可以如下所示(您甚至不需要将上下文传递给模板,所有内容都将从Poll模型属性中获取):

代码语言:javascript
复制
# yourapp/views.py
class PollDetailView(DetailView):
    model = Poll
    template_name = 'user_choices.html'


# yourapp/templates/user_choices.html
{% extends 'base.html' %}{% load customtags %}

{% block content %}
    <h1>{{ poll.title }}</h1>
    <table border="1">
        <tr>
            <th>username</th>
            {% for choice in poll.choices %}<th>choice{{ choice.id }}</th>{% endfor %}
        </tr>
        {% for user_choice in poll.users_choices %}
        <tr>
            <td>{{ user_choice.username }}</td>
            {% for choice in poll.choices %}
                <td>{% if user_choice|get_attr:choice.id %}+{% endif %}</td>
            {% endfor %}
        </tr>
        {% endfor %}
    </table>
{% endblock %}

我必须添加自定义模板过滤器才能通过选择id (可能有更优雅的解决方案,而我错过了):

代码语言:javascript
复制
# yourapp/templatetags/customtags.py
from django import template

register = template.Library()


@register.filter(name='get_attr')
def get_attr(obj, attr_name):
    return getattr(obj, str(attr_name), None)
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46334516

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档