sábado, 29 de noviembre de 2008

Generando formularios de modelos en Django

Es muy fácil generar formularios basándonos en los datos definidos en un modelo (esto está ampliamente documentado en el sitio de Django, excepto:
1) cómo setear los ítems que debe contener el SELECT correspondiente a un campo ForeignKey
2) cómo cambiar el nombre del campo que debe aparecer en el formulario autogenerado

(marqué en rojo la manera que encontré para resolver estas 2 cuestiones).

Modelo:

from django.db import models
from django.contrib.auth.models import User

class Proyecto(models.Model):
name = models.CharField(max_length=256, verbose_name="Nombre")
customer = models.ForeignKey(to=User, verbose_name="Cliente")


Formulario:

from django import forms

class ProyectoForm(forms.ModelForm):

class Meta:
model = Proyecto
fields = ('name', 'customer')


Vista:

    if request.POST:
form = ProyectoForm(request.POST)
else:
form = ProyectoForm()

form.fields['customer'].queryset = User.objects.all().reverse()

jueves, 20 de noviembre de 2008

martes, 18 de noviembre de 2008

Como backupear usuarios y grupos de PostgreSql

Respuesta:

pg_dumpall --globals-only


(también backupea tablespaces)

Artículo original y respuestas más largas: Backing up Login Roles aka Users and Group Roles

sábado, 15 de noviembre de 2008

Ejemplo de mod_deflate

Comprimir contenidos con mod_deflate es mucho más fácil que con mod_gzip:

<ifmodule mod_deflate.c>
SetOutputFilter DEFLATE
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/javascript application/x-javascript text/css
DeflateFilterNote Input instream
DeflateFilterNote Output outstream
DeflateFilterNote Ratio ratio
LogFormat '"%r" %{outstream}n/%{instream}n (%{ratio}n%%)' common_deflate_log
CustomLog logs/xyz.dynamicware.com.ar-mod_deflate.log common_deflate_log
</ifmodule>


Con las 2 primeras líneas ya alcanza. Las demás líneas son para loguear en un archivo información estadística sobre la compresión. Por ejemplo:

"GET /resources/virtualdisk-default.css HTTP/1.1" 1077/4041 (26%)
"GET /resources/static/back-body.gif HTTP/1.1" 44/52 (84%)
"GET /resources/static/back01.jpg HTTP/1.1" 138938/139402 (99%)

Optimización de sitios

Puede optimizarse considerablemente un sistema web que estoy utilizando a través de la configuración del tiempo de expiración de los archivos servidos. Esto lo hice organizando todos los archivos que no cambian nunca (javascripts de prototype y jquery, algunos logos, etc). Los ubique en el directorio /resources/static, y luego configure en Apache:

<directory /xxxxxxx/templates/resources/>
ExpiresActive On
ExpiresDefault "now plus 2 month"
</directory>

Esto hace que el servidor Apache le envíe al navegador información para que guarde en su caché estos archivos por más de 2 meses. Los demás recursos que pueden cambiar (como los estilos desarrollados por mi y algunos javascripts) los ubiqué en /resources, así evito que sean cacheados por tanto tiempo.

Antes:




Después:



Para estas tareas de optimización, Firefox e YSlow son grandes aliados. Por ejemplo, en el último gráfico, a la izquierda, vemos que del total de bytes bajados, la mitad corresponden a "CSS images", lo que nos da información valiosa para saber por dónde empezar para optimizar más aún nuestro sitio (en este caso se debe a una imagen muy grande usada como background).

viernes, 14 de noviembre de 2008

Ejemplo de mod_gzip de Apache + JBoss

Un ejemplo de configuración de mod_gzip. Dos problemas con los que me topé mientras lo configuraba:

- Hacerlo funcionar con contenido tomado de un servidor JBoss vía AJP: para esto debemos utilizar:

mod_gzip_item_include handler ^jakarta-servlet

- Algunos contenidos no se comprimian, aunque parecía estar todo bien configurado: esto es debido a que la expresión regular configurada era:

^text/html$

y debía ser:

^text/html

porque los encabezados suelen incluir información de encoding, por ejemplo:

text/plain; charset=us-ascii



Ejemplo completo

