5

I'm trying to validate that a submitted URL doesn't already exist in the database.

The relevant parts of the Form class look like this:

from django.contrib.sites.models import Site
class SignUpForm(forms.Form):
    # ... Other fields ...
    url = forms.URLField(label='URL for new site, eg: example.com')

    def clean_url(self):
        url = self.cleaned_data['url']
        try:
            a = Site.objects.get(domain=url)

        except Site.DoesNotExist:
            return url

        else:
            raise forms.ValidationError("That URL is already in the database.  Please submit a unique URL.")

    def clean(self):
        # Other form cleaning stuff.  I don't *think* this is causing the grief

The problem is, regardless of what value I submit, I can't raise the ValidationError. And if I do something like this in the clean_url() method:

if Site.objects.get(domain=url):
    raise forms.ValidationError("That URL is already in the database.  Please submit a unique URL.")

then I get a DoesNotExist error, even for URLs that already exist in the Database. Any ideas?

saturdayplace
  • 8,370
  • 8
  • 35
  • 39

4 Answers4

4

django channel in IRC saved me here. The problem was that the URLField.clean() does two things I wasn't expecting:

  1. If no URL scheme is present (eg, http://) the method prepends 'http://' to the url
  2. the method also appends a trailing slash.

The results are returned and stored in the form's cleaned_data. So I was checking cleaned_data['url'] expecting something like example.com and actually getting http://example.com/. Suffice to say, changing my clean_url() method to the following works:

def clean_url(self):
        url = self.cleaned_data['url']        
        bits = urlparse(url)
        dom = bits[1]
        try:
            site=Site.objects.get(domain__iexact=dom)
        except Site.DoesNotExist:
            return dom
        raise forms.ValidationError(u'That domain is already taken.  Please choose another')
saturdayplace
  • 8,370
  • 8
  • 35
  • 39
1

I do it this way. It's slightly simpler.

try:
    a = Site.objects.get(domain=url)
    raise forms.ValidationError("That URL is already in the database.  Please submit a unique URL.")
except Site.DoesNotExist:
    pass
return url
S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • You've got other problems, then. This has to work. Are you running "manage.py testserver" and getting a new, empty database each time you run? Are you running "manage.py runserver"? – S.Lott Dec 04 '08 at 11:11
  • Agreed. There's a good chance your other validation methods _are_ "causing the grief". – Carl Meyer Dec 04 '08 at 15:30
  • Figured out the problem - URLField.clean() was putting a different value in cleaned_data than I was expecting. The answer is below. – saturdayplace Dec 04 '08 at 18:33
0

I think, you can return '' and fill _errors.

msg = u"That URL is already in the database.  Please submit a unique URL."
self._errors["url"]=ErrorList([msg])
return ''

or

from django.contrib.sites.models import Site
class SignUpForm(forms.Form):
    # ... Other fields ...

url = forms.URLField(label='URL for new site, eg: example.com')

def clean_url(self):
    url = self.cleaned_data['url']
    try:
        a = Site.objects.get(domain=url)
        raise forms.ValidationError("That URL is already in the database.  Please submit a unique URL.")
    except Site.DoesNotExist:
        return url
    return ''

def clean(self):
    # Other form cleaning stuff.  I don't *think* this is causing the grief
Igorekk
  • 256
  • 1
  • 8
  • -1: raising ValidationError is the correct way. Filling self._errors manually is a hack for no good reason. – Carl Meyer Dec 04 '08 at 15:31
0

Well I logged in cause I found this via Google with a similar issue and wanted to add a comment to Carl Meyers post noting that using self._errors is totally valid as per the Django docs:

http://docs.djangoproject.com/en/1.2/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other