django 如何将属性从一个外键相关模型检索到另一个外键相关模型?

nfs0ujit  于 2022-12-14  发布在  Go
关注(0)|答案(1)|浏览(118)

我使用的是django4.1.2和python3.10.8,我有三个模型,一个用于用户管理,一个用于提问,另一个用于回答,如下所述:

class User(AbstractUser):
    phone_number = models.CharField(max_length=14, unique=True)
    first_name = models.CharField(max_length=40)
    father_name = models.CharField(max_length=40)
    email = models.EmailField(unique=True, required=True)
    age = models.CharField(max_length=3)
    username = models.CharField(max_length=8, required=True)

class Question(models.Model):
    question = models.CharField(
        max_length=500,
        null=False,
        unique=True
    )
    creating_staff = models.ForeignKey(
        User,
        null=False,
        on_delete=models.PROTECT,
        to_field="phone_number",
    )
    options = models.JSONField(null=False)
    correct_option = models.CharField(max_length=250, null=False)
    question_ts = models.DateTimeField(auto_now_add=True, null=False)

    class Meta:
        verbose_name = "Question"

    def __str__(self) -> str:
        return f"{self.question}"

class Answer(models.Model):
    answer = models.CharField(max_length=500, null=False)
    question_answered = models.ForeignKey(
        Question,
        null=False,
        on_delete=models.PROTECT,
        related_name="question_answered"
    )
    answering_user = models.ForeignKey(
        User,
        null=False,
        on_delete=models.PROTECT,
        to_field="phone_number",
        related_name="answerer"
    )
    status = models.BooleanField(null=False)
    answer_ts = models.DateTimeField(auto_now_add=True, null=False)

    class Meta:
        verbose_name = "Answer"

    def __str__(self) -> str:
        return f"{self.answer} -- {self.answering_user}"

这是urls.py文件:

from django.urls import path

from .views import (AnswerView)

app_name = "commons"

urlpatterns = [
    path("play/", AnswerView.as_view(), name="play"),
]

我尝试做的是,每当用户登录并希望通过/commons/play/回答一组问题时,在GET请求下,我希望解析出用户以前回答过的所有问题,并始终通过从未回答的问题中随机选择10个问题来显示新问题。
到目前为止,我所做的是:

import random
from django.shortcuts import (redirect, render)
from django.views import View
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin

from .models import (Question, Answer, User)

class AnswerView(LoginRequiredMixin, View):

    def get(self, request):
            answerer = request.user
            total_answers_by_user = Answer.objects.filter(answering_user=answerer)
            questions = Question.objects.all()
            question_list = list()
            for ans in total_answers_by_user:
                for q in questions:
                    if not ans.question_answered == q:
                        question_list.append(q)
            questions_count = question.count()
            try:
                rand_sample = random.sample(range(questions_count), 10)
            except (ValueError, Exception) as e:
                print(f"{e} population for random sample < 10, perhaps new player")
                total_questions = Question.objects.all().count()
                rand_sample = random.sample(range(total_questions), 10)
                questions_to_ask = Question.objects.filter(id__in=rand_sample)
            else:
                questions_to_ask = Question.objects.filter(id__in=rand_sample)

            return render(request, "commons/answer.html", {"questions": questions_to_ask})

但我很怀疑这是否是检索未回答问题或新问题的有效方法,尤其是当涉及多个用户时。是否有更好的方法来检索用户以前回答过的所有问题,而只显示新问题或未回答的问题?
我对你的答复表示感谢。

lnxxn5zx

lnxxn5zx1#

要分解您需要做的事情,首先您需要一个用户回答的问题的ID列表

answered_qs = (Answer.objects
    .filter(answering_user=answerer)
    .values_list('question_answered_id', flat=True)
    )

然后,您需要从所有问题集中排除该问题列表

question_list = Question.objects.exclude(pk__in=answered_qs)

使用related_name s,可以在一个调用中完成所有这些操作。这里我们跟随questions_answered到答案集,其中字段answering_user是我们的请求者,并排除该集合。

questions_list = Question.objects.exclude(question_answered__answering_user=answerer)

如果有 * 很多 * 问题,性能会有轻微的影响,您甚至可以在同一个数据库调用中获得10个问题的随机集,例如,

questions_list = (
    Question.objects
    .exclude(question_answered__answering_user=answerer)
    .order_by('?')[:10]
    )

相关问题