<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Fitoria.net</title><link>http://fitoria.net/</link><description></description><atom:link href="http://fitoria.net/category/django.rss.xml" rel="self"></atom:link><lastBuildDate>Wed, 16 Jan 2013 21:40:00 -0600</lastBuildDate><item><title>Django Suite IV: Hablemos un poco de caché.</title><link>http://fitoria.net/2013/01/django-suite-iv-cache/</link><description>&lt;p&gt;Decía &lt;strong&gt;Phil Karlton&lt;/strong&gt; &lt;em&gt;"Solo hay dos cosas dificiles en las ciencias de la computación: invalidación de caché y nombrar cosas."&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;En esta entrega de la serie &lt;strong&gt;Django Suite&lt;/strong&gt; - después de mas de un año de ausencia - hablaré sobre el &lt;a href="https://docs.djangoproject.com/en/dev/topics/cache/"&gt;framework 
de caché&lt;/a&gt; de Django.&lt;/p&gt;
&lt;h2&gt;Principios de caché&lt;/h2&gt;
&lt;p&gt;Cuando hacemos un sitio, especialmente si estamos comenzando no tomamos en cuenta el desempeño del sitio y la 
cantidad de tiempo de procesamiento por cada petición. El tiempo de procesamiento de un sitio está afectado por
varios factores el mas importante la cantidad de consultas que realizamos a la base de dato por cada request, 
generalmente estas varían según la complejidad de nuestras vistas y el tipo de usuario (anónimo o autenticado) 
que tengamos en el sitio.&lt;/p&gt;
&lt;p&gt;Para mejorar el desempeño del sitio se usa el caché que no es mas que un almacenamiento rápido, generalmente en 
RAM,  que nos evita recaer en &lt;em&gt;operaciones de cálculo pesadas&lt;/em&gt; como lo son hacer muchas consultas de base de datos 
la lógica de las vistas y el renderizado de las mismas en la plantilla que normalmente son realizadas haciendo 
lectura/escritura de disco duro que agrega mas tiempo a la receta.&lt;/p&gt;
&lt;p&gt;Hacer caché de datos no es tan dificil, lo dificil es saber cuando los datos cacheados ya no son válidos 
y debemos de recalcular de nuevo para construir un nuevo caché, de ahí la frase del inicio del post.&lt;/p&gt;
&lt;h2&gt;Caché framework&lt;/h2&gt;
&lt;p&gt;Django contiene un framework de caché que abstrae las operaciones básicas, sin que nosotros tengamos que 
preocuparnos por el motor de caché que usemos, por defecto Django soporta &lt;a href="http://memcached.org/"&gt;Memcached&lt;/a&gt;, caché en base de datos,
 caché en el sistema de archivos y memoria local, siendo no muy recomendados estos últimos tres.&lt;/p&gt;
&lt;p&gt;Pero como todo en Django la comunidad da soporte para otros motores de caché opensource muy buenos ademas de 
memcached, como por ejemplo:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Varnish con &lt;a href="https://github.com/justquick/django-varnish"&gt;django-varnish&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Redis con &lt;a href="https://github.com/sebleier/django-redis-cache"&gt;django-redis-cache&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Caché de vistas&lt;/h2&gt;
&lt;p&gt;Django nos provee con el decorador &lt;strong&gt;cache_page&lt;/strong&gt; para hacer caché a una vista, el decorador lo que hace es lo 
siguiente.&lt;/p&gt;
&lt;p&gt;Si la vista ha sido cargada por primera vez, hace todas las operaciones y la guarda en caché con tiempo 
de vencimiento designado en la llamada del decorador, caso contrario carga el resultado de la vista desde 
caché.&lt;/p&gt;
&lt;p&gt;Ejemplo:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decorators&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cache_page&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="n"&gt;cache_page&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;60 &lt;span class="o"&gt;*&lt;/span&gt; 15&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;my_view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="p"&gt;....&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;El valor de 60 * 15 representa la duración de la validez del caché &lt;em&gt;en segundos&lt;/em&gt;, en este caso 15 minutos, se acostumbra mucho para 
asignar valores de vencimiento poner multiplicaciones de la cantidad de segundos en un minuto (60) por el número de minutos deseado.&lt;/p&gt;
&lt;p&gt;En el caso que la vista tuviera parámetros como un &lt;strong&gt;mi_vista(request, post_id)&lt;/strong&gt; el caché ser haría de manera individual 
por cada valor de &lt;code&gt;post_id&lt;/code&gt; que tengamos presente. Mas detalles de esto en la documentación oficial.&lt;/p&gt;
&lt;h2&gt;Caché de fragmentos de plantillas&lt;/h2&gt;
&lt;p&gt;Fragmentos plantillas también pueden ser cacheadas, esto es especialmente útil para fragmentos que repetimos en casi 
todas las páginas, por ejemplo elementos de menú dinámicos, columnas de 'últimas noticias' o 'últimos post' en caso de 
ser un blog.&lt;/p&gt;
&lt;p&gt;Ejemplo:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c"&gt;% load cache %}&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c"&gt;% cache 500 menu %}&lt;/span&gt;
    &lt;span class="p"&gt;..&lt;/span&gt; &lt;span class="n"&gt;mi&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt; &lt;span class="n"&gt;menu&lt;/span&gt; &lt;span class="n"&gt;de&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;á&lt;span class="n"&gt;gina&lt;/span&gt; &lt;span class="p"&gt;..&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="c"&gt;% endcache %}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Igual acá la template tag de &lt;em&gt;cache&lt;/em&gt; acepta como parámetros la duracion en segundos, el nombre del fragmento
 y el conjunto de variables que deseamos establecer en el cache.&lt;/p&gt;
