动态禁用字段时的ModelChoiceField验证错误

时间:2018-03-27 13:32:29

标签: python django django-forms

大家好我有以下定义如下的表格。如果它是传递fte_assignment对象的表单,如果它不是None,那么我想要禁用似乎正在工作的用户字段。问题是,当我提交表单时,我收到以下字段错误Select a valid choice. That choice is not one of the available choices.我想知道我可以更改哪些字段仍然被禁用put会通过验证吗?下面我将包含所需的表单定义信息和视图中的调用。

forms.py

class TeacherForm(forms.Form):
    def __init__(self, *args, **kwargs):
        self.location = kwargs.pop('location', None)
        self.end_year = kwargs.pop('end_year', None)
        # fte_assignment gets passed in if it is an edit this helps
        # with when to fire off our clean method logic
        self.fte_assignment = kwargs.pop('fte_assignment', None)
        super(TeacherForm, self).__init__(*args, **kwargs)

        # THIS IS WHERE I DISABLE THE FORM
        if self.fte_assignment:
            self.fields['user'].disabled = True

    user = forms.ModelChoiceField(
        label='Employee',
        queryset=User.objects.all()
    )
    room = forms.CharField(max_length=6)
    extension = forms.IntegerField()
    job = forms.ModelChoiceField(
        queryset=Job.objects.all()
    )

views.py

fte_assignment = FTEFutureAssignment.objects.get(pk=fte_id)
form_kwargs = {
    'user': fte_assignment.user,
    'room': fte_assignment.room,
    'extension': fte_assignment.extension,
    'job': fte_assignment.job
}
form = TeacherForm(
    request.POST or None,
    initial=form_kwargs,
    location=location,
    end_year=end_year,
    fte_assignment=fte_assignment
)

teacher_form.html

    <form
        method="post"
        novalidate
        action="
            {% if not fte_assignment %}
                {% url 'position_control:teacher_form_add' location_id tab %}
            {% else %}
                {% url 'position_control:teacher_form_edit' location_id fte_assignment.id %}
            {% endif %}
        ">
        {% csrf_token %}
        <div class="form-row">
            <div class="form-group col-4">
                {{ form.errors.user }}
                <label for="">{{ form.user.label }}</label>
                {{ form.user }}
            </div>
            <div class="form-group col-2">
                {{ form.errors.room }}
                <label for="">{{ form.room.label }}</label>
                {{ form.room }}
            </div>
            <div class="form-group col-2">
                {{ form.errors.extension }}
                <label for="">{{ form.extension.label }}</label>
                {{ form.extension }}
            </div>
            <div class="form-group col-4">
                {{ form.errors.job }}
                <label for="">{{ form.job.label }}</label>
                {{ form.job }}
            </div>
        </div>
        <div class="form-row">
            <div class="form-group col">
                <button type="submit" class="btn ok">Submit</button>
            </div>
        </div>
        <a href="{% url 'position_control:teacher_list' location_id %}"><i class="far fa-arrow-circle-left"></i> Return to Teacher List</a>
    </form>

3 个答案:

答案 0 :(得分:1)

对于需要但不应由用户编辑的字段,您通常希望隐藏字段但不禁用该字段

    if self.fte_assignment:
        self.fields['user'].widget = forms.HiddenInput

然后在你的模板中:

{% if form.fte_assignment %}
    {{ form.user }}
{% else %}
    <div class="form-group col-4">
        {{ form.errors.user }}
        <label for="">{{ form.user.label }}</label>
        {{ form.user }}
    </div>
{% endif %}

答案 1 :(得分:0)

您必须在用户MultiChoiceField中添加required = False。

user = forms.ModelChoiceField(
    label='Employee',
    required=False,
    queryset=User.objects.all()

这意味着对于self.fte_assignment没有选择required 不是无案例。 您已禁用用户字段,但未在表单级别将其设置为空。

答案 2 :(得分:0)

只是想把我的工作留给解决方案我想出了原来的问题,以防它将来会帮助任何人。在模板中,如果是编辑,我只是​​使表单呈现用户字段的值而不是实际字段本身。

{% if not form.initial %}
    {{ form.errors.user }}
    <label for="">{{ form.user.label }}</label>
    {{ form.user }}
{% else %}
    <label for="">{{ form.user.label }}</label>
    <p>{{ form.initial.user.last_name }}, {{  form.initial.user.first_name }}</p>
{% endif %}

然后在forms.py中,我对用户字段进行了更改,将其定义为:

user = forms.ModelChoiceField(
    label='Employee',
    required=False,
    queryset=User.objects.all()
)

然后我手动清理用户字段。我之所以这样做的原因是因为如果它是一个编辑并且fte_assignment具有某个属性(业务需求我不会进入),那么值永远不会改变所以我只是从这里的对象返回它。

 def clean_user(self):
    user = self.cleaned_data.get('user', None)

    # If it is an edit check to see if fte_assingment has assignment so
    # we know we are editing a current year object. If it is current
    # year object just return the user from this method so that it
    # gets set in the request.POST and is valid. This is done because
    # in current year users cannot be edited.
    if self.fte_assignment:
        if hasattr(self.fte_assignment, 'assignment'):
            return self.fte_assignment.assignment.user

    # Manually handle user validation
    if not user:
        raise forms.ValidationError('This field is required.')
    return user

我不确定解决方案有多干净,但这对我有用,显然任何批评都是受欢迎的。