Feb 27

penguin

penguin

:D

Author: Vero

Jan 28

go-downloader descarga desde goear.com

usas goear.com

Estas 2 semanas (fines de semana solamente) estuve trabajando en desarrollar una aplicacion que descargue los mp3 desde goear.com a tu disco, la desarrolle en python usando "quickly" una herramienta que te ayuda distribuir una aplicacion para ubuntu.

https://launchpad.net/~luismmontielg/+archive/godownloader

UPDATE: Dado que goear.com ha ofuscado y modificado la arquitectura del servicio de mp3, el programa no funciona, pero me sirivió de mucho para aprender py-gtk, el código está en LP, por si alguien quiere agarrarlo (Carlos) y hacer un fix para que vuelva a funcionar. Por falta de tiempo no modificaré el programa por ahora.

Jan 21

Cannot empty clipboard error, Windows

Para el trabajo necesito usar windows, ya que me conecto a un escritorio remoto en Chicago a través de un enlace por medio de una VPN. Y trabajo desde aquí en México.

Me había pasado varias veces que como nunca (casi nunca) apago mi computadora remota (esto es para simplemente llegar y conectarme y que ya estén todos los programas abiertos como los deje la ultima vez, y también por flojo) después de un tiempo, de tanto hacer copy-paste, mas que nada en excel, me marca un error de que no puede vaciar el clipboard, y ya no puedo copiar mas con el CTRL-V o algún otro método.

Entonces la solución que encontré con ayuda de google fue esta:

  1. Abres el task manager.
  2. Localiza el proceso llamado "rdpclip.exe"
  3. Termina el proceso.

Y ya esta, se liberara la memoria y podremos seguir copy-pasteando todo el día.

Jan 20

Eclipse en GTK, maximizar espacio en pantalla

Usas eclipse en linux con GTK y no te gusta como se ve?

Bueno pues si son desarrolladores, porsupuesto que han usado eclipse, uno de los mejores IDEs que hay hoy en dia. Si lo han usado en linux, con GTK, habran notado que no se ve tan BIEN como en windows, se ve un poco mas "grande" la letra y como que con menos espacio.

Aqui les dejo un truco que me dejo con un eclipse mucho mejor que el que se ve en winbugs ;(.

Primero hay que hacer un archivo llamado "gtkrc-sar" o como le quieran llamar...

y peguen esto:


style "eclin" {
GtkButton::default_border={1,1,1,1}
GtkButton::default_outside_border={1,1,1,1}
GtkButtonBox::child_min_width=0
GtkButtonBox::child_min_heigth=0
GtkButtonBox::child_internal_pad_x=0
GtkButtonBox::child_internal_pad_y=0
GtkMenu::vertical-padding=1
GtkMenuBar::internal_padding=1
GtkMenuItem::horizontal_padding=4
GtkToolbar::internal-padding=1
GtkToolbar::space-size=1
GtkOptionMenu::indicator_size=0
GtkOptionMenu::indicator_spacing=0
GtkPaned::handle_size=4
GtkRange::trough_border=0
GtkRange::stepper_spacing=0
GtkScale::value_spacing=0
GtkScrolledWindow::scrollbar_spacing=0
GtkExpander::expander_size=10
GtkExpander::expander_spacing=0
GtkTreeView::vertical-separator=0
GtkTreeView::horizontal-separator=0
GtkTreeView::expander-size=12
GtkTreeView::fixed-height-mode=TRUE
GtkWidget::focus_padding=0
font_name="Liberation Sans,Sans Regular 8"
}
class "GtkWidget" style "eclin"

style "eclin2" {
xthickness=1
ythickness=1
}

class "GtkButton" style "eclin2"
class "GtkToolbar" style "eclin2"
class "GtkPaned" style "eclin2"

Luego, hagan un archivo de texto y denle permiso de ejecución, y peguen esto (pueden llamarlo "lanzadorEclipse" ):


#!/bin/sh
export GDK_NATIVE_WINDOWS=1
GTK2_RC_FILES=/ruta/a/eclipse/gtkrc-sar '/ruta/a/eclipse/eclipse'

Y eso es TODO. Vera un eclipse muy bien parecido ;).

eclipse en GTK

FUENTE: http://techtavern.wordpress.com/2008/09/24/smaller-font-sizes-for-eclipse-on-linux/

Jan 20

Dropbox

Hoy abrí mi cuenta de dropbox, ya que un amigo me lo recomendó, y al parecer esta muy bueno, tiene soporte para windows, mac y linux, yo que uso linux, lo probare (a ver que tal).

De entrada te dan 2 GB de espacio, digo no es mucho pero al menos es algo. Para subir fotos basicas que siempre necesitas para avatares, etc. y unos cuantos documentos muy necesarios.

Bueno, aqui esta el link https://www.dropbox.com/referrals/NTQxMzQ4MjE5, para que porfavor se suscriban y asi me den un poco mas de espacio ;)!

Ademas, espero ya empezar a escribir denuevo.

Nov 04

Revertir clicks en ubuntu karmic

regresando el click de enmedio al tap con dos dedos en karmic