&lt;p&gt;Este conjuto de variables es tremendamente útil para hacer caché en diversas situaciones tales como 
si el usuario está o no autenticado, el lenguaje del navegador del usuario ( en caso que usemos 
la opción de internacionalización y localización del sitio ), valor de alguna varible que usemos que 
puede modificar el resultado de la plantilla entre otros.&lt;/p&gt;
&lt;p&gt;Ejemplo en &lt;a href="https://github.com/fitoria/askbot-devel/blob/master/askbot/templates/widgets/related_tags.html#L1"&gt;código fuente de la vida real acá&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Generalmente la mejor documentación es el código fuente, y para verdaderamente entender y jugar con esta 
template tag recomiendo que vean como está hecha en &lt;a href="https://github.com/django/django/blob/master/django/templatetags/cache.py#L39"&gt;este archivo&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Caché manual&lt;/h2&gt;
&lt;p&gt;Si queremos verdaderamente sacar provecho al framework de caché de django tenemos que tomar ventaja del API 
de caché manual. Los motores de caché se basan en almacenamiento de llave-valor (&lt;a href="http://es.wikipedia.org/wiki/Tabla_hash"&gt;hashmap&lt;/a&gt;) o en lo que python seríá un 
equivalente al tipo &lt;em&gt;diccionario&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;El api de caché es bastante simple, podemos ver su uso en el siguiente código fuente:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="c"&gt;#importamos el objeto caché&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;

&lt;span class="c"&gt;#guardamos algo en el cache con expiración de 60 segundos&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;un valor cacheado&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 60&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;#leemos algo desde cache&lt;/span&gt;
&lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c"&gt;#borramos &amp;#39;a&amp;#39; del cache &lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Básicamente esa es el API de bajo nivel, si nosotros ponemos como valor de tiempo 0 el caché nunca se vencerá y tendremos que eliminarlo manualmente a posteriori.&lt;/p&gt;
&lt;h2&gt;Trucos con el caché manual.&lt;/h2&gt;
&lt;p&gt;El caché manual es tremendamente útil usándolo en conjunto con modelos. Un ejemplo sencillo y fácil de implementar es un menú dinámico, recientemente programé uno que se veía algo así:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="c"&gt;#models.py&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;
&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; 
 