<ifmodule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_can_negotiate No
mod_gzip_dechunk Yes
mod_gzip_handle_methods GET POST

# 512k
mod_gzip_maximum_file_size 524288

# 200k
mod_gzip_maximum_inmem_size 204800

mod_gzip_item_include handler ^jakarta-servlet
mod_gzip_item_include file \.html$

# Si usamos ^text/html$ (con $ al final) entonces estaremos excluyendo
# los mime que incluyen el encoding (utf8, etc) junto a text/html
mod_gzip_item_include mime ^text/html
mod_gzip_item_include mime ^text/plain
mod_gzip_item_include mime ^text/javascript
mod_gzip_item_include mime ^text/css
mod_gzip_item_include uri ^/intranet/app
mod_gzip_item_exclude mime ^image/
</ifmodule>

Minimización de JS

Buscando algún servicio online para minimizar JS, encontré una librería, creada por el proyecto Dojo que se puede bajar. Está hecho en Java y son sólo 2 jars.

http://dojotoolkit.org/docs/shrinksafe

Hay que bjajar js.jar y shrinksafe.jar y ejecutar:

java -cp js.jar -jar shrinksafe.jar archivo.js > archivo-minimizado.js

jueves, 13 de noviembre de 2008

viernes, 7 de noviembre de 2008

Arranque de proyecto Django

Un par de cositas que me han ayudado como "buenas prácticas" en proyectos Django:

Estructura de directorio
Crear una estructura de directorios que contenga Django, los fuentes y templates:
  • /src
  • /templates
  • /Django-1.0

Path a instalación de Django

Configurar manage.py para que se agregue al path la instalación de Django:

import sys, os

sys.path.append(os.path.abspath(
os.path.join(
os.path.dirname(__file__), '..', '..', 'Django-1.0')))

sys.path.append(os.path.abspath(
os.path.join(
os.path.dirname(__file__), '..')))


Logging
Setear logging por consola en nivel debug, cuando DEBUG está activado, agregando las siguientes líneas en settings.py:

if DEBUG:
import logging
logging.basicConfig(
level = logging.DEBUG,
format = '%(asctime)s %(levelname)s %(message)s',
)
También sería prudente configurarlo en nivel warning cuando DEBUG no está seteado:

else:
import logging
logging.basicConfig(
level = logging.WARN,
format = '%(asctime)s %(levelname)s %(message)s',
)



Path a templates

Se puede agregar automaticamente a 'TEMPLATE_DIRS' nuestro directorio de templtates modificando settings.py de manera que quede:

tmp_template_dir = [
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
]

try:
import os
auto_dir = os.environ['AUTO_TEMPLATE_DIR']
tmp_template_dir.append(auto_dir)
except KeyError:
pass

TEMPLATE_DIRS = tuple(tmp_template_dir)

Y en manage.py:

os.environ['AUTO_TEMPLATE_DIR']=
os.path.abspath(os.path.join(
os.path.dirname(__file__), '../../templates'))

OJO que los pedazos de código Python que copié y pegué quedaron mal indentados... aún cuando le agregué los <pre> necesarios en el HTML...

domingo, 2 de noviembre de 2008

Java theory and practice: Are all stateful Web applications broken?

Java theory and practice: Are all stateful Web applications broken?
HttpSession and friends are trickier than they look

The session state management mechanism provided by the Servlets framework, HttpSession, makes it easy to create stateful applications, but it is also quite easy to misuse. Many Web applications that use HttpSession for mutable data (such as JavaBeans classes) do so with insufficient coordination, exposing themselves to a host of potential concurrency hazards.

Link





Templates de Django desde la BD

Encontré un proyecto que parece implementar la funcionalidad necesaria para que Django pueda tomar los templates desde una base de datos. Aunque no lo probé parece estable...

http://code.google.com/p/django-dbtemplates/

Introduction to Python/Django testing: Doctests

Nota: copié todo el artículo porque el link al post original no me funcionó... (este es el link original)

Eric Holscher: Introduction to Python/Django testing: Doctests

This is the first in a series of blog posts and screencasts that will walk you through how to test your Django application. These posts will focus more on how to get things done in Django, but note that a lot of the content is applicable to pure python as well. A lot of best practices are codified into Django's testing framework, so that we don't have to worry about them! I will try to point them out as we are using them through, because they are good things to know.

