Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Debugging form validation in Pycharm

I am trying to debug form validation in Django with Pycharm. Validation of my form fails at an image I upload via an ImageField and I want to find out why it's failing on it. However, whenever I try to debug the validation process and step into and through the form initialization with the POST data, it doesn't even try validating and at the end throws an error because of empty fields when trying to save the form data to the database. It is driving me nuts... how can the behavior change depending on whether I observe the individual steps or not? I also tried to set several break points, e.g. during the full-clean method of the BaseForm class, but it doesn't seem to ever get there.

Edit: Here is some code

My model & form:

class Car(models.Model):
    ...
    image = models.ImageField(upload_to='car_images/',blank=True,null=True)

class CarForm(ModelForm):
    class Meta:
        model = Car

My View:

def create_car(request):
    if request.method == 'POST':
        car_form = CarForm(request.POST,request.FILES)
        if car_form.is_valid():
            ...
like image 966
Se Norm Avatar asked Aug 27 '12 13:08

Se Norm


1 Answers

This is a real pain. I've got this problem twice, and still have not found good solution.

This is an example of safe debugging when you override the form's __init__ method.

class MyForm(forms.ModelForm):

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

        # Disable form validation for debugging purposes unless the
        # object is fully initialized. Set breakpoints BELOW this line.
        del self._errors

        # Write some additional initializations here, debug safely.
        ...

        # Initialization is finished. Enable form validation.
        self._errors = None

If you want to debug the base form classes then patch Django code in the same way.

You can either leave or remove this additional code after debugging - this does not make significant difference. But it's better to leave for the case you need this in the future.

So, what is really going on here?

(bugreport on Django project site: https://code.djangoproject.com/ticket/24710)

It seems the problem is that Django's BaseForm.errors property getter (which is really a method with @property decorator) does too much. It calls the full_clean() method which changes the _errors property value so that errors getter does not do same work again on repeating calls.

class BaseForm(object):

    @property
    def errors(self):
        if self._errors is None:
            self.full_clean()
        return self._errors

    def full_clean(self):
        self._errors = ErrorDict()
        ...

Of course PyCharm debugger assumes that properties are just properties, and they do not do critical changes to the internal state of the objects. So the debugger calls the errors getter to show it's value in the "Variables" window when you debug the __ini__ method. And this breaks the normal execution flow.

(This is why you should define methods like get_error() in such cases, not properties)

One possible suggestion may be to avoid breakpoints and step-by-step execution inside of the form's __init__ method. But if you really need to debug it then modify the code so that the _errors property does not exist during the step-by-step execution. This will prevent calls to the full_clean method. PyCharm debugger will receive error each time it will try to access the errors property.

Note: the errors property may be evaluated on any step when execution is paused, even outside of the __init__ method. This probably will not affect the result if all fields are fully initialized already (remember to do this in the __init__ method only). However you may find that you still can not debug the form validation process because the form appears validated before you reach the is_valid method call. In this case set a breakpoint inside of the full_clean method, and don't stop between the form instantiation point and this breakpoint.

like image 170
raacer Avatar answered Sep 18 '22 13:09

raacer