Model中的Dynamic Multiwidget / MultivalueField

时间:2017-04-06 12:11:32

标签: django django-models django-forms

开头很简单:

class Question(models.Model):
    question_string = models.CharField(max_length=255)
    answers = models.CharField(max_length=255)

答案是字符串列表的json,例如['是','否']。答案数量是动态的。 我现在面临的挑战是为这个模型写一个表格。

现状是:

class NewQuestionForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(NewQuestionForm, self).__init__(*args, **kwargs)

        if self.instance:
            self.fields['answers'] = AnswerField(num_widgets=len(json.loads(self.instance.answers)))

    class Meta:
        model = Question
        fields = ['question']
        widgets = {
            'question': forms.TextInput(attrs={'class': "form-control"})
        }


class AnswerField(forms.MultiValueField):
    def __init__(self, num_widgets, *args, **kwargs):
        list_fields = []
        list_widgets = []
        for garb in range(0, num_widgets):
            field = forms.CharField()
            list_fields.append(field)
            list_widgets.append(field.widget)

        self.widget = AnswerWidget(widgets=list_widgets)
        super(AnswerField, self).__init__(fields=list_fields, *args, **kwargs)

    def compress(self, data_list):
        return json.dumps(data_list)

class AnswerWidget(forms.MultiWidget):

    def decompress(self, value):
        return json.loads(value)

问题是:我得到'JSON对象必须是str,而不是带有'{{field}}'的模板中的'NoneType''

有什么问题?

1 个答案:

答案 0 :(得分:1)

我发现了问题。我忘了在Meta'字段'类中添加“答案”。

所以我从Model创建的动态Multiwidget示例是:

class NewQuestionForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        # need this to create right number of fields from POST
        edit_mode = False
        if len(args) > 0:
            edit_mode = True
            answer_fields = 0
            for counter in range(0, 20):
                answer_key = "answers_" + str(counter)
                if args[0].get(answer_key, None) is not None:
                    answer_fields = counter + 1
                else:
                    break
        super(NewQuestionForm, self).__init__(*args, **kwargs)
        if edit_mode:
            self.fields['answers'] = AnswerField(num_widgets=answer_fields, required=False)
        # get number of fields from DB
        elif 'instance' in kwargs:
            self.fields['answers'] = AnswerField(num_widgets=len(json.loads(self.instance.answers)), required=False)
        else:
            self.fields['answers'] = AnswerField(num_widgets=1, required=False)

    class Meta:
        model = Question
        fields = ['question', 'answers']
        widgets = {
            'question': forms.TextInput(attrs={'class': "form-control"})
        }

    def clean_answers(self):
        temp_data = []
        for tdata in json.loads(self.cleaned_data['answers']):
            if tdata != '':
                temp_data.append(tdata)
        if not temp_data:
            raise forms.ValidationError('Please provide at least 1 answer.')
        return json.dumps(temp_data)

'clean_answers'有2个门户:1。删除空答案。 2.我未能在第一个小部件上设置必需属性。所以我在这里检查至少有一个答案存在

class AnswerWidget(forms.MultiWidget):

    def decompress(self, value):
        if value:
            return json.loads(value)
        else:
            return ['']


class AnswerField(forms.MultiValueField):
    def __init__(self, num_widgets, *args, **kwargs):
        list_fields = []
        list_widgets = []
        for loop_counter in range(0, num_widgets):
            list_fields.append(forms.CharField())
            list_widgets.append(forms.TextInput(attrs={'class': "form-control"}))
        self.widget = AnswerWidget(widgets=list_widgets)
        super(AnswerField, self).__init__(fields=list_fields, *args, **kwargs)

    def compress(self, data_list):
        return json.dumps(data_list)