Django es el entorno de desarrollo web para perfeccionistas con límites de tiempo

Entradas sobre "trucos":

Modificar la QuerySet de un ModelChoiceField dinámicamente

El campo de formulario ModelChoiceField sirve para permitir la selección de un elemento entre los objetos resultantes de una QuerySet. La QuerySet inicial puede definirse en el propio campo del formulario. Un ejemplo de uso en nuestro forms.py sería:

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

class MiFormulario(forms.Form):
    usuario = forms.ModelChoiceField(queryset=User.objects.all())

En este ejemplo nuestro formulario tiene un campo usuario que permite seleccionar un usuario entre todos los registrados. Sin embargo a veces necesitamos que la QuerySet sea distinta de la predefinida en el formulario. Vamos a ver cómo definir la QuerySet dinámicamente al crear un objeto de formulario.

Para definirla dinámicamente primero cambiamos la QuerySet inicial por una QuerySet vacía. El campo ModelChoiceField espera que le pasemos una QuerySet pero aún no sabemos qué QuerySet queremos ejecutar (la generaremos dinámicamente al crear cada objeto de formulario) por lo que primero usamos el método none() que devuelve una lista vacía:

usuario = forms.ModelChoiceField(queryset=User.objects.none())

A continuación sobreescribimos el método __init__ del formulario para poder definir la QuerySet dinámicamente cuando se crea un formulario. Imaginemos que queremos crear una vista que contenga el formulario y que permita seleccionar cualquier usuario que no sea staff. Sin embargo si un superusuario accede a la vista queremos permitirle seleccionar cualquier usuario (incluyendo los que forman parte del staff). Éste es un ejemplo donde necesitamos definir la QuerySet en el momento de crear el formulario:

class MiFormulario(forms.Form):
    usuario = forms.ModelChoiceField(queryset=User.objects.none())

    def __init__(self, user, *args, **kwargs):
        super(MiFormulario, self).__init__(*args, **kwargs)

        if user.is_superuser:
            self.fields['usuario'].queryset = User.objects.all()
        else:
            self.fields['usuario'].queryset = User.objects.filter(is_staff=False)

Como podemos ver, el método __init__ recibe un parámetro user. Si el usuario que recibe es superusuario el campo ModelChoiceField del formulario se construirá con la lista de todos los usuarios. De lo contrario se construirá con la lista de usuarios que no forman parte del staff del sitio web. Al crear el formulario en nuestra vista pasaremos request.user al formulario para que se construya con la QuerySet adecuada en función del usuario activo:

from forms import MiFormulario

def mi_vista(request):
    mi_form = MiFormulario(user=request.user)
    # ...

¡Listo! La QuerySet del campo usuario será una u otra en función de si el usuario que accede a la vista es superusuario o no. Hemos construído la QuerySet de un ModelChoiceField dinámicamente :)

Publicado por Antonio Melé el Friday 7 de August de 2009 | 9 comentarios | Categorías: fields, forms, trucos

Subdominios con Django

En ocasiones nos interesa trabajar con subdominios en nuestros proyectos Django. Para ello podemos utilizar un sencillo middleware para subdominios que podemos encontrar en djangosnippets. Basta con guardarlo en nuestro proyecto e incluirlo en la lista MIDDLEWARE_CLASSES de nuestro settings.py. De esta forma tendremos el subdominio de la petición en la variable subdomain del objeto request.

El problema al trabajar con subdominios es que las sesiones iniciadas en un subdominio no se mantienen cuando se cambia a otro. Para poder mantener activas las sesiones entre subdominios tenemos que añadir la siguiente línea al settings.py de nuestro proyecto:

SESSION_COOKIE_DOMAIN = '.mi-dominio.com'

De esta forma la cookie de sesión que se almacena en el navegador valdrá para todos los subdominios.

Subdominios para usuarios

Si por ejemplo queremos dar un subdominio a cada usuario de nuestro proyecto podemos modificar el middleware para que busque el usuario adecuado y lo incluya en el objeto request. El middleware quedaría de la siguiente manera:

from django.http import Http404
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.models import User