&lt;span class="nb"&gt;class&lt;/span&gt; &lt;span class="n"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;titulo&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;50&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;URLField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;peso&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PositiveIntegerField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;0&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;help_text&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;peso del elemento del menú, entre mayor sea el número mas hacia el fondo estará el elemento&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c"&gt;#primero guardamos&lt;/span&gt;
        &lt;span class="n"&gt;return_value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ElementoNavegacion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;#invalidamos el cache antiguo de menu&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c"&gt;#creamos el nuevo cache refrescado&lt;/span&gt;
        &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; 0&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;return_value&lt;/span&gt;
 
    &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;__unicode__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&amp;quot;%s (%s)&amp;quot;&lt;/span&gt; &lt;span class="c"&gt;% (self.titulo, self.url)&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Se creó un context manager para tener la lista del menú en todas las plantillas.&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;   &lt;span class="c"&gt;#context manager para el menú.&lt;/span&gt;
   &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;django&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;core&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt; 
    
   &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Menu&lt;/span&gt;
    
   &lt;span class="n"&gt;def&lt;/span&gt; &lt;span class="n"&gt;menu_context_manager&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
       &lt;span class="c"&gt;#probamos si esta el elemento en caché&lt;/span&gt;
       &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="c"&gt;#si no está leemos de la base de datos&lt;/span&gt;
       &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;not&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;valor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="c"&gt;#lo cacheamos&lt;/span&gt;
           &lt;span class="n"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 0&lt;span class="p"&gt;)&lt;/span&gt;

       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;menu&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;valor&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Haciendo esto se ahorran un par de consultas a la base de datos y por ende la velocidad de carga del sitio aumenta.&lt;/p&gt;
