Una Webapp en Django en 2 horas
Fecha: April 14th, 2010 | Categoría: Python | 7 Comments »Bueno, como experimento quería saber qué tan rápido (aunque quedó la mayor parte de las cosas hackeadas para que simplemente anden) podía hacer un URL shrinker en Django, en el menor tiempo que pude. Un URL shrinker es lo que se usa cuando una dirección web es muy larga (por ejemplo, alguna nota en un diario) y se quiere mandar un por twitter u otros medios (donde cada caracter cuenta). El más famoso que yo conozco es http://bit.ly.
Así es como quedó:
http://a51.com.ar/
Seteando el enviroment
18:06 ejecuto en línea de comandos:
-
django-admin startproject a51
-
cd a51
-
./manage.py startapp shrink
-
cd shrink
18:08 edito settings.py:
-
DATABASE_ENGINE = 'sqlite3'
-
DATABASE_NAME = 'sqlite.db'
-
...
-
MEDIA_ROOT = os.path.join(os.path.dirname(__file__), "media")
-
MEDIA_URL = '/media/'
-
ADMIN_MEDIA_PREFIX = '/media/admin/'
-
...
-
TEMPLATE_DIRS = (
-
os.path.join(os.path.dirname(__file__), "templates"),
-
)
-
INSTALLED_APPS = (
-
...
-
'django.contrib.admin',
-
'a51.shrink',
-
)
Escribiendo el programa
18:10 Edito models.py:
-
class Link(models.Model):
-
url = models.CharField(max_length = 511) #random number, 111111111
-
short = models.CharField(max_length = 32) #random number, again
-
-
def __unicode__(self):
-
return "%s -> %s"%(self.short, self.url)
18:14 edito views.py:
-
def make_random_code(size):
-
def random_alphanum():
-
rand = randint(0,61)
-
if 0 < rand < 10: return chr(ord('0')+rand)
-
if 10 < rand < 35: return chr(ord('a')+rand-10)
-
if 35 < rand < 61: return chr(ord('A')+rand-35)
-
res = ''.join([random_alphanum() for i in range(size)])
-
if (res[:6] in ['shrink', 'author'] or
-
res[:5] in ['admin'] or # ... add here future stuff (?)
-
Link.objects.filter(short=res)):
-
return make_random_code(size+1)
-
return res
-
def main(request):
-
try:
-
errorno = request.GET['errorno']
-
except:
-
errorno = 0
-
return render_to_response('main.html', {'errorno': errorno } )
-
-
def look(request, short):
-
try:
-
link = Link.objects.get(short=short)
-
except:
-
return HttpResponseRedirect('/?errorno=1') # errorno 1 == not found
-
return HttpResponseRedirect(link.url) # Everything went smooth
-
-
def shrink(request):
-
url = request.GET['url']
-
try:
-
link = Link.objects.get(url=url)
-
except:
-
short = make_random_code(1)
-
link = Link(url=url, short=short)
-
link.save()
-
return render_to_response('short.html', {'link': link } )
18:29 edito urls.py:
-
urlpatterns = patterns('',
-
(r'^$', 'a51.shrink.views.main'),
-
(r'^shrink$', 'a51.shrink.views.shrink'),
-
(r'^admin/', include(admin.site.urls)),
-
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
-
(r'^(?P<short>.+)', 'a51.shrink.views.look'),
-
)
18:34 edito admin.py para que tome el modelo Link
18:35 actualizo la db desde la consola:
-
./manage.py syncdb
18:35 Hago los .html básicos
3) Debuggeando
18:42 intento levantar el server
- views.py linea 11 tenía dos veces return
- faltaba hacer que main() tenga un parametro opcional
- ifequals no existe, no me acordaba la documentacion era ifequal
- get() del model de django raisea una exception
- HTTP en mayúsculas
18:51 no anda nada! no sé por qué me tira errorno=1 siempre
18:58 no entra nunca en la función 'shrink'
19:03 Interrupción del workflow: me fuí a bañar
19:40 Vuelvo y me pongo a debugear
19:43 nunca entraba en shrink, es porque las urls que tenía configuradas cortan en el ? para el GET (estaba intentando poner en las regex de url, el símbolo ? para hacer los GET a mano)
20:00 tengo el sitio andando!!! me fuí al cumpleaños de @maraoz
Haciendo un diseño lindo
11:32 Centrado el wrapper del medio
11:50 terminé un logo horrendo, arreglando el CSS
12:13 fin del CSS
Agregando chiches: multiples maneras de obtener el shrink
12:22 terminé de agregarle opciones para bajar los datos como plaintext xml, y json
-
def shrink(request):
-
try: url = request.GET['url']
-
except:
-
try: url = request.POST['url']
-
except: return Http404
-
try: how = request.GET['how']
-
except:
-
try: how = request.POST['how']
-
except: return Http404
-
try:
-
link = Link.objects.get(url=url)
-
except:
-
short = make_random_code(1)
-
link = Link(url=url, short=short)
-
link.save()
-
if how == "": return render_to_response('short.html', {'link': link } )
-
if how == "plaintext": return HttpResponse("http://a51.com.ar/"+link.short)
-
if how == "json": return HttpResponse(simplejson.dumps({'url': url, 'short': "http://a51.com.ar/"+link.short }))
-
if how == "xml":
-
s = "<?xml version='1.0'?>\n<link>\n\t<url>%s</url>\n\t<short>http://a51.com.ar/%s</short>\n</link>"%(url, link.short)
-
return HttpResponse(s)
Conclusión
Según los números estos, fueron 127 minutos de desarrollo para una web que no quedó tan mal (el logo es horrible), tiene funcionalidad bastante básica, pero estuvo buena la experiencia.
