‘ Pami ’ category archive

PAMI: Aprendiendo DJANGO con ejemplos(3): Trabajando

February 11, 08 by Tomcask

En el ultimo post, conseguimos enviar objetos javascript via JSON a nuestro servidor, la información es serializada en la base de datos en este capitulo.

Antes de empezar, dejarme allanar el camino, el schema (estructura) de la Base de datos es modificada de esta forma:

PYTHON:
  1. class Book(models.Model):
  2.     isbn = models.CharField(maxlength=10, primary_key=True)
  3.     pub_date = models.DateField(’data published’)

La razón de este cambio la encontramos en que AWS devuelve ISBN-10 como ASIN, Podremos sacar provecho de ello, Otro cambio es la substitución de DateTimeField by DateField para el atributo pub_date. Django no soporta seamless database scheme hasta el momento. Debermos eliminar la basede datos y regenerar tal y como esta descrito. El username/password para la nueva database es admin/gelman como costumbre.

Es bastante molesto un error 500 sin ninguna razón, El servidor Web de Django se come la excepcion por naturaleza, podremos contralar el bug sospechoso con un codigo try/except como este:

PYTHON:
  1. try :
  2.           // database access
  3.     except :
  4.           print sys.exc_info()[0]

Bien, InterfaceError o IntegrityError es el error que muestra en la inserción en la Base de datos, pero porque? las shells interactives son nuestras mejores amigas, podemos usar pdb o [HTML]python manage.py shell[HTML].

Mea culpa, olvidamos que el valor de regreso de get_or_create es una tupla, en vez de un objeto, y para la relación de muchos a muchos, no nos vale simplemente con el conjunto de valores de la lista, necesitamos usar un metodo add despues de que el objeto sea contruido:

PYTHON:
  1. for item in simplejson.loads(request.POST[‘items’]):
  2.      publisher, created = Publisher.objects.get_or_create(name=item[‘publisher’])
  3.      authors = [Author.objects.get_or_create(name=au) for au in item[‘authors’]]
  4.      authors = [author for (author, created) in authors];
  5.      y,m,d = [int(x) for x in item[‘pub_date’].split(‘-’)]
  6.      pub_date = date(y, m, d)
  7.      book, created = Book.objects.get_or_create(isbn=item[‘isbn’], name=item[‘title’],
  8.        pages=300, pub_date=pub_date, publisher=publisher)
  9.      book.authors.add(*authors)
  10.     #print sys.exc_info()[0]
  11.    return HttpResponseRedirect(‘/admin/library/book/’)

Llegamos al final, debemos hacer un redirect del navegador a la nueva url.

Al parecer la base de datos esta actualizada pero la pagina no se redirije, desde que es lanzado el post en una petición AJAX, necesitamos enviar un objeto JSON como respuesta. En el servidor, simplejson.dump es usado:

PYTHON:
  1. xhr = {’succeed’: [], ‘failed’: []};
  2.     for item in simplejson.loads(request.POST[‘items’]):
  3.      # … ….
  4.      try :
  5.          book, created = Book.objects.get_or_create(isbn=item[‘isbn’], name=item[‘title’],
  6.                  pages=300, pub_date=pub_date, publisher=publisher)
  7.          book.authors.add(*authors)
  8.      except :
  9.          xhr[‘failed’].append(item[‘title’])
  10.      xhr[’succeed’].append(item[‘title’])
  11.  
  12. return HttpResponse(simplejson.dumps(xhr), mimetype=‘text/javascript’);

En el cliente, evaluaremos el string JSON que propaga los nodos del DOM.

JavaScript:
  1. dojo.xhrPost({
  2.           url: dojo.byId(“book_form”).action,
  3.           content: { items: dojo.toJson(formdata) },
  4.       }).addCallback(function(response) {
  5.           var result = dojo.fromJson(response);
  6.           var messages = dojo.query(“ul[@class=messagelist])[0]
  7.           dojo.forEach(result.failed, function(item) {
  8.               var msg = document.createElement(“li”);
  9.               msg.innerHTML = “<li><em>” + item + “</em> <strong>failed</strong> to add.</li>”
  10.               messages.appendChild(msg);
  11.       });
  12.       dojo.forEach(result.succeed, function(item) {
  13.           var msg = document.createElement(“li”);
  14.           msg.innerHTML = “<em>” + item + “</em> successfully added.”
  15.           messages.appendChild(msg);
  16.       });
  17. });