&lt;h2&gt;Despedida&lt;/h2&gt;
&lt;p&gt;En resumen hemos visto una introducción al cache framework de Django, espero que les haya servido y tendré que hacer un post 
de continuación para exponer otros casos de uso del caché manual y trucos con el API, además del caché al lado del servidor 
de archivos estáticos y del lado del navegador.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Wed, 16 Jan 2013 21:40:00 -0600</pubDate><guid>tag:fitoria.net,2013-01-16:2013/01/django-suite-iv-cache/</guid></item><item><title>Django Suite III: Usando virtualenv y pip.</title><link>http://fitoria.net/2011/11/django-suite-iii-usand-virtualenv-y-pip/</link><description>&lt;p&gt;Tercera entrega de la serie sobre Django, esta vez no hablaré del
framework en si, sino de un par de herramientas básicas del ecosistema
de Python para ayudarnos a ser mas ordenados a la hora de desarrollar
proyectos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://pypi.python.org/pypi/virtualenv"&gt;&lt;strong&gt;Virtualenv&lt;/strong&gt;&lt;/a&gt; es una herramienta que nos ayuda a crear ambientes
aislados para Python en palabras mas simples instala las bibliotecas e
intérprete en una carpeta separada a la de nuestra instalación en el
sistema operativo, la ventajas están en que nos provee una manera fácil,
rápida, segura y reproducible de hacer desarollo y pruebas de diversas
aplicaciones.&lt;/p&gt;
&lt;p&gt;Por otra parte &lt;strong&gt;&lt;a href="http://pypi.python.org/pypi/pip"&gt;pip&lt;/a&gt;&lt;/strong&gt;es una herramienta para instalar paquetes de
Python desde el &lt;strong&gt;&lt;a href="http://pypi.python.org/pypi"&gt;Python Package Index&lt;/a&gt;&lt;/strong&gt; que es el repositorio
comunitario de paquetes. En conjunto con virtualenv, pip nos ayuda a
tener todo organizado y limpio.&lt;/p&gt;
&lt;h2&gt;Usando Virtualenv&lt;/h2&gt;
&lt;p&gt;Primeramente lo instalamos con nuestro manejador de paquetes favorito,
en caso de ubuntu el paquete se llama "python-virtualenv" luego
procedemos a crear nuestro primer ambiente virtual.&lt;/p&gt;
&lt;p&gt;virtualenv primer_ambiente --no-site-packages&lt;/p&gt;
&lt;p&gt;Donde &lt;em&gt;primer_ambiente&lt;/em&gt; es el nombre que deseamos ponerle
y&lt;em&gt;--no-site-packages&lt;/em&gt; es un parámetro para que se cree un ambiente
totalmente limpio tal y como fuera una instalación básica de python sin
ninguna biblioteca extra. La ejecución de este comando creará una
carpeta en el directorio en donde lo ejecutamos, recomiendo crear en su
directorio $HOME una carpeta llamada virtualenvs para guardar todos los
que vayamos creando en un solo lugar. Para activarlo hacemos lo
siguiente:&lt;/p&gt;
&lt;p&gt;source /path/a/primer_ambiente/bin/activate&lt;/p&gt;
&lt;p&gt;Sabremos que está activo por que en nuestra consola aparecerá
(primer_ambiente) en el prompt, ya en nuestro ambiente podremos usar
pip para confirugrarlo a nuestro gusto.&lt;/p&gt;
&lt;p&gt;Para volver a la normalidad usamos el comando:&lt;/p&gt;
&lt;p&gt;deactivate&lt;/p&gt;
&lt;h2&gt;Usando pip&lt;/h2&gt;
&lt;p&gt;La función principal de pip: instalar, actualizar y eliminar paquetes
nos enfocaremos en esas tres funciones.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Instalar:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install django&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;pip install django==1.3.1&lt;/p&gt;
&lt;p&gt;La primera línea instalaría django en la versión mas actual del pypi,
mientras que en la segunda con el operador de igualdad podemos forzar la
instalación de una versión específica de django o cualquier paquete
requerido, esto es muy útil a la hora de tener incompatibilidades o
&lt;a href="http://es.wikipedia.org/wiki/C%C3%B3digo_heredado"&gt;código legacy.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Desinstalar&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip uninstall django&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Simplemente elimina el paquete especificado.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Actualizar&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install django --upgrade&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Instalará la versión mas actual del paquete ya instalado previamente.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Congelar&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip freeze &amp;gt; requirements.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Esto produce un &lt;a href="http://www.pip-installer.org/en/latest/requirement-format.html"&gt;archivo de requemientos en el formato que pip&lt;/a&gt; puede
entender, el archivo de requerimientos detalla las dependencias que
tiene un ambiente, su formato acepta tanto origenes del pypi, paquetes
en formato tar.gz repositorios en git, mercurial y svn. Comúnmente nos
encontraremos de un requirements.txt en muchos proyectos.&lt;/p&gt;
&lt;p&gt;Si ejecutamos este comando en primer_ambiente seguramente tendremos un
par de requerimientos, django que hemos instalado manualmente y
distribute, que viene por defecto.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Instalar desde un archivo de requerimiento.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pip install -r requirements.txt&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Esto leerá el archivo de requerimientos y lo instalará en el ambiente
actual.&lt;/p&gt;
&lt;h2&gt;¿De qué nos sirve todo esto?&lt;/h2&gt;
&lt;p&gt;Simple: &lt;strong&gt;orden, orden, orden!&lt;/strong&gt; Ventajas de usar virtualenv + pip:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;reproducible&lt;/li&gt;
&lt;li&gt;fácil de compartir por medio del archivo de requerimiento&lt;/li&gt;
&lt;li&gt;no afecta los paquetes del sistema&lt;/li&gt;
&lt;li&gt;nos ayuda a la hora de hacer deployments con django.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Ahora repitan conmigo: "todo proyecto de django deberá tener su propio
virtualenv"&lt;/p&gt;
&lt;p&gt;Lectura extra:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.doughellmann.com/projects/virtualenvwrapper"&gt;Virtualenvwrapper&lt;/a&gt;: un interesante proyecto que provee comandos mas
fáciles de recordar para crear, usar y activar virtualenvs.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Mon, 28 Nov 2011 11:30:00 -0600</pubDate><guid>tag:fitoria.net,2011-11-28:2011/11/django-suite-iii-usand-virtualenv-y-pip/</guid></item><item><title>Django Suite II: Configurando nuestro proyecto de manera correcta.</title><link>http://fitoria.net/2011/11/django-suite-ii-configurando-nuestro-proyecto-de-manera-correcta/</link><description>&lt;p&gt;En esta entrada abordaremos un tema importante: la &lt;strong&gt;configuración&lt;/strong&gt;del
proyecto. Como dije en la entrada anterior, en configuraciones tampoco
hay una manera definitiva de hacer las cosas ya que la flexibilidad de
Django nos lo permite.&lt;/p&gt;
&lt;p&gt;Django usa archivos Python para guardar configuraciones, aprovecha la
manera de trabajar del lenguaje para hacer archivos de configuración
fáciles de leer, extender y utilizar dentro de nuestros proyectos.&lt;/p&gt;
&lt;p&gt;Normalmente al iniciar una aplicación creamos un proyecto en blanco con
el &lt;a href="https://docs.djangoproject.com/en/1.3/ref/django-admin/#startproject-projectname"&gt;comando startproject&lt;/a&gt; que nos crea una carpeta con los archivos
necesarios para iniciar.&lt;/p&gt;
&lt;p&gt;Por defecto estas configuraciones&lt;a href="https://docs.djangoproject.com/en/1.3/ref/settings/"&gt;tienen ciertos valores&lt;/a&gt; de los
cuales normalmente nos molestaremos en cambiar sólo algunas, como
configuración de bases de datos, ubicación de archivos estáticos y
servidor de correo.&lt;/p&gt;
&lt;p&gt;Acá algunos trucos para hacer estas configuraciones de manera dinámica y
distribuibles para usarse en sistemas de control de versiones:&lt;/p&gt;
&lt;h2&gt;Separación del archivo settings.py&lt;/h2&gt;
&lt;p&gt;Este archivo contiene muchas veces datos sensibles que no pueden ser
publicados o simplemente varían de una estación de trabajo a otra, por
lo que conviene separarlo con un archivo extra que por convención lo
llamamos&lt;strong&gt;"settings_local.py"&lt;/strong&gt; acá deberán ir estas configuraciones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DATABASES&lt;/li&gt;
&lt;li&gt;ADMINS&lt;/li&gt;
&lt;li&gt;DEBUG&lt;/li&gt;
&lt;li&gt;TEMPLATE_DEBUG&lt;/li&gt;
&lt;li&gt;SECRET_KEY (si lo vas a hacer código libre y público)&lt;/li&gt;
&lt;li&gt;Claves privadas en caso de usarse( ej. alguna clave de API de
    terceros)&lt;/li&gt;
