【问题标题】:Django: combine items from two queries (two different Models) togetherDjango:将来自两个查询(两个不同的模型)的项目组合在一起
【发布时间】:2014-05-09 09:05:57
【问题描述】:

我正在使用 Django 构建一个事件平台,其中包含一些事件 public 和一些 invite-only。以下是它的基本工作原理:

  • 每个事件都基于 Event 模型。

  • 私人活动只有受邀的客人才能看到:这是实现的 通过引用事件和来宾的 Invite 模型。

  • 用户可以告知他们是否会参加活动 通过存储关联事件的Answer模型,用户 和答案。

  • AnswerInvite 模型完全相互独立,这样我就可以将 Answer 模型用于公共和私人活动。


我想要达到的目标:

对于我被邀请的每个事件,显示邀请(event.creator 邀请您到 event.name),如果存在,我的相关答案,否则显示一个表单来回答。

所以我认为我正在尝试做的是获取我被邀请的所有事件(我对此没有问题)并将其加入我的答案(其中用户=我)。问题是答案可能还不存在——如果我还没有回答的话。

理想情况下,我会将所有这些都放在一个查询中,这样我就可以在模板中执行类似的操作:invite_event.answer 并显示答案(如果存在)。

编辑:

所以我认为我最终需要的是混合两个查询:一个获取我被邀请的所有事件 (1),另一个获取这些事件的所有答案 (2)。

(1)

latest_events_invited = Event.objects.filter(invite__user_invited=request.user)

(2)

answers_events_invited = Answer.objects.filter(user_answering=request.user, event__in=latest_events_invited)

类似于:对于 latest_events_invited 中的每个事件,附加来自 answers_events_invited 的相应答案。

有什么想法吗?


代码:

我的模板(index.html):

<h3>Invites</h3>
{% if latest_invites_list %}
    <ul>
    {% for event in latest_events_invited %}
        <li>
            {{ event.creator }} invited you to {{ event }}<br/ >

            <!--IDEALLY:-->
            {% if event.answer %}
                    You answered: {{ answer.answer }}
            {% else %}
                <form action="{% url 'events:answer_event' invite.event.id %}" method="post">
                    {% csrf_token %}
                    Answer:
                    <select name="answer">
                        <option value="1" >Attending</option>
                        <option value="2" >Not attending</option>
                    </select>
                    <input type="submit" name="submit" value="Answer">
                </form>
            {% endif %}
        </li>
    </ul>
{% else %}
    <p>No invites.</p>
{% endif %}

视图(views.py)

def index(request):

    if request.user.is_authenticated():
        latest_events_invited = Event.objects.filter(invite__user_invited=request.user)
        latest_answers_list = Answer.objects.filter(user_answering=request.user, event__in=latest_events_invited)
        
        #do something with those to get: "latest_events_invited_with_answers"

        context = {'latest_events_invited':latest_events_invited, 'latest_answers_list':latest_answers_list}

    else:
        [...]

return render(request, 'events/index.html', context)

还有模特。

活动

class Event(models.Model):
    PRIVACY_CHOICES = (
        (0, 'Public'),
        (1, 'Invite only'),
    )

    name = models.CharField(max_length=200)
    [...]
    privacy = models.PositiveSmallIntegerField(max_length=1, choices=PRIVACY_CHOICES, default=0)
    invited = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Invite', related_name='events_invited', blank=True)
    answers = models.ManyToManyField(settings.AUTH_USER_MODEL, through='Answer', related_name='events_answered', blank=True)

邀请

class Invite(models.Model):

    user_invited = models.ForeignKey(settings.AUTH_USER_MODEL)
    event = models.ForeignKey(Event)
    created = models.DateTimeField(default=timezone.now, editable=False)

    class Meta:
        unique_together = (("user_invited", "event"),)

回答

class Answer(models.Model):

    ANSWER_CHOICES = (
        (1, 'Attending'),
        (2, 'Not attending'),
    )

    user_answering = models.ForeignKey(settings.AUTH_USER_MODEL)
    event = models.ForeignKey(Event)
    answer = models.PositiveSmallIntegerField(max_length=1, choices=ANSWER_CHOICES)

    class Meta:
        unique_together = (("user_answering", "event"),)

希望这里有人可以帮助我。
谢谢。

【问题讨论】:

    标签: mysql sql django postgresql


    【解决方案1】:

    好的,所以我想通了。我不知道这是否是最佳解决方案,但它现在有效。
    最后,它只有 2 个查询,我结合了 for 循环。

    代码如下:(views.py)

    def index(request):
        if request.user.is_authenticated():
            latest_events_invited = Event.objects.filter(invite__user_invited=request.user)
            latest_answers_for_events = Answer.objects.filter(user_answering=request.user, event__in=latest_events_invited)
    
            for event in latest_events_invited:
                for answer in latest_answers_for_events:
                    if answer.event.id == event.id:
                        event.answer = answer.answer
                    else:
                        event.answer = ''
    
        context = {'latest_events_invited': latest_events_invited,}
    
        return render(request, 'events/index.html', context)
    

    然后我可以直接在模板 (index.html) 中访问答案,如下所示:

    {{ event.answer }}
    

    【讨论】:

      【解决方案2】:

      一个选项是在有人被邀请时自动添加答案,默认为否。使用 Invite 的 post_save 信号或覆盖保存方法,这样您就不必每次都创建关联的答案。

      另一个可能更好的选择是在视图中而不是在模板中执行逻辑。检查答案是否存在;如果是,则将答案列表传递给模板;如果不是,则传递一个空列表。

      编辑:或者,更好的是:

      在视图中:

      try:
        user_answer = Answer.objects.filter(user_answering = request.user).filter(event=event)
      except ObjectDoesNotExist:
        answer = None
      

      EDIT2:或者怎么样:

      Answer.objects.filter(user_answering = request.user).filter(event__in=Event.objects.filter(user__in = event.invited))
      

      【讨论】:

      • 拥有独立的 Answer 和 Invite 模型的原因之一是避免在 db 中有空字段。至于视图中的逻辑,这就是我正在寻找的解决方案。不过,您的建议是为每个事件添加一个查询,对吗?难道不能一次将整个答案表加入到不存在的行中吗?
      • 查看我的更新回复。我想我找到了一个更优雅的解决方案。尽管如此,我认为通过您的模型设置,不可能不对每个事件进行查询,除非您可以使用空字段。也许在原始 SQL 中,我不太擅长,但绝对不是在 Django 中。
      • 感谢您的回答。我希望这很容易,但我认为这不会奏效。看,我不只有一个活动,我得到了一份我被邀请的所有活动的列表。否则,如果您能想到更有意义的方法,我愿意更改我的模型设置。
      • 那么遍历所有事件?你期望会有很多吗?如果是这样,如何:Answer.objects.filter(user_answering = request.user).filter(event__in=Event.objects.filter(user__in = event.invited))?这也是我现在的回复,以防这里的格式难以阅读。
      • 这样做的问题是,如果用户还没有回答,即使可能有邀请,也不会有结果。我认为解决方案是这样的:获取我被邀请的所有事件(查询#1),获得我对这些事件的所有答案(查询#2),然后(步骤3)以某种方式混合这两个查询但是这是我想不通的部分。
      猜你喜欢
      • 2010-09-23
      • 2018-06-27
      • 2018-03-30
      • 2012-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多