El resultado final tiene esta pinta:
Add books with feedback

check r19 para los detalles.

PAMI: Aprendiendo DJANGO con ejemplos(2): Muestrame información

February 11, 08 by Tomcask

Fuente: http://www.kunxi.org/archives/2007/09/learning-django-by-example2-show-me-your-data/

Sigo con mis traducciones sobre Django.

En el ultimo apunte, hicimos un rápido (y feo) prototipo para que Gelman funcionara. En este apunte, quiero usar XSLT para lo que necesitemos.

Si nos has probado XSLT, revisa XSLT (for dummies o la referencia oficial). XSLT es una potente herramienta, si solo te interesa la extracción de datos, deberías comparar los esfuerzos de parsear XML, con PyAWS.

Es simple y muy estúpido, desde que AWS (Amazon WebServices) soporta tanto consultas por ISBN o busquedas por Keyword, nosotros podemos combinar la entrada de dos cajas de texto como si fuera una y enviar diferentes peticiones validando el ISBN basándonos en el conocimiento de AWS. Check r12 para la implementacion, la imagen:
Add book by search

En Check r14, Intentaremos probar dojo.query como alternativa a jQuery, es muy guay referenciar a los objetos usando sintaxis CSS.

JavaScript:
  1. dojo.forEach(dojo.query(“#book_form input[@class=incoming]), function(item) {
  2.                if (item.value != “”) {
  3.                        formdata.push(cache[i]);
  4.                }
  5.                i++;
  6.      });

En el anterior fragmento de codigo, cache contiene los objetos JSON de la petición a AWS, si un fichero es adjuntado para enviar (incoming) [No termino de entenderlo, la verdad] (el upload no funciona todavía, de momento utilizaremos como marca), el meta data correspondiente es recogido en el formdata. La ultima pregunta es como enviamos esto al servidor.

JSON es soportado por ambos lados (cliente y servidor) por ejemplo dojo.json y django.utils.simplejson. En el lado del cliente, serializaremos el javascript como una cadena de texto JSON:

JavaScript:
  1. dojo.xhrPost({
  2.                 url: dojo.byId(“book_form”).action,
  3.                 content: { items: dojo.toJson(formdata) },
  4.         }).addCallback(function(response) {

Y en el lado del servidor, cargaremos los objetos Python desde la cadena de texto JSON. Check r16 para la implementación.

PYTHON:
  1. items = simplejson.loads(request.POST[‘items’])

En el próximo capitulo podríamos hablar sobre como manipular base de datos usando la django's database API

PAMI: Mejorar la usabilidad de tu web con Patrones de diseño de Interacción

February 05, 08 by Tomcask

A ver voy a colgar 2 enlaces de usabilidad que me parecen buenísimos porque te muestra ejemplos claros sobre como hacer las cosas bien en tuweb, con casos reales, razonando el porque.

Sobreentiendo que todos sabemos lo que es la Usabilidad (sino lo sabes) y que uno de sus máximos (aun teniendo detractores) es Jakob Nielsen y hemos leído el famoso articulo de "Se breve, escribir para la Web" o otros parecidos.

UI-patterns me ha gustado bastante, pero welie me ha gustado más todavia, os comento y traduzco algun articulo de UI-Patterns que me ha paracido interesante pero repito, recomiendo su lectura intensa.

La Caja de Texto con ayuda en linea, este patrón nos indica que es una muy buena solución añadir ayuda contextual a nuestras cajas de texto, indicando que es lo que debemos poner en esta en concreto, proporcionando la posibilidad de ocultarlo en el caso de que al usuario le estorbe.

 Como podemos ver en el articulo sobre este patrón nos informa sobre los diferentes usos y técnicas que se utilizan y permiten mejorar esta situación, por ejemplo:

Lo usaremos cuando nuestra interacción en el site no es necesariamente intuitiva y autoexplicatoria, deberemos tener en cuenta que el usuario no conoce el site, ni siquiera exactamente que es lo que hace  o para que sirve, por lo tando deberiamos ponerselo lo más facil posible.

Creo que los desarrolladores pecamos por defecto, por lo tanto si actuamos en exceso, probablemente esta sea la justa medida.

Lo usaremos para motivar al usuario a empezar a usar el sistema, por ejemplo a registrarse, a entrar a una demo, etc.

Introduciremos de una manera suave a las fucionalidades (nuevas o antiguas) a un usuario nuevo o inexperto en el uso de internet.

Usaremos también la funcionalidad de ocultar estos mensajes para evitar la frustración del usuario experimentado.
Os aconsejo revisar el articulo, bueno el website entero.

Logo welie

Para el final el mejor a mi opinión, Welie Libreria de patrones de Diseño de Interacción.

A Pattern Library for Interaction Design

This site contains a lot of best practices in Interaction Design. Over the years I have collected examples and insight on their applicability that I share with you here on this site.

Este sitio contiene muchas de las mejores practicas en Diseño de Intereacción, A lo largo de los años he ido almacenando ejemplos y comentado acerca de su aplicabilidad, y lo comparto con vosotros en este site.

Navegación principal este patrón es de los mas útiles para estudiarse y repasarse, los usuarios necesitan saber donde pueden encontrar lo que buscan.

Pon siempre en un lugar visible y fijo, el menú de la pagina. Apóyate del menú principal con herramientas adicionales de navegación. El articulo habla sobre las formas para hacerlo y los diferentes posibilidades, es un recurso súper interesante.

Os vuelvo a recomendar su lectura intensa, me encanta su clasificación de patrones, y su esquema en cada articulo de Problema, Solución, Cuando usar, Com, Porque, Ejemplos, Implementación, Lecturas, repito es super completo.

Categorias de welie

En las categorías podemos encontrar, patrones de elementos de navegación, búsqueda en el website, Compras, Modificación de información, etc.

Pero cuando hablamos de  usabilidad seria injusto no hablar de usalo.

 Uno de las fuentes de referencia en español que utilizo sobre usabilidad en sitios web, os recomiendo sus articulos de:

PAMI: Aprendiendo Django con Ejemplos (1): Arrancando.

February 04, 08 by Tomcask

Fuente: Learning Django by example 1 start the engine

Hecho en falta Tutoriales de Django en Castellano, si alguien encuentra, que avise

Aquí va mi aportación en traducción a mi manera (se agradecen correcciones).

Otro tutorial más de Django, con un par de diferencias:
* El autor es totalmente novato acerca la programación en Django.
* Cada paso esta cuidadosamente guardado con Google Code , podrás bajarte la última versión para entender cómo evoluciona el proyecto.

Pensando a lo Grande

Realmente adoro la intuitiva interfaz de Delicious Library, - creo que no tiene nada que ver con Del.icio.us -. Lamentablemente es solo para Mac, y no creo que se pueda escalar debido a la falta de un servidor de base de datos.

He decidido hacer Gelman que será la librería de cosas chulas.

Escogí Django por el Bombo “python on rail“, solo necesitaba un ligero framework web en python - Django no es de lo más ligeros – Ojala pueda disfrutar con el proceso de desarrollo.

En el siguiente tutorial quisiera mostrar el código en cada paso cuando mencione “check r#”, puedes hacer el checkout:

HTML:
  1. svn checkout http://gelman.googlecode.com/svn/trunk/gelman -r3 gelman

En este caso # es 3. Si google soportara Trac esto sería mucho más fácil.

Arrancando

‘Aquí instalamos Django tenemos múltiples tutoriales para ello, no lo voy a repetir otra vez, el autor usa SqlLite3 por simplicidad, comenta que en producción migrara a MySql’ “check r5”.

Después añadimos la aplicación library:

HTML:
  1. python manage.py startapp library

Gelman está diseñado como un ligero gestor de ebooks, con especial atención en la reutilización de componentes y uso de web services. Por ejemplo el metadata es com Amazon Web Service AWS, la etiqueta sugerida viene de Yahoo.

Solo la información esencial es almacenada localmente, como la cartografía entre la metadata y el ebook. Los siguientes modelos, Author, Publisher, y Books se han añadido.

PYTHON:
  1. class Book(models.Model):
  2.     isbn13 = models.CharField(maxlength=13, primary_key=True)
  3.     name = models.CharField(maxlength=255)
  4.     authors = models.ManyToManyField(Author)
  5.     pages = models.IntegerField()
  6.     publisher = models.ForeignKey(Publisher)
  7.     pub_date = models.DateTimeField(‘data published’)

ISBN-13 es el ultimo estándar, añadiremos ISBN-10 mas tarde si es necesario, Author y Book tienen una relación Muchos a Muchos, usaremos models.ManyToManyField como se sugiere aquí

Finalmente hacemos:
- Añadimos Django.contrib.admin en INSTALLED_APPS setting
- Sincronizamos el cambio en la BD “sinc”
- Editamos el fichero urls.py para activar la admin page.

Ahora podemos autentificarnos en http://localhost:8000/admin usamos “Bookstack” y “gelman” como Usuario y Password. Check r7

En principio, los libros se añaden manualmente para las pruebas, deberos automatizar este tedioso procedimiento mas tarde. Tener en cuenta la relación entre “Libro” y “Publicador”, esto es realmente guay que la administración nos ayude a relacionar los modelos.

Aprendiendo Django con Ejemplos 1- add book

Añadimos una línea a urls.py para activar la interface de usuario para los usarios normales.

HTML:
  1. (r‘^library/(?P<isbn>\d+)/$’, ‘gelman.library.views.detail’),

Añadimos a detail.html en “Template/books” como una vista de template, no olvides añadirla en TEMPLATE_DIRS en settings.py, Implementamos detail in “library/views.py”:

PYTHON:
  1. def detail(request, isbn):
  2.     book = get_object_or_404(Book, isbn13=isbn)
  3.     return render_to_response(‘books/detail.html’, {‘book’: book})

Ahora podemos acceder a la información en “Http://localhost:8000/library/9780596009250/”, esto solo es un aburrido texto que redefiniremos mas tarde. Check r8.

Haciendo feliz al bibliotecario.

En una biblioteca real, el usuario puede navegar, buscar, pedir prestado, devolver libros, pero solo el bibliotecario gestiona la colección, es menos divertido escribir toda la “meta data” del libro mientras nosotros la podemos obtener de Amazon.

Un Bibliotecario utilizar un lector de código de barras, preferimos el titulo o palabra clave que el aburrido numero de 13 dígitos (ISBN).

Vamos a utilizar Ajax, con The Dojo Javascript Toolkit puedes bajarte la versión dojo-1.0.2 obteniendo las completas ventajas de AOL’S CDN.

Como servir ficheros estáticos es probablemente la pregunta más frecuente en #django desde la URLConf basado en expresiones regulares más o menos sobre destructivas.

HTML:
  1. (r‘^static/(?P<path>.*)$’, ‘django.views.static.serve’, {‘document_root’: ‘/home/bookstack/projects/media’}),

Preparamos el fichero correctamente:

HTML:
  1. cd /home/bookstack/projects/media;
  2. mkdir scripts
  3. sudo mount -o bind $DOJO_ROOT/trunk scripts

Ahora http://localhost:8000/static/scripts/dojo/dojo.js es donde apunta la librería de dojo

Consideramos que los usuarios introducen el guión el espacio de ISBN, necesitaremos anular la “maxlength” por defecto del atributo ISBN13 and añadir una validación para ISBN usando javascript:

JavaScript:
  1. dojo.addOnLoad(function() {
  2.             var p = dojo.byId(“id_isbn13″);
  3.             var n = document.createElement(“div”)
  4.             p.parentNode.appendChild(n);
  5.  
  6.             dojo.connect(p, ‘onblur’, function() {
  7.                 if(isValidISBN(p.value)) {
  8.                     n.innerHTML = “<div>Searching…</div>”
  9.                 } else {
  10.                     n.innerHTML = “<div>Invalid ISBN</div>”
  11.                 }
  12.             });
  13.             p.removeAttribute(“maxlength”);
  14.         });

NOTA: IsValidISBN se fusiona dentro dojox.validatie.isbn, renombrado como djox.validate.isValidsbn. Esto es uno de beneficiós de usar dojo SVN.

Esto es una buena oportunidad para personalizar la pagina de admin, una nueva template add.html es añadida:

HTML:
  1. {% block content %}
  2.         <div id=“content-main”>
  3.         <h1>Add Book<h1>
  4.             <input type=“textid=“id_isbn13″ class=“vTextField” name=“isbn13″ size=“30value=“”/>
  5.             <input type=“button” id=“search_isbn” value=“Search ISBN” />
  6.             <div id=“isbn_valid”></div>
  7.             <input type=“textid=“id_title” class=“vTextField” name=“titlesize=“30value=“”/>
  8.             <input type=“button” id=“search_title” value=“Search Title”/>
  9.             <form action=“” method=“post” id=“book_form”> <div>
  10.                 <fieldset class=“module aligned ()id=“books”>
  11.                 <div class=“form-row” id=“firstrow”> No book found
  12.                 </div>
  13.                 </fieldset>
  14.                     <div class=“submit-row”>
  15.                         <input type=“submit” value=“Save and add another” name=“_addanother”  />
  16.                         <input type=“submit” value=“Save and continue editing” name=“_continue” />
  17.                         <input type=“submit” value=“Save” class=“default” />
  18.                     </div>
  19.  
  20.             </div></form>
  21.         </div>
  22. {% endblock %}

Si usamos XmlHttpRequest, tendremos que parsear y crear un proxy para interpretar el aburrido xml, nada de esto es agradable. La interface de AWS's JSONP viene al rescate, en Dojo 0.9, dojo.io.script.get substituye la magica dojo.io.bind con sintasis TWisted , esto es todavia mas agradable.

JavaScript:
  1. dojo.connect(searchISBN, ‘onclick’, function() {
  2.         dojo.io.script.get({
  3.             url: ‘http://xml-us.amznxslt.com/onca/xml’,
  4.             content: {
  5.                 Service: ‘AWSECommerceService’,
  6.                 SubscriptionId: ‘19267494ZR5A8E2CGPR2′,
  7.                 AssociateTag: ‘kokogiak7-20′,
  8.                 Operation: ‘ItemLookup’,
  9.                 Style: ‘http://kokogiak.com/amazon/JSON/ajsonSingleAsin.xsl’,
  10.                 ContentType: ‘text/javascript’,
  11.                 IdType: ‘ISBN’,
  12.                 ResponseGroup: ‘Medium’,
  13.                 SearchIndex: ‘Books’,
  14.                 ItemId: isbn.value,
  15.             },
  16.             callbackParamName: “CallBack”
  17.             }).addCallback(function(response) {
  18.                 var item = response.Item;
  19.                 var row = dojo.byId(“firstrow”);
  20.                 row.textContent = null;
  21.                 var node = document.createElement(“div”);
  22.                 node.innerHTML = ‘<div> <img src="’ + item.thumburl + ‘"/> ‘ + item.title;
  23.                 row.appendChild(node);
  24.             });
  25.     });

Nota: Todos los parametros son case-Sensitive, especialmente CALLBACK para "callbackParamName" Oh olvidaba añadirlo al repositorio, check r11 para la ultima versión, continuaremos en el capitulo 2 (Pendiente de traducir)

El codigo anterior es una idea dojoized de Kokogiak's, y usaremos us ajsonSingleAsin.xsl para pequeños prototipos, que desarollamos en XSLT para los requerimientos del capitulo siguiente.

Aprendiendo Django con Ejemplos 1 - add book by ISBN