通过外键父模型的字段

时间:2017-10-20 06:25:02

标签: python django django-models foreign-keys

我想根据外键父模型的字段值设置选项。即"问题答案"模型外键"问题"设置为模型"问题"并且该模型包含一个字段" question_type"。如果" question_type" value为1然后将选项设置为a,b,c,d,e或如果值为2,则将选项设置为f,g,h,i,j。表单是作为formset构建的,但这不应该影响它的完成方式吗?

首先,我将选项设置为函数,我在哪里设置它? Forms.py,models.py或views.py? 如果在forms.py中我使用 init 方法吗? 我如何一起得到正确的问题和正确的选择?

如果您需要更多信息,请询问。

Django版本是1.11.5,python版本是3.6.0

forms.py

class AnswerForm(forms.ModelForm):
    class Meta:  
        model = QuestionAnswer
        fields = ['question', 'answer_text', 'questionnaire_key']
        exclude = [] 
        widgets = {
            'question': HiddenInput,
            'answer_text': RadioSelect(choices=CHOICES,
                                                 attrs={'required': 'True'}),
            'questionnaire_key': HiddenInput
            }

models.py

class Question(models.Model):
    questionnaire = models.ForeignKey(Questionnaire)
    question_text = models.CharField(max_length=200)
    question_type = models.CharField(max_length=2)
    def __str__(self):
        return self.question_text

class QuestionAnswer(models.Model):
    questionnaire_key = models.ForeignKey(Questionnaire, null=False, blank=False)
    question = models.ForeignKey(Question, null=False, blank=False)
    answer_text = models.CharField(max_length=1, null=False, default=None)
    def __str__(self):
        return self.answer_text

在视图中,我为formset设置了初始问题数据。然后我将问题和表格集压缩,以便能够在表格中呈现它们,左侧是问题文本,右侧是答案选项。 views.py

def answerpage(request, questionnaire_pk):
    AnswerFormSet = formset_factory(AnswerForm, extra=0)
    questions = Question.objects.filter(questionnaire=questionnaire_pk)
    qname = Questionnaire.objects.get(id=questionnaire_pk)

    if request.method == 'POST':
        answer_formset = AnswerFormSet(request.POST)
        ...
    else:
        quest_id = request.session.get('questionnaire_key', 0)
        question_data = [{'question': question,
                          'questionnaire_key': quest_id} for question in questions]

        answer_formset = AnswerFormSet(initial=question_data)

    combined = zip(questions, answer_formset)
    context = {
        'combined': combined,
        'questions': questions,
        'answer_formset': answer_formset,
        'qname': qname,
    }
    return render(request, 'main/questionnaire_details2.html', context)

更新

表单的初始化方法

def __init__(self, *args, **kwargs):
        extra_info = kwargs.pop('questions', None)
        super(AnswerForm, self).__init__(*args, **kwargs)
        self.fields['answer_text'].widget = RadioSelect()
        self.fields['answer_text'].choices = get_choice_data(self.instance, extra_info)

在此处设置form_kwargs:

formset = AnswerFormSet(form_kwargs={'questions': questions})

如何使用formset?如果我将视图answer_formset = AnswerFormSet(initial=question_data)替换为answer_formset = formset(initial=question_data),则会出现'AnswerFormFormSet' object is not callable错误。我猜这是我应该编辑的那一行吗?

1 个答案:

答案 0 :(得分:0)

您可以区分三种情况:

  1. 选项是修复且始终相同:将choices kwarg与修复的对列表添加到模型字段中。这些选项将由ModelForm的相应字段自动使用。
  2. 选择是在运行时生成的,但与特定实例无关:

    a)forms.Model[Multiple]ChoiceField:向queryset kwarg提供QuerySet,每次创建表单实例时都会对其进行评估。

    b)forms.ChoiceField:提供choices param,它可以是在创建表单实例时调用的可调用对象。这必须返回类似于1的对列表。

  3. 选择是在运行时生成的,它们取决于表单的具体模型实例:

  4. 覆盖表单__init__

    class FooForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            super(FooForm, self).__init__(*args, **kwargs)
            self.fields['bar_field'].choices = create_complex_choices(self.instance)
    

    如果您希望能够使用您在视图中知道的extra_information调整这些选项:

    class FooForm(forms.ModelForm):
        def __init__(self, *args, **kwargs):
            extra_info = kwargs.pop('extra_info', None)
            super(FooForm, self).__init__(*args, **kwargs)
            self.fields['bar_field'].choices = create_complex_choices(self.instance, extra_info)
    
相关问题