Ruth Young
Ruth Young

Reputation: 888

Custom clean() method not validating when setting username

I have a Django ModelForm where I want to set a ForeignKey with a user instance when validating, it's hidden on the template so the user can't set this.

The view:

def view1(request):
    if request.method == "POST":
        model1form = Model1Form(request.POST, request.FILES, user=request.user)
        if model1form.is_valid(): # fails here
            print "is valid"

Form:

class Model1Form(forms.ModelForm):

    class Meta:
        model = Model1
        fields = ['person_id', 'start_date', 'end_date']

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(Model1Form, self).__init__(*args, **kwargs)

    def clean(self):
        cleaned_data = super(Model1Form, self).clean()

        start_date = cleaned_data.get("start_date")
        end_date = cleaned_data.get("end_date")

        username = self.user
        person = Person.objects.get(username_field=username)
        person_id = person.id
        print person_id # this prints fine

        # custom validation

        return cleaned_data

This clean method fails when I run is_valid(). But runs fine without the person_id stuff. What am I doing wrong?

Models:

class Model1(models.Model):

    person_id = models.ForeignKey(Person, null=True)
    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

class Person(models.Model):

    first_name = models.CharField(max_length=15, default='')
    surname = models.CharField(max_length=30, default='')

    def __unicode__ (self):
        return self.first_name + ' ' + self.surname

Is this the wrong approach to this?

Upvotes: 0

Views: 151

Answers (2)

Resley Rodrigues
Resley Rodrigues

Reputation: 2288

First let's change your model a bit

class Model1(models.Model):    
    person = models.ForeignKey(Person, null=True)
    start_date = models.DateField(null=True, blank=True)
    end_date = models.DateField(null=True, blank=True)

Previously you had person_id as the foreign key which meant you would have a field person_id_id which is just weird to read.

Now for the form. You need to make sure your fk is part of the cleaned data.

class Model1Form(forms.ModelForm): 
    class Meta:
        model = Model1
        fields = ['start_date', 'end_date']  
    ...    
    def clean(self):
        cleaned_data = super(Model1Form, self).clean()
        ...
        username = self.user
        person = Person.objects.get(username_field=username)
        cleaned_data["person_id"] = person.id
        # if that doesn't work try cleaned_data["person"] = person
        ...
        return cleaned_data

Upvotes: 0

Alasdair
Alasdair

Reputation: 309049

There's no need for a hidden field here. Leave the field out of the model form:

class Model1Form(forms.ModelForm):

    class Meta:
        model = Model1
        fields = ['start_date', 'end_date']

Then in your view, save with commit=False, then set the person on the instance.

if request.method == "POST":
    model1form = Model1Form(request.POST, request.FILES, user=request.user)
    if model1form.is_valid(): # fails here
        instance = model1form.save(commit=False)
        instance.person = Person.objects.get(username_field=request.user)
        instance.save()

See the docs on the model form's save() method for more info.

Once you have made this change, you may find that you can remove user from the form's __init__ method.

Upvotes: 2

Related Questions