&lt;li&gt;Configuraciones de correo.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/1381110"&gt;Ejemplo:&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Como prodrán ver acá incluyo una configuración extra llamada
&lt;strong&gt;PROJECT_DIR&lt;/strong&gt; que usaremos luego. Para mandar a llamar este nuevo
archivo en el inicio de nuestros settings.py incluimos la siguiente
línea:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;settings_local&lt;/span&gt; &lt;span class="n"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Dinamizando las rutas de archivos estáticos.&lt;/h2&gt;
&lt;p&gt;Django requiere rutas de archivos para cargar archivos estáticos y
definir donde estarán nuestras plantillas, para hacer esto de manera
dinámica y distribuible usamos un poco de Python. En el archivo
settings_local definimos PROJECT_DIR, que no es mas que la ruta del
directorio donde se encuentra dicho archivo, a partir de éste armaremos
MEDIA_ROOT, TEMPLATE_DIRS y STATIC_ROOT&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gist.github.com/1381150"&gt;Ejemplo:&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;gitignore&lt;/h2&gt;
&lt;p&gt;Si vas a usar git u otro sistema de control de versiones recomiendo
agregar ciertos archivos al ignore de tu SCM para git tengo un &lt;a href="https://gist.github.com/1381237"&gt;ejemplo
acá&lt;/a&gt; será similar para otros sistemas.&lt;/p&gt;
&lt;h2&gt;Presentando django-initkit.&lt;/h2&gt;
&lt;p&gt;Para no hacer todo estas configuraciones cada vez que tengamos que
iniciar un proyecto he creado &lt;a href="https://github.com/fitoria/django-initkit"&gt;django-initkit&lt;/a&gt; que es un proyecto
simple que sobrecarga el comando startproject para hacer automáticamente
todo lo que describí en este post. Para instalarlo puedes hacerlo desde
&lt;a href="http://pypi.python.org/pypi/django-initkit/0.0.1"&gt;Pypi&lt;/a&gt; (pip install django-initkit) o haciendo &lt;a href="https://github.com/fitoria/django-initkit"&gt;checkout desde
github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Su uso es igual a django-admin.py, nada más que el nombre del comando es
django_initkit.py&lt;/p&gt;
&lt;p&gt;Ejemplo:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="n"&gt;django_initkit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; &lt;span class="n"&gt;startproject&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Espero que les haya gustado el post de hoy, pueden sugerir mas temas en
los comentarios.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Sun, 20 Nov 2011 23:56:00 -0600</pubDate><guid>tag:fitoria.net,2011-11-20:2011/11/django-suite-ii-configurando-nuestro-proyecto-de-manera-correcta/</guid></item><item><title>Django Suite I: Iniciar con Django.</title><link>http://fitoria.net/2011/11/django-suite-i-iniciar-con-django/</link><description>&lt;p&gt;Esta es una parte de una serie de post semanales que estaré dedicando a
distintos temas de Django. El titulo &lt;strong&gt;Django Suite&lt;/strong&gt;es un pequeño juego
de palabras ya que el nombre del framework fue inspirado por el gran
guitarrista de jazz &lt;a href="http://es.wikipedia.org/wiki/Django_Reinhardt"&gt;Django Reinhardt&lt;/a&gt; y &lt;a href="http://es.wikipedia.org/wiki/Suite"&gt;suite&lt;/a&gt; que se define como
un tipo de pieza musical compuesta por varios movimientos breves.&lt;/p&gt;
&lt;p&gt;Para el primer movimiento empezaré con lo básico el inicio&lt;strong&gt;&lt;em&gt;,no voy a
realizar un tutorial&lt;/em&gt;&lt;/strong&gt; de como iniciar en Django por que hay &lt;strong&gt;&lt;a href="http://lmgtfy.com/?q=tutorial+django"&gt;muchos
ya en internet&lt;/a&gt;&lt;/strong&gt; que son útiles pero debido a que muchas personas me
preguntan cual es la mejor manera de iniciar con Django hago este post
para guiarlos un poco sobre lo que las guías dan por hecho pero que nos
pueden hacer perder algo de tiempo buscando por ahí.&lt;/p&gt;
&lt;p&gt;Sinceramente no hay bala de plata para lograr &lt;a href="http://djangopony.com/"&gt;cabalgar al pony&lt;/a&gt; sino
por que el proceso de aprendizaje varía de quien en quien, lo que si
puedo decir es que Django es uno de los proyectos &lt;em&gt;mejor
documentados&lt;/em&gt;que existen, casi todo el framework menos algunas funciones
internas muy poco usadas están descritas en
&lt;a href="https://docs.djangoproject.com/en/1.3/"&gt;https://docs.djangoproject.com/&lt;/a&gt; en la dirección anterior puedes
navegar fácilmente todos los temas.&lt;/p&gt;
&lt;p&gt;La documentación es muy buena pero no te servirá de nada si no tienes un
conocimiento básico de Python lo bueno es que existen libros como
&lt;a href="http://learnpythonthehardway.com/"&gt;este&lt;/a&gt; y tutoriales completos como &lt;a href="http://mundogeek.net/archivos/2008/05/06/el-tutorial-de-python-en-pdf/"&gt;este otro&lt;/a&gt;. Cosas a tener muy en
cuenta para conocer en python primero:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Definición, uso y construcción de &lt;a href="http://docs.python.org/tutorial/modules.html"&gt;módulos en Python.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Definición y uso de funciones del tipo genérica, [uso de parámetros
    *args y *kwargs][].&lt;/li&gt;
