2016-07-14 20 views
0

私はDjangoでQuizを作成しようとしています。複数の質問とQuestionFormがあります。ビューでは、私はQuestionsのセットを取得し、各オブジェクトのQuestionFormのリストを作成します。次に、このリストがテンプレートに送られ、テキストとフォームをそれぞれの質問ごとにレンダリングします。フォームのリストからデータを正しく受け取る方法は?

この方法は非常に不快であり、私はそれを行うためのより簡単で直接的な方法がなければならないと思います。

主流:ユーザーがテストをとる場合、Sittingオブジェクトが

作成されます。このオブジェクトは、ユーザー、クイズ、およびプリロードされた質問に関する情報を保持します。ユーザーがクイズに答えると、質問とユーザーの回答に関する情報を保持するオブジェクトが作成されます(SittingQuestion)。

ご覧のとおり、各フォームにパラメータname = question-idを追加しました。各フォームの結果はanswer-idです。私はIDを解析し、このIDを使ってオブジェクトを作成する必要があります。

特に解析を避けるために助けていただければ幸いです。

私はQuestionFormviewを装着しています:

QuestionForm

class QuestionForm(forms.Form): 
    def __init__(self, question, *args, **kwargs): 
     super(QuestionForm, self).__init__(*args, **kwargs) 
     choice_list = [(x.pk, x.text) for x in question.get_answers_list()] 
     self.fields["question-{}".format(question.id)] = forms.ChoiceField(choices=choice_list, 
                widget=forms.RadioSelect) 

ビュー

def take_quiz(request, id): 
    if request.method == 'GET': 

     sitting = models.Sitting.objects.create(quiz=quiz, user=request.user) 
     sitting.load_questions() 
     formset = [] 
     for q in sitting.sitting_questions.all(): 
      formset.append((q.question, forms.QuestionForm(q.question))) 

     return render(request, 'quiz/quiz.html', context={'formset': formset}) 

    quiz = get_object_or_404(models.LanguageQuiz, pk=id) 
    sitting = get_object_or_404(Sitting,user=request.user,quiz=quiz) 
    if request.method == 'POST': 
     for question in request.POST: 
      question_id = question.split('-')[1] 
      question_object = get_object_or_404(Question,id=question_id) 
      answer_id = request.POST[question_id][0] 
      answer_object = get_object_or_404(Answer,id=answer_id) 
      SittingQuestion.objects.create(sitting=sitting,question=question_object,answer=answer_object) 

MODELS

ここでは
class LanguageQuiz(models.Model): 
    name = models.CharField(max_length=40) 
    language = models.OneToOneField(sfl_models.Language) 
    max_questions = models.IntegerField() 
    time_to_repeat_in_days = models.PositiveIntegerField(default=0) 

    def __str__(self): 
     return '{} test'.format(self.name) 

    def __unicode__(self): 
     return self.__str__() 

class Question(models.Model): 
    language_quiz = models.ForeignKey(LanguageQuiz,related_name='questions') 
    text = models.TextField() 

    def get_answers_list(self): 
     return self.answers.all() 

class Answer(models.Model): 
    question = models.ForeignKey(Question,related_name='answers',on_delete=models.CASCADE) 
    text = models.TextField() 
    correct = models.BooleanField() 

class Sitting(models.Model): 
    user = models.ForeignKey(sfl_models.User, related_name='test_sitting') 
    quiz = models.ForeignKey(LanguageQuiz) 
    date_opened = models.DateTimeField(auto_now_add=True) 
    date_closed = models.DateTimeField(null=True) 
    closed = models.BooleanField(default=0) 

    class Meta: 
     unique_together = ('user','quiz') 

    def __str__(self): 
     return 'Sitting - user: {}; quiz: {}'.format(self.user, self.quiz) 

    def load_questions(self): 
     questions = random.sample(self.quiz.questions.all(),min(self.quiz.max_questions,len(self.quiz.questions.all()))) 
     for question in questions: 
      SittingQuestion.objects.create(question=question,sitting=self) 

class SittingQuestion(models.Model): 
    sitting = models.ForeignKey(Sitting, related_name='sitting_questions', on_delete=models.CASCADE) 
    question = models.ForeignKey(Question, related_name='sitting_questions') 
    answer = models.ForeignKey(Answer,null=True, blank=True) 

答えて

1

が設計に一つの可能​​な改善である:

代わりのQuestionFormQuizFormを作ります。フォームにsitting.sitting_questions.all()を渡し、それぞれ独自のChoiceFieldにします。これにより、フォームの処理がはるかに簡単になります。あなたは何が必要変数を初期化すると、ビューで取り扱いが通常、このような単純なです:

if request.method == 'POST': 
    form = QuizForm(request.POST) 
    if form.is_valid(): 
     # whatever you'd like to do 
else:    # GET 
    form = QuizForm(list_of_questions) 

question idを取得するために解析する必要はありません、あなただけquestion.idまたはquestion.pkを呼び出すことができます。

いくつかの精緻化:

class QuizForm(forms.Form): 
    def __init__(self, questions, *args, **kwargs): 
     super(QuizForm, self).__init__(*args, **kwargs) 
     for question in questions: 
      choice_list = [("QUESTION TEXT", question.text)] 
      choice_list.append([(x.pk, x.text) for x in question.get_answers_list()]) 
      self.fields["question-{}".format(question.id) = forms.ChoiceField(
       choices=choice_list, 
       widget=forms.RadioSelect 
      ) 

更新:オプションの前に質問テキストを追加する方法。

QuizFormにすべての質問であるフィールドがある場合、フィールドを反復処理すると、次の質問フィールドが表示されます。{% for question in form %}questionはフィールドであり、実際のQuestionオブジェクトではないため、ループ内のquestion.textにはアクセスできません。しかし、question.textをchoicesフィールドに追加することもできます(ちょっとハックしましたが機能的です)。ボタンをレンダリングするため

{% for question in form %} 
{% for id, text in question.field.choices %} 
{% if id == 'QUESTION TEXT' %} 
    {{ text }} 
{% else %} 
    <!-- render however you like --> 
{% endif %} 
{% endfor %} 
{% endfor %} 

:次に、このような何かをしようとhttps://docs.djangoproject.com/es/1.9/ref/forms/widgets/#radioselect 私はSO上で同様の質問の多くは選択肢をレンダリングする方法については、すでにあると思います。

+0

ありがとうございますが、それは問題です。私はクイズフォームの中に質問フォームを作成する方法を理解できません。どうぞよろしくお願いいたします。 –

+0

forループを試しましたか?質問の質問のために:choice_list = ...とself.fields ... = forms.ChoiceField ...? また、質問はフォームではなく、クイズフォームのフォームフィールドである必要があります。 –

+0

これはいいですが、もう1つです。私はどのようにラジオ選択の前に各質問のテキストを置くのか分かりません。 {{form}} {%endfor%}のように、質問のテキストを各セットの前に置く方法はありませんが、{{form}} {%endfor%}のようにQuizFormを繰り返し処理できます。私は{%for ....%} {{answer.question.text}}などを試しましたが、何も動作していないようです... –

関連する問題