Login

RedirectedURLField

Author:
stringify
Posted:
February 14, 2010
Language:
Python
Version:
1.1
Score:
0 (after 0 ratings)

This field is similar to the standard URLField, except it checks the given URL for a HTTP 301 response (permanent redirect) and updates its value accordingly.

For example:

>>> url = RedirectedURLField()
>>> url.clean('http://www.twitter.com/')
>>> 'http://twitter.com/'

In models:

class TestModel(models.Model):
    url1 = RedirectedURLField('Redirected URL')
    url2 = models.URLField('Standard URL')
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# 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

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 11 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 6 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 7 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

Please login first before commenting.