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:

  1. django-admin startproject a51
  2. cd a51
  3. ./manage.py startapp shrink
  4. cd shrink

18:08 edito settings.py:

  1. DATABASE_ENGINE = 'sqlite3'
  2. DATABASE_NAME = 'sqlite.db'
  3. ...
  4. MEDIA_ROOT = os.path.join(os.path.dirname(__file__), "media")
  5. MEDIA_URL = '/media/'
  6. ADMIN_MEDIA_PREFIX = '/media/admin/'
  7. ...
  8. TEMPLATE_DIRS = (
  9.     os.path.join(os.path.dirname(__file__), "templates"),
  10. )
  11. INSTALLED_APPS = (
  12. ...
  13.     'django.contrib.admin',
  14.     'a51.shrink',
  15. )

Escribiendo el programa

18:10 Edito models.py:

  1. class Link(models.Model):
  2.     url = models.CharField(max_length = 511) #random number, 111111111
  3.     short = models.CharField(max_length = 32) #random number, again
  4.    
  5.     def __unicode__(self):
  6.         return "%s -> %s"%(self.short, self.url)

18:14 edito views.py:

  1. def make_random_code(size):
  2.     def random_alphanum():
  3.         rand = randint(0,61)
  4.         if 0 < rand < 10: return chr(ord('0')+rand)
  5.         if 10 < rand < 35: return chr(ord('a')+rand-10)
  6.         if 35 < rand < 61: return chr(ord('A')+rand-35)
  7.     res = ''.join([random_alphanum() for i in range(size)])
  8.     if (res[:6] in ['shrink', 'author'] or
  9.         res[:5] in ['admin'] or # ... add here future stuff (?)
  10.         Link.objects.filter(short=res)):
  11.         return make_random_code(size+1)
  12.     return res
  13. def main(request):
  14.     try:
  15.         errorno = request.GET['errorno']
  16.     except:
  17.         errorno = 0
  18.     return render_to_response('main.html', {'errorno': errorno } )
  19.  
  20. def look(request, short):
  21.     try:
  22.         link = Link.objects.get(short=short)
  23.     except:
  24.         return HttpResponseRedirect('/?errorno=1') # errorno 1 == not found
  25.     return HttpResponseRedirect(link.url) # Everything went smooth
  26.  
  27. def shrink(request):
  28.     url = request.GET['url']
  29.     try:
  30.         link = Link.objects.get(url=url)
  31.     except:
  32.         short = make_random_code(1)
  33.         link = Link(url=url, short=short)
  34.         link.save()
  35.     return render_to_response('short.html', {'link': link } )

18:29 edito urls.py:

  1. urlpatterns = patterns('',
  2.     (r'^$', 'a51.shrink.views.main'),
  3.     (r'^shrink$', 'a51.shrink.views.shrink'),
  4.     (r'^admin/', include(admin.site.urls)),
  5.     (r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
  6.     (r'^(?P<short>.+)', 'a51.shrink.views.look'),
  7. )

18:34 edito admin.py para que tome el modelo Link

18:35 actualizo la db desde la consola:

  1. ./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

  1. def shrink(request):
  2.     try: url = request.GET['url']
  3.     except:
  4.         try: url = request.POST['url']
  5.         except: return Http404
  6.     try: how = request.GET['how']
  7.     except:
  8.         try: how = request.POST['how']
  9.         except: return Http404
  10.     try:
  11.         link = Link.objects.get(url=url)
  12.     except:
  13.         short = make_random_code(1)
  14.         link = Link(url=url, short=short)
  15.         link.save()
  16.     if how == "": return render_to_response('short.html', {'link': link } )
  17.     if how == "plaintext": return HttpResponse("http://a51.com.ar/"+link.short)
  18.     if how == "json": return HttpResponse(simplejson.dumps({'url': url, 'short': "http://a51.com.ar/"+link.short }))
  19.     if how == "xml":
  20.         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)
  21.         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.


  • http://topsy.com/trackback?utm_source=pingback&utm_campaign=L1&url=http://estebanordano.com.ar/una-webapp-en-django-en-2-horas/ Tweets that mention Una Webapp en Django en 2 horas | estebanordano.com.ar — Topsy.com

    [...] This post was mentioned on Twitter by Esteban Ordano. Esteban Ordano said: Nuevo post en mi blog: "Una Webapp en Django en 2 horas" http://bit.ly/aDhYTE [...]

  • http://lateral.netmanagers.com.ar Roberto Alsina

    Acorté http://www.kde.org me dió http://a51.com.ar/4p pero el link no me funciona (dice "Ha habido un error:
    No existe ese shrink")

    Saludos,

  • http://Website Dario

    Puse "www.clarin.com" y me devolvio http://a51.com.ar/pj pero no anda.

    Saludos.

  • http://estebanordano.com.ar/ eordano

    @Dario, @Roberto:

    Bugaso!! Gracias por el feedback.

    estaban redirigiendo a http://a51.com.ar/www.clarin.com y esas a la vez daban error de que no exiten.

    Debería estar solucionado ahora.

    Nuevamente, muchas gracias!

  • http://lateral.netmanagers.com.ar Roberto Alsina

    Si "." no es un caracter valido en el shortcut entonces lo podés sacar de la regex de short y por lo menos va a dar un error razonable (con la URL correcta)

  • http://estebanordano.com.ar/ eordano

    Lo solucioné con esto:

    if not re.match("http://", url):
    url = "http://"+url

  • http://Website Stefano

    Hola, que tal, me parece grande su colaboración, me podría explicar, como se añade la clase modelo Link, estoy tratando de enlazar este modelo, pero el sistema no reconoce la clase, he de usar un comando para hacerlo??. Me podría ayudar con este caso.