class SubdomainMiddleware:
    """ Make the subdomain publicly available to classes """

    def process_request(self, request):
        domain_parts = request.get_host().split('.')
        if (len(domain_parts) > 2):
            subdomain = domain_parts[0]
            if (subdomain.lower() == 'www'):
                subdomain = ''
            domain = '.'.join(domain_parts[1:])
        else:
            subdomain = ''
            domain = request.META['HTTP_HOST']

        request.subdomain = subdomain
        request.domain = domain

        if subdomain != 'www' and subdomain != '':
            # Buscamos el usuario del subdominio
            try:
                request.usuario_subdominio = User.objects.filter(username=subdomain)
            except ObjectDoesNotExist:
                raise Http404

De esta forma el usuario correspondiente al subdominio que se visita está disponible en la variable usuario_subdominio del objeto request. Si utilizamos variables de contexto y tenemos 'django.core.context_processors.request' en la lista de procesadores de contexto (setting TEMPLATE_CONTEXT_PROCESSORS) podemos obtener el usuario actual en nuestras plantillas mediante:

{{ request.usuario_subdominio }}

Publicado por Antonio Melé el Sunday 2 de August de 2009 | 4 comentarios | Categorías: middleware, snippets, trucos, urls

Templatetag {% if %} con más comparaciones

Este snippet reemplaza la funcionalidad del templatetag {% if %} permitiendo realizar comparaciones con operadores >, <, >=, <=, != además de las comparaciones que permite hacer {% if %} por defecto. Por ejemplo una comparación con el operador mayor-igual-que para mostrar algo si hay más de 5 artículos sería:

{% if articulos|length >= 5 %} ... {% endif %}

Para utilizarlo en nuestro proyecto nos basta con seguir los siguientes pasos:

  1. Descargamos smart_if desde djangosnippets.
  2. Lo guardamos como smart_if.py en la carpeta templatetags de alguna de las aplicaciones de nuestro proyecto.
  3. Añadimos el tag {% load smartif %} en las plantillas que queramos utilizarlo y listo.

También hay otro snippet, elif for smart if tag, que permite utilizar el tag {% elif %} para realizar otras comparaciones dentro de un bucle if con nuestro tag smart_if. Este snippet incluye sólo la función smart_if para que la reemplacemos en nuestro smart_if.py original.

Publicado por Antonio Melé el Sunday 19 de July de 2009 | 1 comentario | Categorías: plantillas, snippets, templatetags, trucos

Crear una imagen de nuestros modelos con django-command-extensions

Algo interesante que nos aporta django-command-extensions es poder crear una representación gráfica de nuestros modelos (o por decirlo de otro modo nuestro esquema de base de datos) con tan sólo un comando. Esto es posible gracias a GraphViz y el resultado es algo parecido a un diseño UML. Para poder utilizar este comando debemos tener instalado pygraphviz y por supuesto la aplicación django_extensions debe estar incluída en el setting INSTALLED_APPS de nuestro proyecto.

Para instalar pygraphviz en Linux nos bastará con utilizar el comando:

apt-get install python-pygraphviz

Una vez hemos instalado django-command-extensions y pygraphviz podremos crear un archivo dot, formato utilizado por GraphViz ó una imagen. En nuestro caso vamos a crear un archivo PNG que incluya los modelos de todas las aplicaciones de nuestro proyecto. Para ello usamos el comando:

./manage.py graph_models -a -g -o mis_modelos.png

Con el parámetro -o especificamos el archivo de imagen en el que queremos que se almacene el resultado. Si sólo queremos incluir los modelos de algunas aplicaciones podemos hacerlo con el siguiente comando:

./manage.py graph_models app1 app2 app3 -o mis_modelos.png

Este ejemplo es de los modelos de la PyCon-Tech, un framework de gestión de conferencias basado en Django:

Representación gráfica de modelos con django-command-extensions y graphviz

Publicado por Antonio Melé el Sunday 12 de July de 2009 | 0 comentarios | Categorías: aplicaciones, imágenes, modelos, pluggables, trucos, tutorial