rrb_bbr
rrb_bbr

Reputation: 3056

Problem with Django's URL Field Test

Could someone please clarify me why this url http://www.nacolmeia.com.br/do/Home/oferta/EnER is not being accepted in a form generated from URLField's Django?

:)

Thanks

Upvotes: 7

Views: 11909

Answers (2)

Dave
Dave

Reputation: 12638

I think I found the issue. When you open this URL:

http://www.nacolmeia.com.br/do/Home/oferta/EnER

...it re-directs to this URL:

http://www.nacolmeia.com.br/do/Home/oferta/EnER/piracicaba/a-pascoa-chegou-na-planet-chokolate!-50-off-para-1-caixa-com-16-bombons-recheados--1-pao-de-mel-recheado-ou-1-caixa-com-16-trufas-recheadas--1-pao-de-mel-recheado-de-rs-47.10-por-rs-23.55.

The first URL is fine, but the re-directed one is 247 characters long. This "shouldn't" be a problem, except that models.fields.URLField has max_length which defaults to 200 characters. So it fails validation because it's too long.

Instead, increase the max_length and it should work: models.URLField(max_length=255) For info on the longest URL possible, see this SO question. It's definitely longer than 200 characters though.

EDIT: It only re-directs to the second URL when setting a cookie! If you re-visit the same page again with an existing cookie, it just displays the shorter URL.


But what about the lowercase URL? It appears your web-server is case-sensitive regarding URLs, and the lowercase version:

http://www.nacolmeia.com.br/do/home/oferta/ener

...displays a generic error page. It doesn't re-direct to the 247 character URL. So that passes validation since the only thing models.URLField cares about is; does it load a webpage or not?

Upvotes: 0

dting
dting

Reputation: 39297

Are you hosting the site from the same server you are trying to validate it on? docs

Note that when you're using the single-threaded development server, validating a URL being served by the same server will hang. This should not be a problem for multithreaded servers.

It doesn't look like its failing validation at the form level

>>> from django import forms
>>> f = forms.URLField()
>>> f.clean('http://www.nacolmeia.com.br/do/Home/oferta/EnER')
u'http://www.nacolmeia.com.br/do/Home/oferta/EnER'
>>> f.clean('sadfas')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/dev/.virtualenvs/thepidb/lib/python2.7/site-packages/django/forms/fields.py", line 171, in clean
    self.run_validators(value)
  File "/home/dev/.virtualenvs/thepidb/lib/python2.7/site-packages/django/forms/fields.py", line 160, in run_validators
    raise ValidationError(errors)
ValidationError: [u'Enter a valid URL.']
>>> 

If you don't need to validate that the website doesn't return a 404, in your models.py

url = models.URLField(verify_exists=False)

edit:

after some digging around in the django source code here and some messing around with the shell, I'm still not sure why the URL with caps is causing a redirect loop.

>>> from django.core.validators import URLValidator
>>> u = URLValidator(verify_exists=True)
>>> u.__call__('http://www.nacolmeia.com.br/do/Home/oferta/EnER')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/dev/.virtualenvs/thepidb/lib/python2.7/site-packages/django/core/validators.py", line 105, in __call__
    raise broken_error
ValidationError: [u'This URL appears to be a broken link.']
>>> u.__call__('http://www.nacolmeia.com.br/do/home/oferta/ener')
>>> 

The actual exception being raised is an HTTPError:

  File "/usr/lib/python2.7/urllib2.py", line 606, in http_error_302
    return self.parent.open(new, timeout=req.timeout)
  File "/usr/lib/python2.7/urllib2.py", line 398, in open
    response = meth(req, response)
  File "/usr/lib/python2.7/urllib2.py", line 511, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.7/urllib2.py", line 430, in error
    result = self._call_chain(*args)
  File "/usr/lib/python2.7/urllib2.py", line 370, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 606, in http_error_302
    return self.parent.open(new, timeout=req.timeout)
  File "/usr/lib/python2.7/urllib2.py", line 398, in open
    response = meth(req, response)
  File "/usr/lib/python2.7/urllib2.py", line 511, in http_response
    'http', request, response, code, msg, hdrs)
  File "/usr/lib/python2.7/urllib2.py", line 430, in error
    result = self._call_chain(*args)
  File "/usr/lib/python2.7/urllib2.py", line 370, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 596, in http_error_302
    self.inf_msg + msg, headers, fp)
HTTPError: HTTP Error 302: The HTTP server returned a redirect error that would lead to an infinite loop.
The last 30x error message was:
Found
>>> 

here are some posts talking about the HTTPError: here and here

seems like it has something to do with cookies, but I'm not able to offer a good explanation, I'll leave that to some one else.

A workaround that might work if you don't want to turn off validation but don't care about the capitalization of your urls is to override the clean_field method of your forms.

def clean_your_url_field(self):
    return self.cleaned_data['your_url_field'].lower()

Upvotes: 8

Related Questions