# in util/models.py or wherever
import fields
from django.contrib.admin import options, widgets
from django.db.models.fields import CharField
class RedirectedURLField(CharField):
def __init__(self, verbose_name=None, name=None, **kwargs):
kwargs['max_length'] = kwargs.get('max_length', 200)
CharField.__init__(self, verbose_name, name, **kwargs)
def formfield(self, **kwargs):
defaults = {'form_class': fields.RedirectedURLField}
defaults.update(kwargs)
return super(RedirectedURLField, self).formfield(**defaults)
options.FORMFIELD_FOR_DBFIELD_DEFAULTS[RedirectedURLField] = {'widget': widgets.AdminURLFieldWidget}
# in util/fields.py or wherever
import urllib2
import urlparse
from django.forms.fields import url_re, RegexField, URL_VALIDATOR_USER_AGENT
from django.utils.translation import ugettext_lazy as _
class RedirectedURLField(RegexField):
default_error_messages = {
'invalid': _(u'Enter a valid URL.'),
'invalid_link': _(u'This URL appears to be a broken link.'),
}
# http://www.diveintopython.org/http_web_services/redirects.html
class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_301(self, req, fp, code, msg, headers):
result = urllib2.HTTPRedirectHandler.http_error_301(self, req,
fp, code, msg, headers)
result.status = code
return result
def __init__(self, max_length=None, min_length=None,
validator_user_agent=URL_VALIDATOR_USER_AGENT, *args, **kwargs):
super(RedirectedURLField, self).__init__(url_re, max_length, min_length,
*args, **kwargs)
self.user_agent = validator_user_agent
def clean(self, value):
# If no URL scheme given, assume http://
if value and '://' not in value:
value = u'http://%s' % value
# If no URL path given, assume /
if value and not urlparse.urlsplit(value)[2]:
value += '/'
value = super(RedirectedURLField, self).clean(value)
if value == u'':
return value
headers = {
"Accept": "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5",
"Accept-Language": "en-us,en;q=0.5",
"Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
"Connection": "close",
"User-Agent": self.user_agent,
}
opener = urllib2.build_opener(self.RedirectHandler())
try:
request = urllib2.Request(value, None, headers)
response = opener.open(request)
if 301 == getattr(response, 'status', None):
value = response.geturl()
except ValueError:
raise ValidationError(self.error_messages['invalid'])
except: # urllib2.URLError, httplib.InvalidURL, etc.
raise ValidationError(self.error_messages['invalid_link'])
return value
Comments