&lt;li&gt;Uso y construcción de &lt;a href="http://docs.python.org/library/re.html"&gt;expresiones regulares básicas.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Programación orientada a objetos y herencia de clases.&lt;/li&gt;
&lt;li&gt;Como instalar paquetes de python desde &lt;a href="http://pypi.python.org/pypi"&gt;PyPi&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Django depende bastante de estos cuatro puntos anteriores, por ejemplo
sin conocer mucho de expresiones regulares no podrán construir urls.&lt;/p&gt;
&lt;h2&gt;Herramientas&lt;/h2&gt;
&lt;p&gt;Todo lo que necesitas es el interprete de python, django instalado, un
navegador web y tu editor de texto favorito. Existen también algunos IDE
con soporte a Django como &lt;a href="http://wingware.com/"&gt;Wingware&lt;/a&gt; y soporte para Python en
&lt;a href="http://www.eclipse.org/"&gt;Eclipse&lt;/a&gt; trabaja con lo que te sientas mas cómodo.&lt;/p&gt;
&lt;p&gt;Para motor de base de datos puedes elegir Postgres, MySQL, SQLite3, SQL
Server y Oracle igual que el punto anterior, usa tu favorito.&lt;/p&gt;
&lt;h2&gt;Modo de Trabajo&lt;/h2&gt;
&lt;p&gt;Tienes que tomar en cuenta que Django es un framework que usa el &lt;a href="http://es.wikipedia.org/wiki/Modelo_Vista_Controlador"&gt;patrón
MVC&lt;/a&gt; por lo que preferiblemente y por el bien de tu código debes de
separar muy bien la lógica, presentación y datos de tu aplicación, si
ves que esto se mezcla &lt;strong&gt;&lt;em&gt;estás haciendo algo mal&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Django es &lt;strong&gt;&lt;em&gt;modular&lt;/em&gt;&lt;/strong&gt;e introduce el concepto de "aplicaciones
plugables" que no son mas que módulos de Python encapsulando una parte
de funcionalidad de tu aplicación web. Ejemplo práctico: Tenemos una
página con un foro, un blog y una galería de fotos nuestro proyecto
tendría como mínimo tres aplicaciones django separando la sección de
blog, galería y foro. Este tipo de diseño hacen que existan mucho código
libre de aplicaciones que simplemente conectamos con nuestro proyecto,
si tiene nombre es muy probable que haya una aplicación de django para
eso!&lt;/p&gt;
&lt;p&gt;Si no me crees ve a &lt;a href="http://djangopackages.com/"&gt;http://djangopackages.com/&lt;/a&gt; y busca las múltiples
alternativas para resolver un problema que tengas. Normalmente en mis
proyectos uso al menos una aplicación creada por terceros y eso nos
facilita la vida tremendamente. En la práctica gracias a esto podemos
hacer un sitio con registro de usuarios, confirmación de correo, manejo
de avatares, perfiles de usuarios, blog, menús dinámicos en &lt;strong&gt;&lt;em&gt;menos de
media hora&lt;/em&gt;&lt;/strong&gt;, sin tomar en cuenta el tiempo que nos llevaría realizar
el diseño en html.&lt;/p&gt;
&lt;p&gt;Django también provee un motor de plantillas sencillo de entender pero a
la vez muy poderoso que permite separar los roles entre el frontend y
backend, haciendo mas sencillo el trabajo en equipos.&lt;/p&gt;
&lt;h2&gt;Mantenerse al día&lt;/h2&gt;
&lt;p&gt;Como todo en la vida y mas en el mundo de la programación y tecnología
es una necesidad mantenerse informado con lo último. Acá una pequeña
lista de sitios que pueden ayudar:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.djangoproject.com/community/blogs/"&gt;https://www.djangoproject.com/community/blogs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://django.es/comunidad/"&gt;http://django.es/comunidad/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://reddit.com/r/django"&gt;http://reddit.com/r/django&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.askthepony.com/blog/"&gt;http://www.askthepony.com/blog/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://django.es/blog/"&gt;http://django.es/blog/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Te invito a probarlo y te aseguro que te engancharás enseguida, si le
dedicas algo de tiempo podrías comenzar a hacer sitios web completamente
funcionales en menos de una semana.&lt;/p&gt;
&lt;p&gt;El fin.&lt;/p&gt;
&lt;p&gt;PD. Puedes dejar sugerencia sobre nuevos temas en los comentarios.&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Mon, 14 Nov 2011 13:57:00 -0600</pubDate><guid>tag:fitoria.net,2011-11-14:2011/11/django-suite-i-iniciar-con-django/</guid></item><item><title>Taller Django!</title><link>http://fitoria.net/2010/10/taller-django/</link><description>&lt;p&gt;Hoy se llevó a cabo un el primer taller sobre &lt;a href="http://www.djangoproject.com/"&gt;&lt;strong&gt;Django&lt;/strong&gt;&lt;/a&gt; en
Nicaragua, la cita se dió en &lt;a href="http://simas.org.ni/"&gt;&lt;strong&gt;SIMAS&lt;/strong&gt;&lt;/a&gt; y estuve compartiendo con los
asistentes sobre como hacer una pequeña aplicación de blog en este
framework y la &lt;a href="http://www.linuxjournal.com/content/nicaragua-builds-innovative-agricultural-information-system-using-open-source-software"&gt;experiencia de SIMAS&lt;/a&gt;. Acá les dejo la presentación
que utilicé:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.slideshare.net/AdolfoFitoria/django-5409708" title="Django"&gt;Django&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/AdolfoFitoria"&gt;Adolfo Fitoria&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hay algunas &lt;a href="http://www.facebook.com/album.php?aid=550974&amp;amp;id=310311545047"&gt;fotos haciendo click acá&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Tue, 26 Oct 2010 22:16:00 -0600</pubDate><guid>tag:fitoria.net,2010-10-26:2010/10/taller-django/</guid></item><item><title>Django template filter para obtener thumbnails de youtube.</title><link>http://fitoria.net/2010/10/django-template-filter-para-obtener-thumbnails-de-youtube/</link><description>&lt;p&gt;Acá les dejo un Django template filter para obtener el thumbnail de un
video de youtube a partir de su url, ejemplo de uso:&lt;/p&gt;
&lt;div class="codehilite"&gt;&lt;pre&gt;&lt;span class="x"&gt;&amp;lt;img src=&amp;quot;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt;video.url&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nf"&gt;youthumbnail&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;s&amp;#39;&lt;/span&gt;&lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="x"&gt;&amp;quot;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Tiene dos parámetros de tamaño 's' para un thumbnail pequeño y 'l' para
un thumbnail grande.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://djangosnippets.org/snippets/2234/"&gt;Ver en DjangoSnippets&lt;/a&gt;&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Sat, 16 Oct 2010 11:22:00 -0600</pubDate><guid>tag:fitoria.net,2010-10-16:2010/10/django-template-filter-para-obtener-thumbnails-de-youtube/</guid></item><item><title>¿Cómo agregar editores HTML al django admin?</title><link>http://fitoria.net/2009/05/%c2%bfcomo-agregar-editores-html-al-django-admin/</link><description>&lt;p&gt;&lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; trae una feature que es simplemente genial: &lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/"&gt;&lt;strong&gt;&lt;em&gt;interfaz
administrativa generada automáticamente&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt; como parte del framework.
Esta interfaz ahorra mucho tiempo de desarrollo el cual podés usar para
dejar mas bonita tu aplicación Django. Esta interfaz se puede customizar
hasta cierto punto pero desgraciadamente no trae un editor de &lt;a href="http://es.wikipedia.org/wiki/C%C3%B3digo_HTML"&gt;HTML&lt;/a&gt;
&lt;a href="http://es.wikipedia.org/wiki/WYSIWYG"&gt;WYSIWYG&lt;/a&gt;bonito de esos que se usan para poner un post en un blog o
foro que permiten que alguien sin conocimientos de HTML pueda dar estilo
a lo que escribe de manera sencilla y parecido a una suite ofimática.&lt;/p&gt;
&lt;p&gt;Para esto tenemos disponibles una &lt;a href="http://stackoverflow.com/questions/828004/cms-wysiwyg-for-dummies/"&gt;gran cantidad&lt;/a&gt; de editores hechos
en &lt;a href="http://es.wikipedia.org/wiki/Javascript"&gt;javascript&lt;/a&gt;libres y gratuitos disponibles en la red. En este caso
usaremos mi preferido &lt;a href="http://tinymce.moxiecode.com/"&gt;TinyMCE&lt;/a&gt; el cual es muy popular y es el editor
por defecto de &lt;a href="http://wordpress.org"&gt;Wordpress&lt;/a&gt;. Este editor funciona con los campos
definidos como &lt;a href="http://docs.djangoproject.com/en/dev/ref/models/fields/#textfield"&gt;TextField&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paso 1&lt;/strong&gt;: &lt;a href="http://prdownloads.sourceforge.net/tinymce/tinymce_3_2_3_1.zip?download"&gt;Bajar TinyMCE&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paso 2.&lt;/strong&gt; En un proyecto de Django agregar la carpeta de TinyMCE a la
locación donde guarden su javascript&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paso 3.&lt;/strong&gt; Agregar el &lt;a href="http://gist.github.com/110258"&gt;siguiente archivo&lt;/a&gt; para configurar el aspecto
dentro de una carpeta llamada editores (o como quieran ponerle) en la
misma ubicación del paso 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paso 4.&lt;/strong&gt; En el &lt;a href="http://gist.github.com/110262"&gt;admin.py&lt;/a&gt; de la aplicación en la cual desean tener
el editor hacer algo como esto: (ver comentarios)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paso 5.&lt;/strong&gt; Probarlo!!! y si hicieron todo bien sale asi:&lt;/p&gt;
&lt;p&gt;[&lt;img alt="tinymcedjango" src="http://fitoria.net/wp-content/uploads/2009/05/tinymcedjango.png" title="tinymcedjango" /&gt;][]&lt;a href="https://dl.getdropbox.com/u/611460/django-tinymce.zip"&gt;Bajar projecto de Django de demostración&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;[&lt;img alt="tinymcedjango" src="http://fitoria.net/wp-content/uploads/2009/05/tinymcedjango.png" title="tinymcedjango" /&gt;]: http://fitoria.net/wp-content/uploads/2009/05/tinymcedjango.png&lt;/p&gt;</description><dc:creator xmlns:dc="http://purl.org/dc/elements/1.1/">fitoria</dc:creator><pubDate>Mon, 11 May 2009 20:06:00 -0600</pubDate><guid>tag:fitoria.net,2009-05-11:2009/05/%c2%bfcomo-agregar-editores-html-al-django-admin/</guid></item></channel></rss>