views:

205

answers:

2

This is a fragment of my code from a view:

    if form.is_valid():
        instance = form.save(commit=False)
        try:
            instance.account = request.account
            instance.full_clean()
        except ValidationError, e:
            # Do something with the errors here... I certainly don't want to do this 180 times.

This is an utter mess. Who would want to handle validation errors manually in every view. If you're not modifying the instance after save(commit=False), you don't have to worry about this, but what about in my case where every model has a foreign key to account which is set behind the scenes and hidden from the user?

Any help is really appreciated.

A: 

Not sure understanding your problem correctly, but if you want to "centralize" the validation of your data in the form you can overwrite the clean() method of the form:

django docs - overwrite clean method

In order to alter data of the object based on the data passed in the form you could overwrite the form.save method:

SOF discussion - overwrite save method

Tom Tom
+1  A: 

I assume form is a ModelForm due to the tag on the question.

Since ModelForm performs model validation when you call is_valid(), it should be sufficient to ensure the model instance it will be validating already contains any behind the scenes changes you want to make before you call is_valid().

You could do that by modifying form.instance with your changes before you call is_valid().

A more generic solution to make these kinds of change within the form itself would be:

class PresetAttrsModelForm(ModelForm):
    def __init__(self, *args, **kwargs):
        preset_attrs = kwargs.pop('preset_attrs', None)
        # Sets up self.instance, among other things
        super(ModelForm, self).__init__(*args, **kwargs)
        if preset_attrs:
            for attr, value in preset_attrs.items():
                setattr(self.instance, attr, value)

class MyModelForm(PresetAttrsModelForm):
    class Meta:
        model = MyModel

form = MyModelForm(preset_attrs={'account': request.account})
insin
@insin +1 Thanks! I previously thought you could only access the instance after you called `instance = save(commit=False)`. I have **one more question for you though**: If I'm adding attributes manually, it means that I'm likely not including them in the form (even as hidden because of security). In this case, Django doesn't validate those fields with `is_valid()` because they're "excluded". How can I include them in the validation processes even if they're "excluded" so that I don't have to manually catch errors and use `form._update_errors()`?
orokusaki
@insin What do you think?
orokusaki