
This article describes how to create a simple link
shortening , such as
bit.ly or
goo.gl.')
So, go to the directory with your project and create the application. Let it be named
'shortener' .
$ django-project startapp shortener
To begin, let us describe a simple
URL configuration that will determine what the user needs according to his request.
<br/> # urls.py <br/> from
django.conf.urls.defaults import * <br/> <br/> urlpatterns = patterns ( '' , <br/> (r '^ $' , 'views .index ' ), <br/> (r ' ^ (? P <key>. {3}) $ ' , ' views.redirect ' ), <br/>) <br/>
We will consider the case when using the address example.com to shorten it, that is, the configuration presented above is the only one (do not forget to specify ROOT_URLCONF in settings.py). If you use an address like example.com/shortener/, do not forget to connect your configuration to the main one using the include mechanism .
Now, when accessing
example.com , the view function will call the
index from the
views.py file, the rest of the addresses, the length of which is 3 three characters (no domain), we will try to “expand” using the
redirect function from the same file. To shorten the links, we will use Latin letters in different case and numbers. The length of the "key" will be three characters, this is quite enough for not very mass services (62 ^ 3 options).
Our next step is to define the model, that is, the description of the data at the database level.
# models.py <br/> from django.db import models<br/> <br/> from datetime import datetime<br/> from random import choice<br/> import string<br/> <br/> <br/> def generate_key ():<br/> chars = string .digits + string .letters<br/> return '' .join(choice(chars) for _ in range ( 3 ))<br/> <br/> class ShortUrl (models.Model):<br/> <br/> key = models.CharField(max_length= 3 , primary_key=True, default= generate_key )<br/> target = models.URLField(verify_exists=False, unique=True)<br/> added = models.DateTimeField(auto_now_add=True, editable=False)<br/> <br/> def __unicode__ (self):<br/> return '%s %s' % ( self .target, self .key)<br/> <br/> <br/> class Hit (models.Model):<br/> <br/> target = models.ForeignKey( ShortUrl )<br/> time = models.DateTimeField(auto_now_add=True, editable=False)<br/> referer = models.URLField(blank=True, verify_exists=False)<br/> ip = models.IPAddressField(blank=True)<br/> user_agent = models.CharField(blank=True, max_length= 100 ) <br/>
After importing the necessary functions and models, we will implement a function that will generate a random key from the specified characters. The following describes the
ShortUrl class, which is responsible for presenting our short link in the database. Each object of this class has a unique
key attribute, a field in which the “long” link is stored, as well as the date the link was created. Then comes the
Hit class. With it, we will store information about a click on a shortened link, namely, the time of the click, the
IP clicked, its
User Agent and
Referer , and the “long” link.
Pay attention to the arguments of the fields, later they will be very important.
Our page on which the user can shorten his link will be very minimalistic - one form and one button (it is shown in the first picture). Let's describe this small form, its code will be contained in
forms.py .
#forms.py <br/> from django import forms<br/> <br/> class UrlForm (forms.Form): <br/> url = forms.URLField(label= 'url' , verify_exists=False) <br/>
Everything is very simple here - one field with which we will process the long link sent by the user.
It's time to write a view that will process the data passed by our
URL configuration. First we describe the function
make_short_url and import the necessary modules and functions.
#views.py <br/> from django.http import HttpResponseRedirect<br/> from django.shortcuts import render_to_response, get_object_or_404<br/> from django.template import RequestContext<br/> <br/> from forms import UrlForm<br/> from models import ShortUrl, Hit<br/> <br/> <br/> def make_short_url (url):<br/> short_url = ShortUrl.objects.get_or_create(target=url)[ 0 ]<br/> short_url.save()<br/> return 'http://example.com/%s' % (short_url.key)<br/>
After importing, a function is implemented that takes a certain reference, creates a corresponding object of class
ShortUrl and returns an already shortened reference (it was generated during the creation of the object). It is also possible to use
Site.objects.get_current (). Domain from
django.contrib.sites.models .
Now we need to write functions that process the form and implement the unfolding of the “short” link, that is, the redirect.
#views.py (continuation) <br/> def index (request):<br/> if request.method == 'POST' :<br/> form = UrlForm(request.POST)<br/> if form.is_valid():<br/> url = form.cleaned_data.get( 'url' )<br/> url = make_short_url(url)<br/> return render_to_response( 'shortener.html' , { 'url' :url})<br/> else :<br/> form = UrlForm(label_suffix= '' )<br/> return render_to_response( 'shortener.html' , { 'form' : form, 'url' : '' })<br/> <br/> <br/> def redirect (request, key):<br/> target = get_object_or_404(ShortUrl, key=key)<br/> <br/> try :<br/> hit = Hit()<br/> hit.target = target<br/> hit.referer = request.META.get( "HTTP_REFERER" , "" )<br/> hit.ip = request.META.get( "REMOTE_ADDR" , "" )<br/> hit.user_agent = request.META.get( "HTTP_USER_AGENT" , "" )<br/> hit.save()<br/> except IntegrityError:<br/> pass <br/> <br/> return HttpResponseRedirect(target.target) <br/>
The
index function displays an empty form if the user has not yet accessed it, and processes it in the case of a
POST request. In the first case, the template
shortener.html , which is responsible for the interface, is passed the form itself and a blank link, in the second - only a shortened link. This is followed by the
redirect function, which is referenced by the
URL configuration, if it found the user's request for a request to deploy a “short” link. Before a simple redirect, we create an object of the
Hit class, described in
models.py , with the corresponding attributes obtained from the
request object. I also advise you to read the comments, there are a lot of interesting things about the “except: pass” construction.
Just a little bit left, a little more and we will have our own link shortening!
It is time to describe our template
shortener.html , responsible for the
HTML presentation of the form and a shortened link. Remember what parameters it takes.
<!--shortener.html--> <br/>{% if not url %}<br/> < form action ="." method ="post" > <br/> {{ form.as_p }}<br/> < input type ="submit" name ="submit" value ="submit"/> <br/> </ form > <br/>{% else %}<br/> < a href ="{{url}}"></ a > {{ url }} </ a > <br/>{% endif %} <br/>
Basically, you can already use this code - the URL Shortener itself has already been created. It remains to describe the presentation of our data in the administrator interface (do not forget to include the appropriate configuration in the
urls.py file).
#admin.py <br/> from django.contrib import admin<br/> <br/> from models import ShortUrl, Hit<br/> <br/> <br/> class ShortUrlAdmin (admin.ModelAdmin):<br/> fields = ( 'target' , 'key' )<br/> list_display = ( 'key' , 'target' , 'added' )<br/> ordering = ( '-added' ,)<br/> list_filter = ( 'added' ,)<br/> date_hierarchy = 'added' <br/> <br/>admin. site .register(ShortUrl, ShortUrlAdmin )<br/> <br/> <br/> class HitAdmin (admin.ModelAdmin):<br/> list_display = ( 'target' , 'ip' , 'user_agent' , 'referer' , 'time' )<br/> ordering = ( '-time' ,)<br/> list_filter = ( 'target' , 'referer' , 'time' )<br/> date_hierarchy = 'time' <br/> <br/>admin. site .register(Hit, HitAdmin ) <br/>
That's all. It remains to perform
$ python manage.py syncdb
And enjoy the result :)
Admin Interface:


The result of our URL Shortener is:

You can try it
here .