Algunos habran notado que ahora en Karmic al hacer "tap" en el touchpad de la laptop con 2 dedos, se activa el click derecho, y con 3 dedos, se activa el click de enmedio. Personalmente yo uso mas el click de enmedio (para abrir links en otros tabs en firefox por ejemplo), asi que para regresarlo a "como estaba antes" solo hay que correr esto:

synclient TapButton2=2; synclient TapButton3=3;

lo malo, es que solo dura para la sesion actual, hay que ponerlo en Sistema, Preferencias, Aplicaciones al inico... Y ya quedo ;)

Oct 27

unix cheatsheet

miedo a la shell?

Sep 26

Atajo para búsquedas en la documentacion de django

quieres buscar con mayor eficiencia en la documentación oficial de django?

Para los que constantemente se la pasan recurriendo a la documentación de django y usan firefox o chrome/chromium, esto les puede ahorrar unos cuantos segundos:

django-search-1
  • Damos clic derecho en la barra de búsqueda y seleccionamos la opción: "Add a keyword for this search", no se como diga en español pero ahi lo pueden encontrar.

  • Después establezcan como nombre algo así como django-search, y como keyword yo puse "d".

  • Entonces al estar en firefox solo hago CTRL+L, luego tipeo "d models" y automáticamente busca en la pagina de la documentación el tema de los modelos. Muy rapido.

Si tienen chrome, después de haber hecho esto, vayan a las opciones e importen las búsquedas desde firefox y ya pueden hacer el mismo proceso, con los mismos atajos.

Con esta técnica tengo búsquedas en muchas paginas que tienen search fields, es mas rápido que tener que navegar a la pagina web.

Jul 20

Las bases de paginas web en django

Vamos a crear una pagina Web dinamica en django, una que despliegue la hora fecha y hora actual, este es un buen ejemplo de una "pagina dinamica", ya que sus contenidos no son estaticos, al contrario, son el resultado de algun calculo en el servidor(en este caso es el simple calculo de la fecha y hora actual, pero podria ser cualquier otra cosa mas compleja).

Este ejemplo no involucra alguna base de datos ni algun tipo de datos de entrada por el usuario.

Para crear esto, vamos a crear una "view" de django, esta vista, es en si un "controlador", mas que lo que entendemos por "vista", esta no nos va a mostrar nada en si, ya que django muestra los resultados en el navegador por medio de las "templates" o plantillas. La view es la funcion encargada de procesar un "request" de http, una simple peticion al server. La view tambien es responsable de devolver una http response, o respuesta http, ya sea en forma de un HTML, un XML, una imagen, texto plano, etc., todo esto se hara ahi en la view. Ahi accederemos a la base de datos con consultas y modificaciones, cambiaremos atributos a objetos antes de ser desplegados y finalmente llamaremos a otra parte de django que son las plantillas para mostrar los resultados. En caso de error ahi mandamos llamar paginas 404, 500, etc.

El codigo de una view puede estar donde sea, siempre y cuando este en el PYTHONPATH y pueda ser accedido, pero por convencion se guarda en miaplicacion.views, osea en un archivo llamado views.py.

Ahora vamos a crear esta view, que es solo una simple funcion en python:

#Importamos la respuesta, que es una clase en python llamada HttpResponse, del modulo django.http
from django.http import HttpResponse
#importamos el modulo python del tiempo
import datetime

def fecha_y_hora_hoy(request):
    ahora = datetime.datetime.now()
    html = "Estamos a %s." % ahora
    return HttpResponse(html)

Bien pues esta muy sencilla la funcion:

  • Primero que nada hacemos los imports necesarios.
  • Luego podemos ver que nuestra funcion, tiene un parametro "request", que es un objeto HttpRequest, para conocer mas a fondo estos 2 objetos, ir a la documentacion de django.
  • El nombre del parametro request, es una convencion tambien
  • Por ahora el nombre de la funcion es irrelevante, siempre hay que tratar de utilizar nombres de funciones explicitos. Luego veremos como django encuentra la forma de llamar esta funcion.
  • Aunque el html que generamos no esta muy completo, nos sirve para ser desplegado, y con el formateo de strings de python metemos la variable "ahora", en lugar de usar una concatenacion. %s significa que ahi va a ir una string. Para mas sobre metodos de formateo de strings y reemplazamiento ir a la documentacion de python
  • Al final regresamos un objeto HttpResponse, cada view debe de regresar un HttpResponse, hay excepciones que luego veremos.

Ya tenemos nuestra funcion, ahora queremos que django la muestre, o sacar algo de provecho de ella y mostrarla en el navegador, como la activamos?

Mapeando URLs a Views

Usaremos lo que son "URLconfs", una URLconf es como una tabla de contenidos para tu sitio django. Basicamente es el mapeo entre patrones de URL y funciones "views" que deberan ser llamadas para cada uno de esos "patrones" de URL. Es como decirle a django, para esta URL, ejecuta este codigo, para esta otra, este otro codigo.

Cuando creamos un projecto en django con django-admin.py startproject, nos genera un archivo llamado urls.py, bueno pues aqui es donde residen los patrones de URL

por defecto es algo como esto:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    # Example:
    # (r'^mysite/', include('mysite.apps.foo.urls.foo')),