The currently planned structure for this series is below. Please comment if there is something that you think is missing, or something that I shouldn't do. This is subject to change, a lot, as well, so your feedback will help direct it. Also note that most or all of this content is available in the Django and Python documentation, and I will try and point there and not re-invent the wheel. I hope that these posts will take a more practical look, and try to point out some pit falls and other things that are useful.

Outline

  • Basic Doc tests
  • Basic Unit tests
  • Comparison of Unit tests vs. Doc test
  • Fixtures
  • Using Mock objects
  • Third party testing tools
  • Writing your own test runner
  • Getting code coverage for your tests

Where to start

I'm assuming that you already have a project that you're working on that you would like to test. There are two different ways of putting tests inside of your django project. You can add a tests.py file and put your tests inside of there. You can also define a tests/ directory and put your tests in files inside of that. For these tutorials it is assumed that the second is the way things are done. It makes it a lot easier when you can break your tests out into logical files.

Doctests

These can go in two places inside your django project. You can put them in your models.py file, in the Docstring for your modules. This is a good way to show usage of your models, and to provide basic testing. The official docs have some great examples of this.

The other place your Doctests can go is inside your tests directory. A doctests file is usually pretty simple. A doctest is just a large string, so there isn't much else to put besides a string. Usually you want to use the triple quote, multi-line string delimiter to define them. That way your " and 's inside of your doctests don't break anything.

"""
This is my worthless test.
>>> print "wee"
wee
>>> print False
False
"""

You can go ahead and put that in a file in your tests/ directory, I named it doctst. My application that I'm writing tests for is mine, because it's the code for my website. Make sure that directory has an __init__.py as well, to signify that it is a python module.

Now here is the tricky part; go ahead and try and run your test suite. In your project directory run ./manage.py test APPNAME. It will show you that you have passed 0 tests. 0 tests? We just defined one.

You need to go into your init.py file and put some stuff in there.

import doctst
__test__ = {
'Doctest': doctst
}

You are importing the doc test module and then adding it to the __test__ dictionary. You have to do this because of the way that python handles looking for doc tests. It looks for a __test__ dictionary inside of your module, and if that exists it looks through it, executing all docstrings as doctests. For more information look at the Python docs.

Now you should be able to go ahead and run the tests and see the magical Ran 1 test in 0.003s OK that all testers live for. This is little bit of overhead really threw me off when I was trying to break my tests.py out into the tests/ directory.

So now we have a test suite that is worthless, but you know how to use doc tests. If you didn't notice, the doctest format is simply the output of your default python shell, so when you are testing your code on the command line and it works, you can simple copy and paste it into your tests. This makes writing doc tests almost trivial. Note however, that they are somewhat fragile, and shouldn't be used for everything. In the next segment, we will talk about unit tests. Then we will compare the two and see when you should use each.

jueves, 16 de octubre de 2008

Como cambiar lista de opciones en un ModelForm

# Model
class Branch(models.Model):
nombre = models.CharField(max_length=32)
archivado = models.BooleanField()

# Model
class SolicitudPP(models.Model):
branch = models.ForeignKey(Branch)

# ModelForm
class SolicitudPPForm(ModelForm):
class Meta:
model = SolicitudPP

# Como cambiar lista de "branches" a mostrar:
f = SolicitudPPForm()
f.fields['branch'].queryset = Branch.objects.filter(archivado=False)


Artículo original: http://oebfare.com/blog/2008/feb/23/changing-modelchoicefield-queryset/

sábado, 30 de agosto de 2008

FindBugs, Hudson, Groovy y errores de alta prioridad

Usando Groovy encontré una manera fácil de forzar el fallo de un "build" cuando FindBugs haya encontrado problemas con prioridad alta. Este script Groovy puede agregarse en un scritp Ant o como un ultimo paso dentro de un proyecto Hudson. Esto es necesario porque el plugin de Findbugs para Hudson (en la versión estable) no se puede configurar para que marque el build como inestable dependiendo de la cantidad de warnings de ALTA prioridad (aunque esto ya está en desarrollo, e implementado en HEAD).

