django-shorturls-1.0.1/0000755000076500007650000000000011170506340012744 5ustar jacobdjango-shorturls-1.0.1/PKG-INFO0000644000076500007650000000675611170506340014057 0ustar jacobMetadata-Version: 1.0 Name: django-shorturls Version: 1.0.1 Summary: A short URL (rev=cannonical) handler for Django apps. Home-page: http://github.com/jacobian/django-shorturls Author: Simon Willison, Jacob Kaplan-Moss Author-email: jacob@jacobian.org License: BSD Description: django-shorturls ================ A custom URL shortening app for Django, including easy ``rev=cannonical`` support. Most code was originally by Simon Willison; see http://simonwillison.net/2009/Apr/11/revcanonical/ for details. Improved slightly and packaged by Jacob Kaplan-Moss. Patches welcome: http://github.com/jacobian/django-shorturls Usage ===== So, you want to host your own short URLs on your Django site: 1. In your settings, define a set of prefixes for short URLs:: SHORTEN_MODELS = { 'A': 'myapp.animal', 'V': 'myapp.vegetable', 'M': 'myapp.mineral' } The keys are string prefixes; they can be any string, actually, but since we're going for short a single character is probably good. Values are the (hopefully-familiar) ``"."`` used by Django to identify a model. Remember: ``app-name`` is the (case-sensitive) last bit of your app's name in ``INSTALLED_APPS``, and ```` is your model class's name, lowercased. Make sure your models have a ``get_absolute_url()`` method defined. 2. Wire up the redirect view by adding to your URLconf:: ('^short/', include('shorturls.urls')) 3. If you'd like to quickly link to shortened URLs in your templates, stick ``"shorturls"`` in ``INSTALLED_APPS``, and then in your templates do:: {% load shorturls %} ... (where ``object`` is a model instance). Alternatively:: {% load shorturls %} {% recanonical object %} This generates the whole ```` tag for you. That's it. If you'd like more control, keep reading. Settings ======== Available settings are: ``SHORTEN_MODELS`` You've seen this one. ``SHORT_BASE_URL`` If defined, the ``shorturl`` and ``revcanonical`` template tags will prefix generated URLs with this value. Use this if you've got a shorter domain name you'd like to use for small URLs. For example, given ``SHORT_BASE_URL = 'http://exm.pl/'``, ``{% shorturl obj %}`` would return something like ``http://exm.pl/AbCd``. ``SHORTEN_FULL_BASE_URL`` The domain to redirect to when redirecting away from the small URL. Again, you'll use this if your short URL base and your "real" site differ. If not defined, the redirect view will try to guess the proper domain by consulting the ``django.contrib.sites`` framework, if installed, or the requested domain, if not. Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet django-shorturls-1.0.1/._README0000644000076500000000000000027311170503271015046 0ustar jacobwheelMac OS X  2‰»ATTRˆ »˜#˜#com.macromates.caret{ column = 60; line = 10; }django-shorturls-1.0.1/README0000644000076500007650000000541411170503271013630 0ustar jacobdjango-shorturls ================ A custom URL shortening app for Django, including easy ``rev=cannonical`` support. Most code was originally by Simon Willison; see http://simonwillison.net/2009/Apr/11/revcanonical/ for details. Improved slightly and packaged by Jacob Kaplan-Moss. Patches welcome: http://github.com/jacobian/django-shorturls Usage ===== So, you want to host your own short URLs on your Django site: 1. In your settings, define a set of prefixes for short URLs:: SHORTEN_MODELS = { 'A': 'myapp.animal', 'V': 'myapp.vegetable', 'M': 'myapp.mineral' } The keys are string prefixes; they can be any string, actually, but since we're going for short a single character is probably good. Values are the (hopefully-familiar) ``"."`` used by Django to identify a model. Remember: ``app-name`` is the (case-sensitive) last bit of your app's name in ``INSTALLED_APPS``, and ```` is your model class's name, lowercased. Make sure your models have a ``get_absolute_url()`` method defined. 2. Wire up the redirect view by adding to your URLconf:: ('^short/', include('shorturls.urls')) 3. If you'd like to quickly link to shortened URLs in your templates, stick ``"shorturls"`` in ``INSTALLED_APPS``, and then in your templates do:: {% load shorturls %} ... (where ``object`` is a model instance). Alternatively:: {% load shorturls %} {% recanonical object %} This generates the whole ```` tag for you. That's it. If you'd like more control, keep reading. Settings ======== Available settings are: ``SHORTEN_MODELS`` You've seen this one. ``SHORT_BASE_URL`` If defined, the ``shorturl`` and ``revcanonical`` template tags will prefix generated URLs with this value. Use this if you've got a shorter domain name you'd like to use for small URLs. For example, given ``SHORT_BASE_URL = 'http://exm.pl/'``, ``{% shorturl obj %}`` would return something like ``http://exm.pl/AbCd``. ``SHORTEN_FULL_BASE_URL`` The domain to redirect to when redirecting away from the small URL. Again, you'll use this if your short URL base and your "real" site differ. If not defined, the redirect view will try to guess the proper domain by consulting the ``django.contrib.sites`` framework, if installed, or the requested domain, if not.django-shorturls-1.0.1/setup.cfg0000644000076500007650000000007311170506340014565 0ustar jacob[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 django-shorturls-1.0.1/._setup.py0000644000076500000000000000027211170506316015702 0ustar jacobwheelMac OS X  2ˆºATTRˆ º˜"˜"com.macromates.caret{ column = 20; line = 8; }django-shorturls-1.0.1/setup.py0000644000076500007650000000156211170506316014465 0ustar jacobimport os from setuptools import setup, find_packages def read(fname): return open(os.path.join(os.path.dirname(__file__), fname)).read() setup( name = "django-shorturls", version = "1.0.1", url = 'http://github.com/jacobian/django-shorturls', license = 'BSD', description = "A short URL (rev=cannonical) handler for Django apps.", long_description = read('README'), author = 'Simon Willison, Jacob Kaplan-Moss', author_email = 'jacob@jacobian.org', packages = find_packages('src'), package_dir = {'': 'src'}, install_requires = ['setuptools'], classifiers = [ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Internet', ] )django-shorturls-1.0.1/src/0000755000076500007650000000000011170506340013533 5ustar jacobdjango-shorturls-1.0.1/src/django_shorturls.egg-info/0000755000076500007650000000000011170506340020614 5ustar jacobdjango-shorturls-1.0.1/src/django_shorturls.egg-info/._PKG-INFO0000644000076500000000000000027011170506337023136 0ustar jacobwheelMac OS X  2†žATTR5œž˜ ˜ com.macromates.caretxœ«æR‚äüœÒÜ<[k0?'3/«‹™django-shorturls-1.0.1/src/django_shorturls.egg-info/PKG-INFO0000644000076500007650000000675611170506337021735 0ustar jacobMetadata-Version: 1.0 Name: django-shorturls Version: 1.0.1 Summary: A short URL (rev=cannonical) handler for Django apps. Home-page: http://github.com/jacobian/django-shorturls Author: Simon Willison, Jacob Kaplan-Moss Author-email: jacob@jacobian.org License: BSD Description: django-shorturls ================ A custom URL shortening app for Django, including easy ``rev=cannonical`` support. Most code was originally by Simon Willison; see http://simonwillison.net/2009/Apr/11/revcanonical/ for details. Improved slightly and packaged by Jacob Kaplan-Moss. Patches welcome: http://github.com/jacobian/django-shorturls Usage ===== So, you want to host your own short URLs on your Django site: 1. In your settings, define a set of prefixes for short URLs:: SHORTEN_MODELS = { 'A': 'myapp.animal', 'V': 'myapp.vegetable', 'M': 'myapp.mineral' } The keys are string prefixes; they can be any string, actually, but since we're going for short a single character is probably good. Values are the (hopefully-familiar) ``"."`` used by Django to identify a model. Remember: ``app-name`` is the (case-sensitive) last bit of your app's name in ``INSTALLED_APPS``, and ```` is your model class's name, lowercased. Make sure your models have a ``get_absolute_url()`` method defined. 2. Wire up the redirect view by adding to your URLconf:: ('^short/', include('shorturls.urls')) 3. If you'd like to quickly link to shortened URLs in your templates, stick ``"shorturls"`` in ``INSTALLED_APPS``, and then in your templates do:: {% load shorturls %} ... (where ``object`` is a model instance). Alternatively:: {% load shorturls %} {% recanonical object %} This generates the whole ```` tag for you. That's it. If you'd like more control, keep reading. Settings ======== Available settings are: ``SHORTEN_MODELS`` You've seen this one. ``SHORT_BASE_URL`` If defined, the ``shorturl`` and ``revcanonical`` template tags will prefix generated URLs with this value. Use this if you've got a shorter domain name you'd like to use for small URLs. For example, given ``SHORT_BASE_URL = 'http://exm.pl/'``, ``{% shorturl obj %}`` would return something like ``http://exm.pl/AbCd``. ``SHORTEN_FULL_BASE_URL`` The domain to redirect to when redirecting away from the small URL. Again, you'll use this if your short URL base and your "real" site differ. If not defined, the redirect view will try to guess the proper domain by consulting the ``django.contrib.sites`` framework, if installed, or the requested domain, if not. Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Topic :: Internet django-shorturls-1.0.1/src/django_shorturls.egg-info/._SOURCES.txt0000644000076500000000000000027011170506340023717 0ustar jacobwheelMac OS X  2†žATTR5©ž˜ ˜ com.macromates.caretxœ«æR‚äüœÒÜ<[k0?'3/«‹™django-shorturls-1.0.1/src/django_shorturls.egg-info/SOURCES.txt0000644000076500007650000000112711170506340022501 0ustar jacobREADME setup.py src/django_shorturls.egg-info/PKG-INFO src/django_shorturls.egg-info/SOURCES.txt src/django_shorturls.egg-info/dependency_links.txt src/django_shorturls.egg-info/requires.txt src/django_shorturls.egg-info/top_level.txt src/shorturls/__init__.py src/shorturls/baseconv.py src/shorturls/models.py src/shorturls/testsettings.py src/shorturls/urls.py src/shorturls/views.py src/shorturls/templatetags/__init__.py src/shorturls/templatetags/shorturl.py src/shorturls/tests/__init__.py src/shorturls/tests/models.py src/shorturls/tests/test_templatetag.py src/shorturls/tests/test_views.pydjango-shorturls-1.0.1/src/django_shorturls.egg-info/._dependency_links.txt0000644000076500000000000000027011170506337026120 0ustar jacobwheelMac OS X  2†žATTR5šž˜ ˜ com.macromates.caretxœ«æR‚äüœÒÜ<[k0?'3/«‹™django-shorturls-1.0.1/src/django_shorturls.egg-info/dependency_links.txt0000644000076500007650000000000111170506337024670 0ustar jacob django-shorturls-1.0.1/src/django_shorturls.egg-info/._requires.txt0000644000076500000000000000027011170506337024441 0ustar jacobwheelMac OS X  2†žATTR5›ž˜ ˜ com.macromates.caretxœ«æR‚äüœÒÜ<[k0?'3/«‹™django-shorturls-1.0.1/src/django_shorturls.egg-info/requires.txt0000644000076500007650000000001211170506337023213 0ustar jacobsetuptoolsdjango-shorturls-1.0.1/src/django_shorturls.egg-info/._top_level.txt0000644000076500000000000000027011170506337024573 0ustar jacobwheelMac OS X  2†žATTR5§ž˜ ˜ com.macromates.caretxœ«æR‚äüœÒÜ<[k0?'3/«‹™django-shorturls-1.0.1/src/django_shorturls.egg-info/top_level.txt0000644000076500007650000000001211170506337023345 0ustar jacobshorturls django-shorturls-1.0.1/src/shorturls/0000755000076500007650000000000011170506340015600 5ustar jacobdjango-shorturls-1.0.1/src/shorturls/.___init__.py0000644000076500000000000000027211170467240021137 0ustar jacobwheelMac OS X  2ˆºATTRˆ º˜"˜"com.macromates.caret{ column = 32; line = 5; }django-shorturls-1.0.1/src/shorturls/__init__.py0000644000076500007650000000000011170467240017704 0ustar jacobdjango-shorturls-1.0.1/src/shorturls/._baseconv.py0000644000076500000000000000027111170446237021202 0ustar jacobwheelMac OS X  2‡¹ATTRrd¹˜!˜!com.macromates.caret{ column = 0; line = 7; }django-shorturls-1.0.1/src/shorturls/baseconv.py0000644000076500007650000000340211170446237017761 0ustar jacob""" Convert numbers from base 10 integers to base X strings and back again. Original: http://www.djangosnippets.org/snippets/1431/ Sample usage: >>> base20 = BaseConverter('0123456789abcdefghij') >>> base20.from_decimal(1234) '31e' >>> base20.from_decimal('31e') 1234 """ class BaseConverter(object): decimal_digits = "0123456789" def __init__(self, digits): self.digits = digits def from_decimal(self, i): return self.convert(i, self.decimal_digits, self.digits) def to_decimal(self, s): return int(self.convert(s, self.digits, self.decimal_digits)) def convert(number, fromdigits, todigits): # Based on http://code.activestate.com/recipes/111286/ if str(number)[0] == '-': number = str(number)[1:] neg = 1 else: neg = 0 # make an integer out of the number x = 0 for digit in str(number): x = x * len(fromdigits) + fromdigits.index(digit) # create the result in base 'len(todigits)' if x == 0: res = todigits[0] else: res = "" while x > 0: digit = x % len(todigits) res = todigits[digit] + res x = int(x / len(todigits)) if neg: res = '-' + res return res convert = staticmethod(convert) bin = BaseConverter('01') hexconv = BaseConverter('0123456789ABCDEF') base62 = BaseConverter( 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz' ) if __name__ == '__main__': nums = [-10 ** 10, 10 ** 10] + range(-100, 100) for convertor in [bin, hex, base62]: for i in nums: assert i == bin.to_decimal(bin.from_decimal(i)), '%s failed' % i django-shorturls-1.0.1/src/shorturls/._models.py0000644000076500000000000000027211170443640020661 0ustar jacobwheelMac OS X  2ˆºATTRphº˜"˜"com.macromates.caret{ column = 13; line = 0; }django-shorturls-1.0.1/src/shorturls/models.py0000644000076500007650000000004511170443640017437 0ustar jacob# This file intentionally left blank.django-shorturls-1.0.1/src/shorturls/templatetags/0000755000076500007650000000000011170506340020272 5ustar jacobdjango-shorturls-1.0.1/src/shorturls/templatetags/.___init__.py0000644000076500000000000000027011170470132023621 0ustar jacobwheelMac OS X  2†žATTR@ž˜ ˜ com.macromates.caretxœ«æR‚äüœÒÜ<[k0?'3/«‹™django-shorturls-1.0.1/src/shorturls/templatetags/__init__.py0000644000076500007650000000000011170470132022370 0ustar jacobdjango-shorturls-1.0.1/src/shorturls/templatetags/._shorturl.py0000644000076500000000000000027311170476472023764 0ustar jacobwheelMac OS X  2‰»ATTRY»˜#˜#com.macromates.caret{ column = 74; line = 32; }django-shorturls-1.0.1/src/shorturls/templatetags/shorturl.py0000644000076500007650000000373111170476472022546 0ustar jacobimport urlparse from django import template from django.conf import settings from django.core import urlresolvers from django.utils.safestring import mark_safe from shorturls.baseconv import base62 class ShortURL(template.Node): @classmethod def parse(cls, parser, token): parts = token.split_contents() if len(parts) != 2: raise template.TemplateSyntaxError("%s takes exactly one argument" % parts[0]) return cls(template.Variable(parts[1])) def __init__(self, obj): self.obj = obj def render(self, context): try: obj = self.obj.resolve(context) except template.VariableDoesNotExist: return '' try: prefix = self.get_prefix(obj) except (AttributeError, KeyError): return '' tinyid = base62.from_decimal(obj.pk) if hasattr(settings, 'SHORT_BASE_URL') and settings.SHORT_BASE_URL: return urlparse.urljoin(settings.SHORT_BASE_URL, prefix+tinyid) try: return urlresolvers.reverse('shorturls.views.redirect', kwargs = { 'prefix': prefix, 'tiny': tinyid }) except urlresolvers.NoReverseMatch: return '' def get_prefix(self, model): if not hasattr(self.__class__, '_prefixmap'): self.__class__._prefixmap = dict((m,p) for p,m in settings.SHORTEN_MODELS.items()) key = '%s.%s' % (model._meta.app_label, model.__class__.__name__.lower()) return self.__class__._prefixmap[key] class RevCanonical(ShortURL): def render(self, context): url = super(RevCanonical, self).render(context) if url: return mark_safe('' % url) else: return '' register = template.Library() register.tag('shorturl', ShortURL.parse) register.tag('revcanonical', RevCanonical.parse)django-shorturls-1.0.1/src/shorturls/tests/0000755000076500007650000000000011170506340016742 5ustar jacobdjango-shorturls-1.0.1/src/shorturls/tests/.___init__.py0000644000076500000000000000027211170471773022307 0ustar jacobwheelMac OS X  2ˆºATTRQLº˜"˜"com.macromates.caret{ column = 46; line = 2; }django-shorturls-1.0.1/src/shorturls/tests/__init__.py0000644000076500007650000000017411170471773021070 0ustar jacobfrom shorturls.tests.models import * from shorturls.tests.test_views import * from shorturls.tests.test_templatetag import *django-shorturls-1.0.1/src/shorturls/tests/._models.py0000644000076500000000000000027311170453546022032 0ustar jacobwheelMac OS X  2‰»ATTRQP»˜#˜#com.macromates.caret{ column = 15; line = 18; }django-shorturls-1.0.1/src/shorturls/tests/models.py0000644000076500007650000000145711170453546020617 0ustar jacob""" A handful of test modules to test out resolving redirects. """ from django.db import models class Animal(models.Model): name = models.CharField(max_length=100) class Meta: app_label = 'shorturls' def __unicode__(self): return self.name def get_absolute_url(self): return '/animal/%s/' % self.id class Vegetable(models.Model): name = models.CharField(max_length=100) class Meta: app_label = 'shorturls' def __unicode__(self): return self.name def get_absolute_url(self): return 'http://example.net/veggies/%s' % self.id class Mineral(models.Model): name = models.CharField(max_length=100) class Meta: app_label = 'shorturls' def __unicode__(self): return self.namedjango-shorturls-1.0.1/src/shorturls/tests/._test_templatetag.py0000644000076500000000000000027311170474051024107 0ustar jacobwheelMac OS X  2‰»ATTR‘Ê»˜#˜#com.macromates.caret{ column = 64; line = 46; }django-shorturls-1.0.1/src/shorturls/tests/test_templatetag.py0000644000076500007650000000330711170474051022670 0ustar jacobfrom django import template from django.conf import settings from django.test import TestCase from shorturls.tests.models import Animal, Vegetable, Mineral class RedirectViewTestCase(TestCase): urls = 'shorturls.urls' fixtures = ['shorturls-test-data.json'] def setUp(self): self.old_shorten = getattr(settings, 'SHORTEN_MODELS', None) self.old_base = getattr(settings, 'SHORT_BASE_URL', None) settings.SHORT_BASE_URL = None settings.SHORTEN_MODELS = { 'A': 'shorturls.animal', 'V': 'shorturls.vegetable', } def tearDown(self): if self.old_shorten is not None: settings.SHORTEN_MODELS = self.old_shorten if self.old_base is not None: settings.SHORT_BASE_URL = self.old_base def render(self, t, **c): return template.Template('{% load shorturl %}'+t).render(c) def test_shorturl(self): r = self.render('{% shorturl a %}', a=Animal.objects.get(id=12345)) self.assertEqual(r, '/ADNH') def test_bad_context(self): r = self.render('{% shorturl a %}') self.assertEqual(r, '') def test_no_prefix(self): r = self.render('{% shorturl m %}', m=Mineral.objects.all()[0]) self.assertEqual(r, '') def test_short_base_url(self): settings.SHORT_BASE_URL = 'http://example.com/' r = self.render('{% shorturl a %}', a=Animal.objects.get(id=12345)) self.assertEqual(r, 'http://example.com/ADNH') def test_revcanonical(self): r = self.render('{% revcanonical a %}', a=Animal.objects.get(id=12345)) self.assertEqual(r, '') django-shorturls-1.0.1/src/shorturls/tests/._test_views.py0000644000076500000000000000027311170472401022732 0ustar jacobwheelMac OS X  2‰»ATTRˆ »˜#˜#com.macromates.caret{ column = 49; line = 11; }django-shorturls-1.0.1/src/shorturls/tests/test_views.py0000644000076500007650000000456311170472401021520 0ustar jacobfrom django.conf import settings from django.http import Http404 from django.test import TestCase from shorturls.baseconv import base62 class RedirectViewTestCase(TestCase): urls = 'shorturls.urls' fixtures = ['shorturls-test-data.json'] def setUp(self): self.old_shorten = getattr(settings, 'SHORTEN_MODELS', None) self.old_base = getattr(settings, 'SHORTEN_FULL_BASE_URL', None) settings.SHORTEN_MODELS = { 'A': 'shorturls.animal', 'V': 'shorturls.vegetable', 'M': 'shorturls.mineral', 'bad': 'not.amodel', 'bad2': 'not.even.valid', } settings.SHORTEN_FULL_BASE_URL = 'http://example.com' def tearDown(self): if self.old_shorten is not None: settings.SHORTEN_MODELS = self.old_shorten if self.old_base is not None: settings.SHORTEN_FULL_BASE_URL = self.old_base def test_redirect(self): """ Test the basic operation of a working redirect. """ response = self.client.get('/A%s' % enc(12345)) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'http://example.com/animal/12345/') def test_redirect_from_request(self): """ Test a relative redirect when the Sites app isn't installed. """ settings.SHORTEN_FULL_BASE_URL = None response = self.client.get('/A%s' % enc(54321), HTTP_HOST='example.org') self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'http://example.org/animal/54321/') def test_redirect_complete_url(self): """ Test a redirect when the object returns a complete URL. """ response = self.client.get('/V%s' % enc(785)) self.assertEqual(response.status_code, 301) self.assertEqual(response['Location'], 'http://example.net/veggies/785') def test_bad_short_urls(self): self.assertEqual(404, self.client.get('/badabcd').status_code) self.assertEqual(404, self.client.get('/bad2abcd').status_code) self.assertEqual(404, self.client.get('/Vssssss').status_code) def test_model_without_get_absolute_url(self): self.assertEqual(404, self.client.get('/M%s' % enc(10101)).status_code) def enc(id): return base62.from_decimal(id) django-shorturls-1.0.1/src/shorturls/testsettings.py0000644000076500007650000000036711170467240020725 0ustar jacobimport os DEBUG = TEMPLATE_DEBUG = True DATABASE_ENGINE = 'sqlite3' DATABASE_NAME = '/tmp/shorturls.db' INSTALLED_APPS = ['shorturls'] ROOT_URLCONF = ['shorturls.urls'] TEMPLATE_DIRS = os.path.join(os.path.dirname(__file__), 'tests', 'templates')django-shorturls-1.0.1/src/shorturls/urls.py0000644000076500007650000000037711170467240017153 0ustar jacobfrom django.conf import settings from django.conf.urls.defaults import * urlpatterns = patterns('', url( regex = '^(?P%s)(?P\w+)$' % '|'.join(settings.SHORTEN_MODELS.keys()), view = 'shorturls.views.redirect', ), )django-shorturls-1.0.1/src/shorturls/._views.py0000644000076500000000000000027311170506232020531 0ustar jacobwheelMac OS X  2‰»ATTRˆ»˜#˜#com.macromates.caret{ column = 54; line = 32; }django-shorturls-1.0.1/src/shorturls/views.py0000644000076500007650000000427711170506232017321 0ustar jacobimport urlparse from django.conf import settings from django.contrib.sites.models import Site, RequestSite from django.db import models from django.http import HttpResponsePermanentRedirect, Http404 from django.shortcuts import get_object_or_404 from shorturls.baseconv import base62 def redirect(request, prefix, tiny): """ Redirect to a given object from a short URL. """ # Resolve the prefix and encoded ID into a model object and decoded ID. # Many things here could go wrong -- bad prefix, bad value in # SHORTEN_MODELS, no such model, bad encoding -- so just return a 404 if # any of that stuff goes wrong. try: app_label, model_name = settings.SHORTEN_MODELS[prefix].split('.') model = models.get_model(app_label, model_name) if not model: raise ValueError id = base62.to_decimal(tiny) except (AttributeError, ValueError, KeyError): raise Http404('Bad prefix, model, SHORTEN_MODELS, or encoded ID.') # Try to look up the object. If it's not a valid object, or if it doesn't # have an absolute url, bail again. obj = get_object_or_404(model, pk=id) try: url = obj.get_absolute_url() except AttributeError: raise Http404("'%s' models don't have a get_absolute_url() method." % model.__name__) # We might have to translate the URL -- the badly-named get_absolute_url # actually returns a domain-relative URL -- into a fully qualified one. # If we got a fully-qualified URL, sweet. if urlparse.urlsplit(url)[0]: return HttpResponsePermanentRedirect(url) # Otherwise, we need to make a full URL by prepending a base URL. # First, look for an explicit setting. if hasattr(settings, 'SHORTEN_FULL_BASE_URL') and settings.SHORTEN_FULL_BASE_URL: base = settings.SHORTEN_FULL_BASE_URL # Next, if the sites app is enabled, redirect to the current site. elif Site._meta.installed: base = 'http://%s/' % Site.objects.get_current().domain # Finally, fall back on the current request. else: base = 'http://%s/' % RequestSite(request).domain return HttpResponsePermanentRedirect(urlparse.urljoin(base, url))