Snippet para incluir el token CSRF en todas las plantillas Django

Django 1.2 tiene por defecto protección CSRF, que si quieres usarla (en
admin por ejemplo es obligatorio), debes incluir un token CSRF en las
plantillas, tal que así:

{% csrf_token %} {{ form }}

Pues bien, hay un snippet para ejecutar un comando que te lo inserte en
todas las plantillas que tengan formularios:

http://charlesleifer.com/blog/quick-shell-command-add-csrf-token/

django-nonrel: Django ORM en bases de datos no relacionales

django-nonrel es un fork de Django cuyo fin es dar soporte a bases de datos no relacionales (como App Engine, mongodb, couchdb, Tokio Cabinet, hypertable, etc.). Actualmente sólo tiene implementado el backend App Engine.

Aquí el artículo que explica el estado del proyecto y como instalarlo:

http://www.allbuttonspressed.com/blog/django/2010/01/Native-Django-on-App-Engine

Para terminar, para aquellos que se quieran adentrar en probar a programar con el ORM de Django en bases de datos no relacionales, aquí explican 4 tips principales que hay que tener en cuenta:

http://www.allbuttonspressed.com/blog/django/2010/02/4-things-to-know-for-NoS... Lo más interesante es que, aunque las bases de datos no relacionales no permiten el uso de JOINs (hay que hacer un "join" de forma programática, con el aumento de complejidad del código que supone), los de django-nonrel van a incluirlo en el backend para que se haga transparentemente al desarrollador.

Natural keys en Django 1.2

Las fixtures de Django son una forma muy cómoda de disponer de datos en formatos legibles por humanos e independientes de la base de datos que se utilice. Son fáciles de crear y de cargar, pero tienen varios inconvenientes. En Django 1.2 se ha solucionado uno de sus mayores problemas: cuando las fixtures dejan de ser válidas porque hay referencias a instancias con claves primarias que cambian respecto de lo que indican las fixtures.

Un caso típico es que se crean fixtures de un proyecto, y algunos modelos de datos hacen referencia a ContentType (django.contrib.contentype.models.ContentType). Django genera dinámicamente un ContentType por cada modelo de datos existente en un proyecto al ejecutar syncdb, pero las claves primarias de los ContentType pueden ser (y serán) diferentes a medida que se crean y eliminan modelos en el proyecto. Por tanto las fixtures creadas en una instantánea del proyecto probablemente deje de funcionar en el futuro porque habrá referencias erróneas a los ContentType.

La solución incluida en Django 1.2 son las "natural keys" (claves naturales de ahora en adelante). La idea es, en vez de referenciar esas instancias por su clave primaria

"content_type": 37

usamos un conjunto de atributos que identifica unívocamente una instancia:

"content_type": ["library", "book"]

En el caso de ContentType su clave natural está compuesta de la aplicación ("library") y el modelo de datos ("book").

Las claves naturales no son algo exclusivo de ContentType, sino que pueden incluirse en cualquier modelo de datos, simplemente añadiendo un método get_natural_key() al modelo y otro método get_by_natural_key() a su manager. Por ejemplo:

Claves naturales en la documentación de Django: http://docs.djangoproject.com/en/dev/topics/serialization/#natural-keys

Declarative definition of widgets in a ModelForm

Say goodbye to the previous and tedious way to define a widget in a model form:

class FooForm(forms.ModelForm):
     def __init__(self, *args, **kwargs):
         super(FooForm, self).__init__(*args, **kwargs)
         self.fields['description'].widget = Textarea(attrs={'cols': 80,
'rows': 20})

Now, after [12194] commit is easier and cleaner, without having to redefine the __init__ method:

class FooForm(forms.ModelForm):
     class Meta:
         widgets = {
              'description': Textarea(attrs={'cols': 80, 'rows': 20}),
         }

Optimizando consultas M2M con django-batch-select

Es una idea original para evitarnos consultas innecesarias cuando
queremos, para una lista de objetos, sacar una lista de propiedades del
mismo (definidas como un atributo m2m del objeto).

Lo explica muy bien aquí:

   http://github.com/lilspikey/django-batch-select

Voy a resumirlo en español y ejemplificando un caso de uso posible.
Supongamos estos modelos:

class Image(models.Model):
    modification_date = models.DateTimeField(...)
    ...

