2

Using this example. Pretend there are date fields in both forms. How would you write a custom clean for validation to compare both dates? I have added an example clean at the bottom which returns a key error on poll.

models and forms

from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField()
    target_date= models.DataTimeField()

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    target_date= models.DataTimeField()
    votes = models.IntegerField(default=0)
To start, we’ll need forms for each model.

from django import forms
from mysite.polls.models import Poll, Choice

class PollForm(forms.ModelForm):
    class Meta:
        model = Poll

class ChoiceForm(forms.ModelForm):
    class Meta:
        model = Choice
        exclude = ('poll',)

Views

from mysite.polls.models import Poll, Choice
from mysite.polls.forms import PollForm, ChoiceForm
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response

def add_poll(request):
    if request.method == "POST":
        pform = PollForm(request.POST, instance=Poll())
        cforms = [ChoiceForm(request.POST, prefix=str(x), instance=Choice()) for x in range(0,3)]
        if pform.is_valid() and all([cf.is_valid() for cf in cforms]):
            new_poll = pform.save()
            for cf in cforms:
                new_choice = cf.save(commit=False)
                new_choice.poll = new_poll
                new_choice.save()
            return HttpResponseRedirect('/polls/add/')
    else:
        pform = PollForm(instance=Poll())
        cforms = [ChoiceForm(prefix=str(x), instance=Choice()) for x in range(0,3)]
    return render_to_response('add_poll.html', {'poll_form': pform, 'choice_forms': cforms})

Example clean being ran on the form which returns the key error for poll.

def clean(self):
        if any(self.errors):
            raise forms.ValidationError("")
        data = self.cleaned_data
        choiceDate = data["target_date"]
        pollDate = data["poll"]    ##--- The key error happens here
        if choiceDate > pollDate.target_date:
            raise forms.ValidationError("Your dates do not match")
        return data

1 Answer 1

1

pollDate = data["poll"] ##--- The key error happens here

That's because the form has no field called poll because your're explicitly excluding it in the form definition. I can't tell the clean you give is on the PollForm or the ChoiceForm, but neither has a poll field.

Sign up to request clarification or add additional context in comments.

5 Comments

Correct, but I am setting the value with the following code. Is this the wrong way to do it? - for cf in cforms: new_choice = cf.save(commit=False) new_choice.poll = new_poll new_choice.save()
Yeah, but you're setting that value AFTER clean() has been called by is_valid() and clean() is still trying to access a field that just is not present in the form instance...
True, what would be the right way to accomplish this? I see what's wrong but haven't figured out a way to rewrite it to work correctly.
You can't cross validate between forms. Validation happens within their cleaning methods. What you could do is, in the view, test what you get back out of cleaned_data and then act on it/not act on it accordingly and show an appropriate error message with the messages framework.
Gotcha, I guess it's time to dig into the built in django admin site and see how they handel doing the same thing. Thanks for the help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.