Alejandro Veintimilla
Alejandro Veintimilla

Reputation: 11523

Django form not passing value to cleaned_data

I have this view:

def new_booking(request):

    if request.method == "POST":
        form = BookingForm(request.POST, request.FILES)
        print "form before clean: %s" % form.data  # Data is here
        if form.is_valid():
            form.save()

and this form:

class BookingForm(forms.ModelForm):

    def clean(self):
        print "form data in clean method: %s" % self.cleaned_data
        hora = self.cleaned_data['hora']  # !!! KeyError
        print hora

    class Meta:
        model = Booking
        fields = ['hora', 'nombre', 'email', 'archivo']
        widgets = {
            'nombre': forms.TextInput(attrs={'class': 'form-control'}),
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'archivo': forms.FileInput(attrs={}),
            'hora': forms.TextInput(attrs={'class': 'form-control date', 'id': 'booking_time', 'readonly': 'readonly'})
        }

So.. the first print (the one in the view) gives me this:

form before clean: <QueryDict: {u'hora': [u'Jueves 4 de Febrero a las 9:00 am '], u'nombre': [u'Alejandro'], u'csrfmiddlewaretoken': [u'**********'], u'email': [u'[email protected]']}>

The second print, the one in the clean method, gives me this:

form data in clean method: {'nombre': u'Alejandro', 'email': u'[email protected]', 'archivo': <InMemoryUploadedFile: SO_username_admin_upZnsyk.png (image/png)>}

As you can see, for some reason I don't understand, the hora kwarg has disappeared from the data dict: It doesn't show up in self.cleaned_data.

Extra info: I need to manipulate it in the clean method cause I'm receiving a string I need to coerce into a datetime. But, why isn't it there?

Upvotes: 0

Views: 3559

Answers (3)

Alejandro Veintimilla
Alejandro Veintimilla

Reputation: 11523

Ok, the solution was to declare the field explicitly:

class BookingForm(forms.ModelForm):

    hora = forms.CharField(max_length=150, required=True,
                           widget=forms.TextInput(attrs={'class': 'form-control date', 'id': 'booking_time', 'readonly': 'readonly'}))  #HERE


    def clean_hora(self):            

        hora = self.cleaned_data['hora']

        return process_time_string(hora)


    class Meta:
        model = Booking
        fields = ['hora', 'nombre', 'email', 'archivo']
        widgets = {
            'nombre': forms.TextInput(attrs={'class': 'form-control'}),
            'email': forms.EmailInput(attrs={'class': 'form-control'}),
            'archivo': forms.FileInput(attrs={}),
            'hora': forms.TextInput(attrs={'class': 'form-control date', 'id': 'booking_time', 'readonly': 'readonly'})
        }

Then, I can receive the data in self.cleaned_data['hora'] and process it in the function clean_hora as @LostMyGlasses suggested. The function process_time_string just gets the string, calls strptime and returns a datetime.

Upvotes: 0

LostMyGlasses
LostMyGlasses

Reputation: 3144

You declare 'hora' in your form as a TimeInput, but the value you receive in request.POST is a string that not only contains the time, but also the date. For that reason, the value is invalid and 'hora' is not set in form.cleaned_data when the clean() method is called. I guess form.is_valid() returns false.

Upvotes: 1

Shang Wang
Shang Wang

Reputation: 25539

You need to call the base class clean method first to get the cleaned_data:

def clean(self):
    cleaned_data = super(BookingForm, self).clean()
    print "form data in clean method: %s" % cleaned_data
    hora = self.cleaned_data['hora']
    print hora

Django doc example of clean method.

Upvotes: 1

Related Questions