Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
923 views
in Technique[技术] by (71.8m points)

django - disabled field is not passed through - workaround needed

I have a form with which I want to update a MyModel object. On the model there is a unique_together constraint, fieldA together with fieldB. In the form in the clean method I check for this unique constraint.

For some reasons I have to show fieldA as readonly in the update. Thus fieldA is not passed through. My issue is that if the form does not validate, the form is re-shown, but I have lost the value in fieldA.

I tried to reset the cleaned_data['fieldA'], but it does not work. Any idea what to change?

Forms.py

class MyModelUpdateForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyModelUpdateForm, self).__init__(*args, **kwargs)
        self.fields['fieldA'].widget.attrs['readonly'] = True
        self.fields['fieldA'].widget.attrs['disabled'] = True

    def clean(self):
        cleaned_data = self.cleaned_data
        fieldA= self.instance.fieldA
        fieldB = cleaned_data.get("fieldB")

        if MyModel.objects.filter(fieldA=fieldA, fieldB=fieldB).count() > 0:
            #try to reset fieldA, since it is not passed through, since it is disabled
            cleaned_data['fieldA'] = fieldA.pk #does not work
            raise forms.ValidationError('some unique validation error')
        return cleaned_data

Views.py:

myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)

    if request.method == 'POST':
        model_form = MyModelUpdateForm(request.POST, instance=myModelobject )

        if model_form .is_valid():
           ....
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I had a little fun looking into how forms works and came up with multiple solutions, just for the heck of it.

Since you are disabling the widget and not the field, as far as the form is concerned it's always receiving nothing for fieldA and that will always fail validation.

Trying something in the clean() method won't help for invalid forms because clean() data is for processing.

It looks like the way forms pull data for HTML display is field.data, which is a call to field.widget.value_from_datadict(POST, FILES, field_name) so it will always be looking at your POST data.

So I think you have a few options. Hack request.POST, hack the internal form POST data, or hack value_from_datadict.


Hacking request.POST: straight forward, makes sense.

    myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)

        if request.method == 'POST':
            POST = request.POST.copy()
            POST['fieldA'] = myModelobject.fieldA
            model_form = MyModelUpdateForm(POST, instance=myModelobject )

            if model_form .is_valid():
                # ...

Hacking internal dictionary:

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.data.update({ 'fieldA': self.instance.fieldA })

Hacking value_from_datadict: kinda ridiculous, but illustrates what you can learn from digging into the source

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.fields['fieldA'].widget.value_from_datadict = lambda *args: self.instance.first_name

Learned some cool things here : ) Hope it helps.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...