# Uncomment this for admin:
    # (r'^admin/', include('django.contrib.admin.urls')),
)

Veamos lo que hace:

  • La primera linea importa todo de django.conf.urls.defaults, que incluye una funcion llamada "patterns"
  • La segunda linea llama a la funcion "patterns()" y guarda el resultado en una variable llamada "urlpatterns".
  • patterns() es llamada por ahora con una string en blanco ' ' como argumento, pero eso lo modificaremos mas adelante.

Lo mas importante aqui es la variable urlpatterns, django espera que este declarada la variable "ROOT_URLCONF" en el modulo que uses como settings, casi siempre es settings.py

Vamos a editar urls.py:

from django.conf.urls.defaults import *
from mysite.views import fecha_y_hora_hoy

urlpatterns = patterns('',
    url(r'^time/$', fecha_y_hora_hoy),
)

Primero importamos de nuestra aplicacion, del modulo views, la funcion fecha_y_hora_hoy, esto es un import de python, para mas documentacion ver la documentacion de python. Ya importada, vamos a modificar la forma en que llamamos la funcion patterns(), mantenemos el primer argumento como ' ', ya que no lo ocuparemos por ahora, despues de ahi, vamos a ir agregando el resultado de la funcion url(). Esto lo explicare ahora:

El Despachador de URLs:

Un limpio, elegante esquema de URLs es un detalle importante en una aplicacion web. Django tepermite dise;ar tu esquema de URLS, de la manera que mas te agrade, sin limitaciones.

Para el diseño de las URLs de una aplicación, se crea un módulo de Python informalmente llamado URLconf (URL de configuración). Este módulo es puro código Python y es una simple relación entre los patrones de URL (como simples expresiones regulares) a funciones de python.

Este mapeo puede ser tan corto o tan largo como sea necesario. Puede referenciar otras asignaciones. Y, porque es puro código Python, puede ser construida dinámicamente.

¿Cómo es que Django procesa una petición http?

Cuando un usuario solicita una página de su sito de Django, este es el camino que sige el sistema para determinar la ejecución de código Python:

  1. Django determina la "URLconf raiz" a usar. Normalmente, este es el valor de la ROOT_URLCONF en settings.py, pero si el objeto HttpRequest entrante tiene un atributo llamado urlconf, su valor será utilizado en lugar de la ROOT_URLCONF de settings.
  2. Django carga este módulo de python y busca la variable urlpatterns. Esta debera ser una lista de python, en el formato devuelto por la función django.conf.urls.defaults.patterns ().
  3. Django corre a través de cada patrón de URL, en orden, y se detiene en el primero que coincide con la URL solicitada.
  4. Una vez que uno de los patrones concuerda, django importa y ejecuta la view, que es una simple función de Python. A la view se le pasa un HttpRequest como su primer argumento y los valores capturados en el resto del patron como argumentos.

Ejemplo:

