Django y el error “object has no attribute ‘__name__'” al usar objetos invocables

Estándar

El framework web Django acepta como vista (concepto conocido en otros entornos como controlador) cualquier función o clase que cumpla con la interfaz “callable” (o invocable en castellano). Si decidimos emplear esta última forma nos encontraremos con que Django lanza una excepción en principio desconcertante:

AttributeError: object has no attribute '__name__'

¿Pero de donde sale eso? ¿Acaso Django se ha vuelto loco? ¡Si yo definí el método __call__ en la clase! ¡El framework no debería quejarse! ¡#$%&@! :D.

La respuesta a esto y tal vez a los improperios lanzados por el desarrollador 😉 es que en algún lugar de las profundidades del código fuente de Django (en un momento encontré el módulo causante del error pero ahora no lo recuerdo) el mismo está intentando acceder al atributo que menciona la excepción.

Cuando uno define una función en Python mediante la palabra clave def, detrás de bambalinas el interprete agrega el atributo __name__ a la misma (recordemos que en Python todo es un objeto, incluidas las clases y las funciones, y hasta es posible asignar atributos a esta última). Obviamente el framework espera que este atributo exista, es decir, espera una función propiamente dicha y no un objeto invocable.

La solución a esto es definir __name__ a mano, de la siguiente manera:

class Qwerty(object):

    __name__ = 'Qwerty'

    def __call__(self, *args, **kwargs):

        print args
        print kwargs

Personalmente he encontrado este error agregando vistas a la interfaz de administración que el framework genera con la ayuda del paquete django.contrib.admin (tal vez sea solo un bug que afecte a este paquete, debería probar usando objetos invocables en el despachador de URLs). Con esto espero ahorrarle a alguien horas de esfuerzo, desesperación y mechones de pelo. A mi me hubiese encantado :P.