class Artist(models.Model):
    name = models.CharField(...)
    images = models.ManyToManyField(Image)

Supongamos que queremos el típico listado de artistas (paginado de N en
N) con las últimas imágenes de cada uno, todo en la misma página. Como
sabéis, un Artist.objects.all().select_related() no sigue los m2m (ver razón),
con lo que nunca se hará JOIN con Image a menos que se realice a mano
con un extra(tables=...). Esto implica que o lo hacemos a mano o se
ejecutarán N*2 consultas (donde N es el tamaño de la paginación).

Pues bien, con django-batch-select se reducirían las consultas a 2, sea
cual sea el tamaño de página, con una secuencia como la que sigue (ojo,
código no probado):

>>> artists = Artist.objects.batch_select('images').all()
>>> artists[0].images_all # imagenes del primer artista
[<Image image object>, ...]

Esto realiza estos dos selects:

SELECT * FROM app_artist; # guardando los ids en python, p.ej. (1, 3, 5)
SELECT * FROM app_image JOIN app_artist_image ON (app_image.id =
app_artist_image.image_id) WHERE artist_id in (1, 3, 5)

Pero como algún perspicaz habrá adivinado, esto no devuelve las últimas
fotos del artista, sino todas, y sin ordenación. Podemos realizarlo de
la siguiente forma:

>>> batch = Batch('images').order_by('-modification_date')[:5]
>>> artists = Artist.objects.batch_select(batch).all()

O cambiar el descriptor:

>>> artists = Artist.objects.batch_select(last_images=batch).all()
>>> artists[0].last_images
[<Image image object>, ...]

La verdad es que una cosa así bien merece la pena integrarla en el
BaseManager de merengue, para posibles usos futuros.

Multiples Bases de datos en Django ya apuntito

En la rama de código multidb se está terminando de implementar la
posibilidad de conectar múltiples bases de datos.

Por la pinta que tiene el movimiento en el SVN, donde ya están limpiando
ficheros y haciendo los últimos merges de trunk/ a multidb/, parece que
se acerca el merge contrario, es decir, de multidb/ a trunk/.

Aunque aún podemos usar la forma clásica (hasta la versión 1.4, donde se
proclamaría incompatible hacia atrás), vamos a introducir un poco como
sería...

El settings cambiaría de los parámetros DATABASE_* al siguiente:

DATABASES = {
    'default': {
       'NAME': 'foodb',
       'BACKEND': 'django.db.backends.postgresl_psycopg2',
       'HOST': 'masterdb.foodb.com',
    }
    'slave1': {
       'NAME': 'foodb',
       'BACKEND': 'django.db.backends.postgresl_psycopg2',
       'HOST': 'slavedb1.foodb.com',
    }
}

Las consultas serían de este estilo:

>>> qs1 = FooModel.objects.all() # el de siempre
>>> qs2 = FooModel.objects.filter(status='published').using('slave1') #
usando la base de datos secundaria

Las manipulaciones serían así:

>>> content.save() # guarda en "default"
>>> content.save(using='slave1')
>>> content.delete(using='slave1')


Para más información:

http://code.djangoproject.com/browser/django/branches/soc2009/multidb/docs/to...

Django con soporte de múltiples bases de datos bastante avanzado

El código se puede ver aquí:

 http://github.com/alex/django/tree/multiple-db

 En principio, para resumir, si tienes un cluster de dos máquinas, puedes
definirlo así:

 DATABASES = {
  'c1': {
  DATABASE_ENGINE = 'postgresql_psycopg2',
  DATABASE_NAME = 'merengue',
  DATABASE_HOST = '192.168.1.5',
  },
  'c2': {
  DATABASE_ENGINE = 'mysql',
  DATABASE_NAME = 'merengue',
  DATABASE_HOST = '192.168.1.6',
  },
}

 Con esto se puede hacer sharding de datos, por usuarios por ejemplo, y
que por tanto hacer las consultas del usuario X en c1 y del usuario Y en
c2.

 Ejemplos de uso podrían ser:

 >>> product = Product.objects.using('c1').get(id=1)
>>> product.name = 'Mi nombre'
>>> product.save(using='c1')

  
Hay un hilo donde habla del estado actual:

 http://groups.google.com/group/django-developers/browse_thread/thread/267a2fd...

  
Saludos.