from django.core import validators from django.core.exceptions import ValidationError from django.core.urlresolvers import resolve from django.db.models import get_model from django.http import Http404 from django.utils.translation import ugettext_lazy as _ class ExtendedURLValidator(validators.URLValidator): def __call__(self, value): try: super(ExtendedURLValidator, self).__call__(value) except ValidationError: if value: self.validate_local_url(value) else: raise def validate_local_url(self, value): """ Validate local URL name """ try: value = self.fix_local_url(value) if self.verify_exists: resolve(value) self.is_local_url = True except Http404: # We load flatpages here as it causes a circular reference problem # sometimes. FlatPages is None if not installed FlatPage = get_model('flatpages', 'FlatPage') if FlatPage is not None: for page in FlatPage.objects.all().only(('url')): if value == page.url: return raise ValidationError(_('Specified page does not exist')) def fix_local_url(self, value): """ Puts preceding and trailing slashes to local URL name """ if value != '/': value = '/' + value.lstrip('/') q_index = value.find('?') if q_index > 0: value = value[:q_index] return value class URLDoesNotExistValidator(ExtendedURLValidator): def __call__(self, value): """ Validate that the URL in *value* does not already exist. The URL will be verified first and raises ``ValidationError`` when it is invalid. A valid URL is checked for existance and raises ``ValidationError`` if the URL already exists. Setting attribute ``verify_exists`` has no impact on validation. This validation uses two calls to ExtendedURLValidator which can be slow. Be aware of this, when you use it. Returns ``None`` if URL is valid and does not exist. """ self.verify_exists = False # calling ExtendedURLValidator twice instead of replicating its code # and invert the cases when a ValidationError is returned seemes to # be a much cleaner solution. Although this might not be the most # efficient way of handling this, it should have not much of an impact # due to its current application in flatpage creation. try: super(URLDoesNotExistValidator, self).__call__(value) except ValidationError: raise ValidationError(_('Specified page does already exist'), code='invalid') # check if URL exists since it seems to be valid try: self.verify_exists = True super(URLDoesNotExistValidator, self).__call__(value) except ValidationError: return raise ValidationError(_('Specified page does already exist'), code='invalid')