| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657 | from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
from django.core.urlresolvers import resolve
from django.db import models
from django.http import Http404
class ExtendedURLField(models.CharField):
    u"""
    Custom field similar to URLField type field, however also accepting 
    and validating local relative URLs, ie. '/product/'
    """
    description = "Extended URL"
    def __init__(self, verbose_name=None, name=None, verify_exists=True, **kwargs):
        kwargs['max_length'] = kwargs.get('max_length', 200)
        models.CharField.__init__(self, verbose_name, name, **kwargs)
        self.is_local_url = False
        self.verify_exists = verify_exists
        
    def get_prep_value(self, value):
        u"""
        Make sure local URLs have preceding and trailing slashes 
        """
        if self.is_local_url == True:
            value = self.fix_local_url(value)
        return value
    def validate(self, value, model_instance):
        u"""
        Overrides global vaidate method to check whether URL is valid
        """
        v = URLValidator(verify_exists=self.verify_exists)
        try:
            v(value)
        except ValidationError, e:
            if (e.code == 'invalid_link'):
                raise ValidationError('This link appears to be broken')
            self.validate_local_url(value)
    def validate_local_url(self, value):
        u"""
        Validate local URL name
        """
        try:
            value = self.fix_local_url(value)
            if self.verify_exists:
                resolve(value)
            self.is_local_url = True
        except Http404:
            raise ValidationError('Specified page does not exist')
    def fix_local_url(self, value):
        u"""
        Puts preceding and trailing slashes to local URL name 
        """
        return '/' + value.strip('/') + '/'
    
 |