from django.conf.urls.defaults import *
urlpatterns = patterns('',
    (r'^articles/2003/$', 'news.views.special_case_2003'),
    (r'^articles/(\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

Notas:

  • from django.conf.urls.defaults import * hace que la funcion patterns() este disponible(mas sobre esto adelante).
  • Para capturar un valor desde la url, solo ponlo entre parentesis(esto se puede mejorar mucho mas, mas adelante lo veremos).
  • No hay necesidad de agregar / al principio: ^articles, NO ^/articles.
  • La 'r' antes de cada expresion regular es opcional pero es MUY recomendada, esa string le dice a python que es "cruda" y nada en la string debera ser escapado.

Ejemplos de peticiones:

  • Una peticion a /articles/2005/03/ llamaria a la funcion news.views.month_archive(request, '2005', '03').
  • /articles/2005/3/ no encajaria en ningun patron, porque para el mes, se requieren 2 digitos segun la expresion regular.
  • /articles/2003/ encajaria con el primer patron, NO el segundo, ya que los patrones se van evaluando en el orden en que aparecen, esto a veces se puede cambiar a nuestro favor, cambiando el orden a proposito.
  • /articles/2003 no encajaria en NINGUNO, ya que todos los patrones requieren que acabe con /
  • /articles/2003/03/3/ encajaria en el ultimo patron y se llamaria a la funcion asi news.views.article_detail(request, '2003', '03', '3').

Named groups

El ejemplo de arriba usaba simple, grupos de expresiones regulares sin-nombre (por medio de los parentesis) para caputar los pedazos de la string y mandarlos como positional arguments a una view. Una forma mas avanzada y mas recomendada de hacer esto son,los "grupos de expresion regular con nombre" que capturan pedazos de la url y los mandan como keyword-arguments a la view.

En python, esto se hace asi (?Ppattern), donde variable es el nombre del grupo y pattern es el patron de regex.

Aqui esta el ejemplo pasado mejorado para usar esto:

urlpatterns = patterns('',
    (r'^articles/2003/$', 'news.views.special_case_2003'),
    (r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
    (r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d+)/$', 'news.views.article_detail'),
)

Esto logra exactamente lo mismo que en el ejemplo anterior, con una sutil diferencia: Los valores capturados son pasados a la view como keyword-arguments en lugar de argumentos posicionales. Por ejemplo:

  • La solicitud a /articles/2005/03/ a llamar a la función news.views.month_archive (request, year='2005 ', month='03'), en lugar de news.views.month_archive (request,'2005 ', '03 ').
  • La solicitud a /articles/2003/03/3/ va a llamar a la función news.views.article_detail (request, year ='2003 ', month='03', day='3').

En la práctica, esto significa que su URLconfs son un poco más explícita y menos propenso a errores argumento de orden - y puede reordenar los argumentos a su preferencia.

Nota: aunque en la rexeg pongamos que esperamos 2 digitos, enla funcion django se pasan como STRING siempre

Sintaxis de la variable urlpatterns

urlpatterns debe ser una lista de Python, en el formato devuelto por la función django.conf.urls.defaults.patterns (). Siempre siempre hay que usar patterns() para crear la variable urlpatterns.

Es una convencion usar from django.conf.urls.defaults import * en la parte superior de su URLconf. Esto le da a su módulo de acceso a estos objetos:

patterns

Una función que toma un "prefijo" y un número arbitrario de patrones de URL, y devuelve una lista de patrones de URL en el formato que django necesita en la variable urlpatterns

El primer argumento de patterns() es una cadena "prefijo".

El resto de argumentos deben tuplas en este formato:

(expresión regular, Python función callback [, diccionario opcional [, nombre opcional]])

donde si queremos colocar un nombre a la view, tenemos que poner a fuerzas un diccionario, ya que es opcional el ultimo conjunto, pero de los 2 juntos (notar los [ ])

Nota: Porque patterns() es una llamada a una función, se acepta un máximo de 255 argumentos (patrones de URL, en este caso). Este es un límite para todas las llamadas a funciones de Python. Esto no suele ser un problema en la práctica, porque lo general, su estructura modular los patrones de URL con secciones include() Sin embargo, ante la posibilidad de que se pueda llegar al límite de 255 argumentos, se dan cuenta de que patterns() devuelve una lista de Python, por lo que puede dividir la construcción de la lista por medio de la concatenacion:

urlpatterns = patterns('',
    ...
    )
urlpatterns += patterns('',
    ...
    )

Python usa listas con tamaño ilimitado, por lo que no hay límite para el número de patrones de URL puede construir. El único límite es que se puede crear sólo 254 a la vez (ya que el el argumento numero 255 es el "prefijo" que veremos mas adelante).

url

Nuevo en Django 1.0:

Puede utilizar la funcion url(), en lugar de una tupla, como argumento de patterns(). Esto es conveniente si desea especificar un nombre sin la opción argumentos diccionario. Por ejemplo:

urlpatterns = patterns('',
     url(r '^índice/$', index_view, name="principal-view"),
     ...
)

Esta función tiene cinco argumentos, la mayoría de los cuales son opcionales:

url (regex, view, kwargs=None, name=None, prefix ='')

El parámetro "prefix" tiene el mismo significado que el primer argumento de patterns() y sólo es relevante cuando se pasa un string como parámetro de la vista, no la funcion en si.

include

Una funcion que toma como argumento el path completo hacia otra URLconf que deberia "incluirse" en ese lugar.

El "prefix" de la view

Recuerden la funcion patterns(), su primer parametro es el prefijo, que siempre habiamos dejado en blaco "". Bueno pues enviando este primer argumento podemos especificar un prefijo comun a todas las vistas de los patrones de url de abajo, esto para simplificar el codigo y evitar repetir codigo.

Aqui hay un ejemplo:

from django.conf.urls.defaults import *
urlpatterns = patterns('',
    (r'^articles/(\d{4})/$', 'mysite.news.views.year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'mysite.news.views.month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'mysite.news.views.article_detail'),
)

En este ejemplo, cada vista tiene un prefijo comun, 'mysite.news.views', en lugar de poner esto en cada entrada para patterns(), vamos a mandarselo como primer argumento:

from django.conf.urls.defaults import *

urlpatterns = patterns('mysite.news.views',
    (r'^articles/(\d{4})/$', 'year_archive'),
    (r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
    (r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'),
)

Tambien podemos hacer esto:

from django.conf.urls.defaults import *

urlpatterns = patterns('django.views.generic.date_based',
    (r'^$', 'archive_index'),
    (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','archive_month'),
)

urlpatterns += patterns('weblog.views',
    (r'^tag/(?P<tag>\w+)/$', 'tag'),
)

Muy util, concatenacion de listas.

Incluyendo otras URLconfs

En cualquier momento en tu urls puedes incluir otras URLconfs.

Por ejemplo:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^weblog/',        include('django_website.apps.blog.urls.blog')),
    (r'^documentation/', include('django_website.apps.docs.urls.docs')),
    (r'^comments/',      include('django.contrib.comments.urls')),
)

Notar que las expresiones regulares en este ejemplo no tienen '$' que significa final del string, pero si incluyen '/', cuando django encuentra un include(), corta todo todo lo que esta despues del string que concuerda con la expresion regular y lo demas lo manda al otro modulo de URLconf, para que aya sea procesado.

Pasando opciones extra a las views

Las URLconf tienen un truco que les deja pasar argumentos extra a la funcion que sera llamada, como un diccionario en python. Cualquier tupla dentro de URLconf puede tener un tercer elemento opcional (como ya les habia comentado arriba) e incluso un cuarto, "name", que nombra a nuestra view, esto lo veremos mas adelante, mientras, aqui un ejemplo de esto:

urlpatterns = patterns('blog.views',
    (r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
)

En este ejemplo para una peticion a /blog/2005/, django va a llamar blogs.views.year_archive(), passandole estos keyword-arguments:

year='2005', foo='bar'

Ya que year es capturado en el regex, como vimos antes, y el diccionario opcional tiene una llave llamada 'foo', cuyo valor es el string 'bar'.

De forma similar se le pueden mandar opciones extra a include(), mediante un segundo argumento, que es un diccionario de python.

Asi, estos 2 URLconfs son iguales:

# main.py
urlpatterns = patterns('',
    (r'^blog/', include('inner'), {'blogid': 3}),
)

# inner.py
urlpatterns = patterns('',
    (r'^archive/$', 'mysite.views.archive'),
    (r'^about/$', 'mysite.views.about'),
)

Y:

# main.py
urlpatterns = patterns('',
    (r'^blog/', include('inner')),
)

# inner.py
urlpatterns = patterns('',
    (r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
    (r'^about/$', 'mysite.views.about', {'blogid': 3}),
)

vemos que es mas "corto" el primero, ya que solo enviamos el diccionario y este se le agregaria a todas las tuplas del URLconf del include. Claro, debemos se asegurarnos que todas las funciones del URLconf, acepten los parametros que le enviamos en el include.

Pasando objectos "callables" en lugar de strings.

Tambien en URLconf podemos en lugar de mandar 'miapp.views.mivista' mandar la funcion:

urlpatterns = patterns('',
    (r'^archive/$', 'mysite.views.archive'),
    (r'^about/$', 'mysite.views.about'),
    (r'^contact/$', 'mysite.views.contact'),
)

Esto lo podemos escribir igual de este modo, con puras funciones de python:

from mysite.views import archive, about, contact

urlpatterns = patterns('',
    (r'^archive/$', archive),
    (r'^about/$', about),
    (r'^contact/$', contact),
)

Aqui tenemos que importar primero estas funciones antes de intentar usarlas.

Nota: recordar que al usar esta notacion, el "prefijo" de patterns(), no tiene efecto, solo es aplicable cuando usamos puras strings en las tuplas de URLconf.

Nombrando URL patterns

Es muy comun usar la misma funcion view para multiples patrones URL, por ejemplo

urlpatterns = patterns('',
    (r'^archive/(\d{4})/$', archive), def archive(reaquest, year, smmary=False)
    (r'^archive-summary/(\d{4})/$', archive, {'summary': True}),
)

Esto es completamente valido, pero te lleva a problemas cuando intentas hacer una busqueda reversiva de la url, por medio del decorador permalink() o el tag "url" de las plantillas. Continuando con el ejemplo, si quisieras agarrar la URL para la vista de archive, django se confundiria, ya que hay 2 patrones que apuntan a la misma view, para esto, django soporta las url patterns nombradas, esto asigna un unico nombre a un url pattern para distinguirlo de los demas.

urlpatterns = patterns('',
    url(r'^archive/(\d{4})/$', archive, name="full-archive"),
    url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}, name="arch-summary"),
)

Con esos nombres (full-archive and arch-summary), puedes dirigirte a cualquiera de los 2 patrones usando su nombre:

{% url arch-summary 1945 %}
{% url full-archive 2007 %}

Nota: Cuando nombres a los patrones de URL, asegurate de usar nombres que no es probable que choque con cualquier otra aplicación. Si llamas a tu patrón de URL "comentario", y otra aplicación lo llama igual, no hay garantía cual sera la URL llamada. Poner un prefijo a los nombres de su URL, es algo muy recomendado, myapp-nombre, como "myapp-comentario" en lugar de solo "comentario".

Jun 26

Creando una wiki en django

Vamos a crear una simple wiki, usando django

Vamos a crear una simple wiki sobre django, para esto primero vamos a crear el proyecto django:

$ django-admin.py startproject simplewiki
$ cd simplewiki
$ python manage.py startapp iwiki

Modificamos settings.py deacuerdo a nuestra base de datos, si necesitamos crear la base de datos, la hacemos.

Ahora vamos a crear los modelos, en iwiki/models.py


from django.db import models
from django import forms

# Create your models here.

class Pagina(models.Model):
    nombre = models.CharField(max_length=50, unique=True)
    contenido = models.TextField(blank=True)

def get_absolute_url(self):
        return ('detalles', (), {'nombre':self.nombre})
    get_absolute_url = models.permalink(get_absolute_url)

def __unicode__(self):
        return self.nombre

class PaginaForm(forms.ModelForm):

class Meta:
        model = Pagina

Aqui lo que creamos es un simple modelo, de una Pagina wiki, luego le podemos agregar atributos como categorias, author, estado(borrador, etc), solo lectura, etc. Tambien creamos una Form, osea un formulario, para editar/crear instancias de un determinado modelo, en este caso es "Pagina". Como vemos es bastante simple crear esta clase en python, simplemente en la clase interna "Meta" le asignamos el atributo model = Pagina y listo. El metodo get_absolute_url es utilizado para obtener una unica url para el objeto especificado, asi, regresamos el nobre de la url(ver nuestro urls.py, una tupla con argumentos posicionales, y un diccionario con argumentos nombrados. Despues decoramos esta funcion con models.permalink, haciendo esto un enlace permanente.

Agregamos a INSTALLED_APPS en settings.py nuestra aplicacion y tambien la de django.contrib.admin, luego hacemos la sincronizacion de la base de datos:


python manage.py syncdb

Ahora vamos a crear el archivo iwiki/admin.py :


from django.contrib import admin
from simplewiki.iwiki.models import *

admin.site.register(Pagina)

Con esto registramos el objeto Pagina en el administrador de django. Ahora vamos a crear unas urls, editamos urls.py:


from django.conf.urls.defaults import *
from django.contrib import admin

admin.autodiscover()

urlpatterns = patterns('',
    url(r'^simplewiki/', include('simplewiki.iwiki.urls')),
    url(r'^admin/', include(admin.site.urls)),
)

Aqui lo que hacemos es incluir en 'simplewiki/' las urls de iwiki, esto nos sirve para transportar nuestra aplicacion iwiki, a cualquier otro proyecto de django y mantener todo mas organizado. Ahora creamos iwiki/urls.py :

from django.conf.urls.defaults import *

urlpatterns = patterns('simplewiki.iwiki.views',
    url(r'^$', 'listado', name='listado'),
    url(r'^(?P\w+)/$', 'detalles', name='detalles'),
)

Como podemos ver, solo tenemos 2 patrones de urls, una en "", osea midominio.com/simplewiki/, nos mandaria al "listado" , y la otra midominio.com/simplewiki/PaginaWiki, nos mandaria a los detalles de esa pagina wiki.

Bueno ahora necesitamos crear esas vistas en el archivo iwiki/views.py


from django.shortcuts import render_to_response
from simplewiki.iwiki.models import *
from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect, \
                                            HttpResponse

# Create your views here.

def listado(request):
    """despliega una lista de todas las paginas wiki"""
    paginas = Pagina.objects.all()
    return render_to_response('iwiki/listado.html', \
                      {'articulos':paginas})

def detalles(request, nombre):
    return HttpResponse("detalles")

def editar(request, nombre):
    return HttpResponse("editar")

Las 2 views de abajo, se ocuparan mas adelante, pero por ahora dejemoslas asi. Empezaremos por crear el listado, es una simple view que nos va a mandar a un html que nos desplegara todos los Articulos de la wiki. Pero necesitamos crear el template. Para esto creamos el archivo templates/iwiki/listado.html, tambien debemos decirle django, que busque las plantillas en la carpeta "templates". Para esto modificamos settings.py :


TEMPLATE_DIRS = (
    '/home/luis/documentos/dev/django/simplewiki/templates'
)

Cambiando su ruta absoluta por la que concuerde en su pc... Ahora si, editamos templates/iwiki/listado.html:

Listado de todos los Articulos

Esto esta bastante simple y nos va a mostrar una lista de links a los articulos Wiki, recuerdan el metodo get_absolute_url, pues aqui esta un claro ejemplo de su utilidad, hacemos un link con href a nuestro permalink, y listo, django hace el resto. Ahora vamos a modificar la vista detalles, para que nos muestre la informacion acerca del articulo que queremos ver, editamos iwiki/views.py


def detalles(request, nombre):
    """Muestra un articulo de la wiki"""
    articulo = None
    try:
        articulo = Pagina.objects.get(nombre=nombre)
    except Pagina.DoesNotExist:
        pass
    if ('editar' in request.GET):
        return editar(request, nombre)
    return render_to_response('iwiki/detalles.html', {'articulo':articulo, 'nombre':nombre})

Pues esta view tambien esta sencilla, intentamos agarrar la Pagina y la guardamos en articulo, por ahora ignoren la parte del request.GET, lo veremos mas adelante. Si no existe ese articulo, la variable articulo sera None, y sera enviada a la plantilla 'iwiki/detalles.html' como None. Ahora veamos esta utilidad en el html. Creamos templates/iwiki/detalles.html:


{% load markup %}
    

{{ nombre }}

{% if articulo %}

{{ articulo.contenido|wikifica|markdown }}

editar? {% else %}

Este articulo no existe, deseas crearlo? {% endif %}

Mostramos la variable nombre, luego si "articulo" existe en el contexto desplegamos la informacion, usando el filtro markdown, para esto tuvimos que cargar con el tag "load" el paquete markup, esto se puede hacer solo si en INSTALLED_APPS de settings.py agregamos 'django.contrib.markup':


INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.admin',
    'django.contrib.markup',
    'iwiki',
)

Luego, si no existe el articulo, desplegamos la opcion para crearlo, tal como la wiki funciona: presten atencion al link....

Le estamos diciendo que nos mande a la url llamada 'detalles', le mandamos como primer argumento la variable "nombre" del contexto y despues agregamos el string ?editar, esto nos daria una url asi por ejemplo: Si tipeamos en el browser: http://localhost:8000/simplewiki/NoExiste Nos da el mensaje: Este articulo no existe, deseas crearlo? Donde el link de "crearlo?" es: http://localhost:8000/simplewiki/NoExiste/?editar

entonces vamos a revisar la view "detalles" que es a donde nos va a mandar:


def detalles(request, nombre):
    """Muestra un articulo de la wiki"""
    articulo = None
    try:
        articulo = Pagina.objects.get(nombre=nombre)
    except Pagina.DoesNotExist:
        pass
    if ('editar' in request.GET):
        return editar(request, nombre)
    return render_to_response('iwiki/detalles.html', \
                                  {'articulo':articulo, 'nombre':nombre})

Observer, ahora ya tiene sentido que chequemos si el request.GET, que es el diccionario de la peticion GET, tiene una llave llamada "editar", si si la tiene, nos manda a la funcion editar, que antes no tenia ningun uso, vamos a modificarla:


def editar(request, nombre):
    """Editar/Crear una pagina wiki"""
    msg = ''
    articulo = Pagina(nombre=nombre)
    try:
        articulo = Pagina.objects.get(nombre=nombre)
        form = PaginaForm(instance=articulo)
    except Pagina.DoesNotExist:
        pass
    if (request.POST):
        if ('delete' in request.POST):
            #borramos y enviamos a la lista de Articulos
            articulo.delete()
            return HttpResponseRedirect(reverse('listado'))
        else:
            form = PaginaForm(request.POST, instance=articulo)
            if (form.is_valid()):
                form = PaginaForm(request.POST, instance=articulo)
                articulo = form.save()
                msg = 'Articulo grabado con exito'
    form = PaginaForm(instance=articulo)
    return render_to_response('iwiki/editar.html', \
              {'articulo':articulo, 'form':form, 'msg':msg,})

Aqui vamos a explotar los beneficios de las modelForms, osea formularios basados en objetos, estos se pueden crear a partir de un POST request y basados en una instancia ya existente, para que solo modifique los objetos que ya existen y guarde los nuevos, al ejecutar el metodo save(). Les recomieno mucho leer la documentacion de las model Forms y las Forms normales:

  • http://docs.djangoproject.com/en/dev/topics/forms/modelforms/
  • http://docs.djangoproject.com/en/dev/topics/forms/

Bueno, analicemos un poco la view editar, primero intentamos agarrar el articulo, si es que existe, si no , pues ya lo habiamos declarado arriba con el nombre=nombre de la peticion, ahora vamos a checar si la request es POST, si lo es y ademas tiene la llave 'delete' vamos a borrar el articulo y regresar al listado, esto esta bastante sencillo. Pero si no tiene 'delete' como llave y sigue siendo POST, entonces seria un POST del form del articulo, y tendremos que procesar, su edicion/creacion. primero validamos si estan completos los campos del formulario, si si, vamos a crear una form con esos datos y con la instancia de la base de datos, si no existe, con la instancia que solo tiene el nombre=nombre(declarada arriba), despues usamos el metodo save() de la form para que nos guarde y nos devuelva el articulo que recien grabo, mandamos un mensaje de confirmacion y despues vamos a crear la form que se desplegara en nuestra plantilla con el articulo recien grabado/creado. Necesitamos hacer la template en templates/iwiki/editar.html:

{{ articulo.nombre }}

{{msg}}
{% for field in form %}

{{ field }} {% if field.errors %} {% for error in field.errors %} * {{ error}}
{% endfor %} {% endif %}

{% endfor %}

Aqui mostramos la form, del articulo y le damos que la accion sea '', en la misma pagina, tambien creamos otra form, con el 'delete' oculto y el boton que diga borrar. y por ultimo ocupamos el get_absolute_url para ver el articulo en la pagina.

Espero que esto les sirva como apoyo y como experiencia para aquellos desarrolladores que quieran aprender django.

(11 Julio 2009) UPDATE: me falto poner el codigo del filtro "wikifica", hay que crear en iwiki/templatetags un archivo llamado "wikitags.py" y dentro ponemos:


from django import template
register = template.Library()

@register.filter
def wikifica(value):
    "Forma las wikipalabras"
    import re
    wikificador = re.compile(r'\b(([A-Z]+[a-z]+){2,})\b')
    #WikiPalabra
    #ver la forma de no hardcodear simplewiki, ya que puede cambiar
    return wikificador.sub(r'\1', value)

Si no tienes la carpeta, la creas, aqui es donde por default se cargan tags adicionales para plantillas o "templatetags" creados por el usuario, en este caso esta simple nuestro filtro, lo que hace es buscar en "value" que es un string, las coincidencias con el patron regex de una WikiPalabra y regresa un link.

Muchas gracias a Carlos P.L que noto el error, bueno pues creo que esto es todo lo que faltaba, ahora ya podemos ver que los links se hacen al escribir algo ComoEsto, espero que les sirva, y cualquier otra duda comentenla.

Jun 24

Chuleta de vim

novato en vim?

Aqui les dejo una chuleta de vim

vim cheatsheet-1vim cheatsheet-2vim cheatsheet-3

Jun 21

Instalar django trunk en ubuntu

Primero que nada instalamos setuptools y subversion:

sudo aptitude install python-setuptools subversion

instalamos Mysql-python, si vamos a usar mysql con django:

sudo easy_install Mysql-python

Obtenemos nuestro site-packages de python:

python -c "from distutils.sysonfig import get_python_lib; print get_python_lib()"

Esto lo guardamos por ahi ya que lo ocuparemos, "site-packages" sera como le llamaremos a esa cadena para referencias posteriores.

Bajamos django trunk

svn co http://code.djangoproject.com/svn/django/trunk/ django-trunk

Luego vamos a crear un enlace simbolico, para meter a django en los site-packages, esto se puede saltar, si metemos la carpeta django-trunk/django en el PYTHONPATH:

ln -s `pwd`/django-trunk/django "site-packages"/django

Donde "site-packages" lo reemplazamos por lo que les dije previamente.Abrimos python e intentamos importar django, si nos marca error, algo hicimos mal, si no, adelante, vamos a enlazar django-admin.py a nuestro PATH con:

ln -s `pwd`/django-trunk/django/bin/django-admin.py /usr/local/bin

Y ya podemos ejecutar django-admin.py desde donde sea, para crear nuestros proyectos en django. Agregarmos la variable PYTHONPATH

vi ~/.bashrc
export PYTHONPATH=/ruta/a/carpeta/proyectos/django

Guardamos y salimos,reiniciamos la terminal y ya esta listo nuestro $PYTHONPATH.


import datetime

def timer(text):
    print text
Jun 15

Conocían Django?

Conocían Django?

Django es un framework de desarrollo web de código abierto escrito en python, que nos permite crear aplicaciones de una manera muy rapida y sencilla. Django cumple en cierta medida el modelo MVC(Modelo Vista Controlador), y procura separar al máximo la presentación de los datos, de la lógica de la aplicación.

En lugar de requerir que los desarrolladores escriban controladores y vistas para las áreas de administración de la página, Django proporciona una aplicación incorporada para administrar los contenidos, que puede incluirse como parte de cualquier página hecha con Django y que puede administrar varias páginas hechas con Django a partir de una misma instalación; la aplicación administrativa permite la creación, actualización y eliminación de objetos de contenido, llevando un registro de todas las acciones realizadas sobre cada uno, y proporciona una interfaz para administrar los usuarios y los grupos de usuarios (incluyendo una asignación detallada de permisos). Algunas características de Django:

  • Un mapeador objeto-relacional.
  • Aplicaciones "enchufables" que pueden instalarse en cualquier página gestionada con Django.
  • Una API de base de datos robusta.
  • Un sistema incorporado de "vistas genéricas" que ahorra tener que escribir la lógica de ciertas tareas comunes.
  • Un sistema extensible de plantillas basado en etiquetas, con herencia de plantillas.
  • Un despachador de URLs basado en expresiones regulares.
  • Un sistema "middleware" para desarrollar características adicionales; por ejemplo, la distribución principal de Django incluye componentes middleware que proporcionan cacheo, compresión de la salida, normalización de URLs, protección CSRF y soporte de sesiones.
  • Soporte de internacionalización, incluyendo traducciones incorporadas de la interfaz de administración.
  • Documentación incorporada accesible a través de la aplicación administrativa (incluyendo documentación generada automáticamente de los modelos y las librerías de plantillas añadidas por las aplicaciones).
Jun 14

New Website

Después de varias semanas planeando comprar mi dominio y mi hosting, para alojar alguna aplicación en django, decidí hacer este blog y montarlo aquí, conseguí el alojamiento en webfaction y el dominio en godaddy, excelentes compañias las 2 y muy fácil de configurarlas(nunca habia tenido un dominio ni habia hosteado una app web). Y a pesar de todo no salió tan caro, solo comprar el dominio por 1 año, me costó 10 dolares, y compre en webfaction el plan más barato por 1 año, prepagado. Total, ya sumando me salieron como $1400 por tener hosting y dominio por 1 año.

Me tardé en desarrollar el diseño, porque lo hice yo, y el blog esta en django, asi que no fue muy tardado, hay muchos ejemplos en internet y es algo relativamente "fácil" de conseguir, aún le iré dando varias mejoras al blog y aquí iré posteando cosas que crea importantes destacar y comentar, más que nada para transmitir conocimientos y forzarme a investigar más sobre el tema.

Mi nombre es Luis Miguel Montiel Gómez, soy un estudiante de la carrera de Ing. en Sistemas Computacionales, actualmente trabajo como junior programmer en objectwave, y me dedico generalmente a la programacion de sistemas en java, me gusta python y actualmente estoy empezando a usarlo más que nada debido a django, mi plataforma de desarrollo es linux, ubuntu específicamente, también he desarrollado 2 plugins para gnome-do, aquí y aquí en C#, uno de YouTube y el otro para Emesene respectivamente.

Bueno pues entonces, mis posts van a ser generalmente acerca de django y python, y obviamente java, espero postear con regularidad y hacer crecer el sitio lo más que pueda.

About

A blog about myself, Luis Montiel, an IT student, currently working as junior developer for ObjectWave corp.

Subscribe

Elsewhere

Categories

Recent Posts

Archive

BlogRoll

Popular Posts

Django Popular