Usando Groovy + XPath:


import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.*

content = new File("ant_build/findbugs/findbugs-report.xml").getText("UTF-8")

builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
doc = builder.parse(new ByteArrayInputStream(content.bytes))
xpath = '/BugCollection/BugInstance[@priority="1"]'
expr = XPathFactory.newInstance().newXPath().compile(xpath)
nodes = expr.evaluate(doc, XPathConstants.NODESET)
if(nodes.length>0) {
throw new RuntimeException("FindBugs reporto ${nodes.length} warning(s) de prioridad ALTA")
}


Usando GPath es mucho más fácil:


def bugCollection = new XmlParser().parseText(content)
highPriorityBugs = bugCollection.BugInstance.findAll { it['@priority'] == '1' }
if(highPriorityBugs.size()>0) {
throw new RuntimeException("FindBugs reporto ${highPriorityBugs.size()} warning(s) de prioridad ALTA")
}


El 'target' de Ant puede definirse así:


<target name="groovy">
<taskdef name="groovy" classname="org.codehaus.groovy.ant.Groovy">
<classpath>
<fileset dir="lib/groovy">
<include name="*.jar"></include>
</fileset>
</classpath>
<groovy>
<!--[CDATA[ // SCRIPT GROOVY AQUI ]]-->
</groovy>
</taskdef>
</target>

.

lunes, 18 de agosto de 2008

Tuning Your PostgreSQL Server

Encontré un artículo con buenas referencias, con información para afinar la configuración de PostgreSql.

http://wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server

sábado, 3 de mayo de 2008

Relaciones (1:1, 1:n: m:n) con AppEngine

Encontré un link donde se explican las distintas formas de relacionar entidades. Está muy simple y describe los pro y contras de cada opción.
http://daily.profeth.de/2008/04/er-modeling-with-google-app-engine.html

jueves, 6 de marzo de 2008

Salto de páginas con OpenOffice

En la página de OpenOffice están las instrucciones para incorporar una carátula a un documento, pero de forma tal que NO afecte a la numeración de nuestras páginas.

http://wiki.services.openoffice.org/wiki/Documentation/OOoAuthors_User_Manual/Writer_Guide/Numbering_pages

lunes, 11 de febrero de 2008

Limpieza de paquetes de Ubuntu / Debian

Buscando algunos consejos para limpiar mi instalación de Ubuntu 7.10 (luego de hacer el upgrade desde 7.04) encontré http://www.tuxapuntes.com/tux/content/view/416/122/.

En resumen, el comando más útil para esta tarea es deborphan. Por ejemplo, para limpiar los archivos de configuración de paquetes eliminados podemos usar:

deborphan --find-config | xargs -r aptitude -y purge

Para ver la información de los paquetes que purgaríamos con el comando anterior, podemos usar:

deborphan --find-config | xargs -r dpkg -l

El comando deborphan posee varias opciones más de "busqueda" de paquetes ('deborphan --help' las lista)

jueves, 7 de febrero de 2008

Herramientas de testing para Python

Encontré un link muy bueno con una listado bastante extenso de las herramientas existentes para realizar el testing de programas desarrollados con Python.

http://pycheesecake.org/wiki/PythonTestingToolsTaxonomy

lunes, 7 de enero de 2008

Cheat sheet de PostgreSql

Encontré 2 páginas con "cheat sheets" de PostgreSql (no sé cuál sería la traducción de "cheat sheets", quizá "machetes", pero para lo que no saben: son resúmenes sobre lenguajes, programas, etc. con información normalmente usada de referencia cuando no nos acordamos cómo especificar ciertas cosas).
Estas "cheat sheets" las bajé de aqui y aqui.

StaticGenerator para aplicaciones Django

Esta herramienta convierte un sitio dinámico desarrollando de Django en un conjunto de HTMLs listos para servir. Es una forma muy común de mejorar significativamente la performance de un sitio. Es distribuido bajo la licencia MIT. http://superjared.com/projects/static-generator/

En el sitio declaran que se puede mejorar la performance de 500 request por segundo a 7000 req/s:

  • mod_python, no caching: 100 req/s
  • mod_python, memcached: 500 req/s
  • StaticGenerator file: 7,000 req/s