Статья описывает создание простейшей сокращалки ссылок, вроде bit.ly или goo.gl.
Итак, заходим в директорию с вашим проектом и создаём приложение. Пусть оно носит имя 'shortener'.
$ django-project startapp shortener
Для начала опишем несложную конфигурацию URL, которая будет определять, что нужно пользователю в соответствии с его запросом.
<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/>
Мы будем рассматривать случай, когда для сокращения используется адрес example.com, то есть представленная выше конфигурация является единственной (не забудьте указать ROOT_URLCONF в settings.py). Если же вы используете адрес вроде example.com/shortener/, не забудьте подключить свою конфигурацию в основной с помощью механизма include.
Теперь при обращении к example.com будет вызывать функция представления index из файла views.py, остальные же адреса, длина которых 3 три знака (без домена), мы будем пытаться «развернуть» помощью функции redirect из того же файла. Для сокращения ссылок мы будем использовать латинские буквы в различном регистре и цифры. Длина «ключа» будет три символа, этого вполне достаточно для не очень массовых сервисов (62^3 варианта).
Следующим нашим шагом будет определение модели, то есть описание данных на уровне БД.
# 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/>
После импорта нужных функций и моделей мы реализуем функцию, которая будет генерировать случайный ключ из заданных символов. Далее описывается класс ShortUrl, который отвечает за представление нашей сокращённой ссылки в базе данных. Каждый объект этого класса имеет уникальный атрибут key, поле, в котором хранится «длинная» ссылка, а также дату создания ссылки. Затем идет класс Hit. С помощью него мы будет хранить информацию о клике по укороченной ссылке, а именно время клика, IP кликнувшего, его User Agent и Referer, ну и «длинную» ссылку.
Обратите внимание на аргументы полей, впоследствии они будут очень важны.
Наша страница, на которой пользователь сможет укоротить свою ссылку, будет очень минималистичной — одна форма и одна кнопка (она показаны на первой картинке). Давайте опишем эту небольшую форму, её код будет содержаться в 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/>
Здесь всё очень просто — одно поле, с помощью которого мы будем обрабатывать отправленную пользователем «длинную» ссылку.
Пришло время написать представление, которое будет обрабатывать данные, переданные нашей конфигурацией URL. Первой опишем функцию make_short_url и импортируем нужные модули и функции.
#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/>
После импортов реализуется функция, которая принимает некую ссылку, создаёт соответствующий ей объект класса ShortUrl и возвращает уже укороченную ссылку (она была сгенерирована во время создания объекта). Возможно также использование Site.objects.get_current().domain из django.contrib.sites.models.
Теперь нам нужно написать функции, которые обрабатывают форму и реализуют разворачивание «короткой» ссылки, то есть редирект.
#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/>
Функция index отображает пустую форму, если пользователь ещё не обращался к ней, и обрабадывает её в случае POST запроса. В первом случае шаблону shortener.html, который отвечает за интерфейс передаётся сама форма и пустая ссылка, во втором — только укороченная ссылка. Далее следует функция redirect, к которой обращается конфигурация URL, если она сочла обращение пользователя за просьбу развернуть «короткую» ссылку. Перед простым редиректом мы создаём объект класса Hit, описанного в models.py, с соответствующими атрибутами, полученными из объекта request. Ещё советую почитать комментарии, в них много интересного про конструкцию «except: pass».
Осталось совсем чуть-чуть, еще немного и у нас будет своя сокращалка ссылок!
Настало время описать наш шаблон shortener.html, отвечающий за HTML представление формы и укороченной ссылки. Вспомните, какие параметры он принимает.
<!--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/>
В принципе, вы уже можете использовать этот код — сам URL Shortener уже создан. Осталось описать представление наших данных в интерфейсе администратора (не забудьте подключить соответствующую конфигурацию в файле urls.py).
#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/>
Вот и всё. Осталось выполнить
$ python manage.py syncdb
И наслаждаться результатом :)
Интерфейс администратора:
Результат работы нашего URL Shortener'a:
Попробовать его вы можете здесь.