Archive for the ‘django/python’ Category

El nuevo Amigo Invisible Online

Última hora!!! Tenemos un nuevo Amigo Invisible Online, la mejor forma de celebrar un amigo invisible por email. Bueno, no es última hora, pero como todavía no lo había blogeado, pues alguno no lo sabrá.

El nuevo amigo invisible, que por fuera se parece mucho al antiguo, tiene las siguientes funcionalidades:

  • Exclusiones múltiples. Era una funcionalidad muy demanda. Si no quieres que te toque ni fulanito ni menganito, escribe sus ids (su número de sorteo) separados por comas, y el sorteo se encargará de no cruzarlos.
  • Recupera el sorteo con el email. Mucha gente, aunque se le avise que debe anotar su número de sorteo, se le olvida o lo pierde y luego es un lío recuperarlo. Con esta funcionalidad puedes recuperar tu sorteo escribiendo 2 emails de los participantes. Es un método seguro, no hay problema de obtener otros emails ya que solo se muestran los nombres de los jugadores, si quieres reenviarles algo tendrás que volver a escribir el email
  • Mejores emails. El email que se envía al usuario es más bonito, con más funcionalidad (te puede dar de baja de la bbdd con un click, o recuperar fácilmente tu sorteo)
  • Mejor rendimiento. El nuevo amigo invisible corre en python + django. El poco js es jQuery. Está alojado en Amazon EC2 y los emails se envía usando Amazon SES
Todo esto y otras pequeñas mejoras hacen la mejor web para celebrar el sorteo del amigo invisible por email estas navidades.

django-membergetmember

He liberado una nueva app para django para la gestión de campañas Member-Get-Member al estilo groupon y otros. Tu traes un amigo y yo os doy X créditos a cada uno. Más info en el README del proyecto en github

Feedback is welcome

I have posted a new django app to manage Member Get Member campaigns, as groupon or livingsocial do. You get a new user and we give you some credits to spend onsite. More info in the README file on github’s project repository

django-sermepa

Acabo de subir al github una versión sencilla para utilizar el TPV Virtual de Sermepa: django-sermepa

Django-sermepa funciona de una forma muy parecida a django-paypal IPN:

  • En una página renderiza un formulario oculto y un botón de “Comprar”
  • Esto te lleva al TPV Virtual de Sermepa (Servired) donde se paga
  • Sermepa envía un post (el IPN de paypal) a tu servidor con los datos de la compra
  • django-sermepa captura este post, lo almacena en BBDD, lo valida y ejecuta las señales correspondientes
Por ahora solo permito pagos directos, nada de recurrentes. Yo no necesito el tema recurrenta así que no lo haré, pero entiendo que es fácil de implementar: Añadir los campos al formulario, mirar el código de respuesta, crear una Signal nueva y listo.

Cómo se hizo el mapa de calor

En el anterior post explicaba lo que era el mapa de calor de dooplan. Robert construyó la solución (a partir de otro desarrollo) y aquí explica cómo funciona.

pdb.set_trace() en Google App Engine

GAE redirecciona todo el stdout a la salida del navegador (response), por lo que el pdb tal cual no funciona. Para hacerlo funcionar hay que hacer un pequeño truco:

import sys, pdb
for attr in ('stdin', 'stdout', 'stderr'):
    setattr(sys, attr, getattr(sys, '__%s__' % attr))
pdb.set_trace()

Yo lo he encapsulado en un fichero, así puedo usarlo más o menos como antes. Lo he llamado gpdb.py:

import sys
import pdb

def set_trace():
    for attr in ('stdin', 'stdout', 'stderr'):
        setattr(sys, attr, getattr(sys, '__%s__' % attr))

    return pdb.set_trace()

Y para usarlo, en mi código añado:

            import gpdb; gpdb.set_trace()

Y el Amigo Invisible llegó a la nube

He subido el amigo invisible versión Django + GAE y ha funcionado! Aquí tenéis una versión primitiva de la aplicación, pero que funciona al 100%. Y con múltiples exclusiones!

TODOs:

  • L&F, ponerle el css adecuado
  • Corregir los últimos cambios de app_bij.py que ha hecho David
  • Uno, dos o tres pasos?
  • Añadir todas las funcionalidades extras: Recuperar el sorteo, ver con quien juegas, comentar lo que quieres que te regalen…
  • Añadir AdSense (y forrarme)
  • Y cuando todo vaya bien, mover el DNS para que www.amigoinvisibleonline.com apunte a la nube

PD. Tengo un límite de 2000 emails por día. Esto puede ser un problema, estas navidades estuve enviando más de 4000 al día, tendré que preguntar precios.

Primeros pasos con GAE y Django

Mi tutorial step-by-step:

  • Te bajas el GAE SDK y te lo instalas
  • Te bajas Django, si no lo tuvieras y quieres usar una versión moderna (>0.96)
  • Crea tu proyecto django, donde quieras: django-admin.py startproject xxx
  • Modifica el settings.py quitar todas las referencias a la BBDD, sessions, auth y admin. Ver esta nota
  • Copiar django framework y todo su contenido en la raiz del proyecto
  • Añade un fichero app.yaml, descriptor del proyecto, que contenga:
application: aio
version: 1
runtime: python
api_version: 1
handlers:
- url: /static
static_dir: site_media
- url: /.*
  script: main.py
  • Crea un fichero main.py, conteniendo lo siguiente:
import logging, os, sys

# Google App Engine imports.
from google.appengine.ext.webapp import util

# Remove the standard version of Django.
for k in [k for k in sys.modules if k.startswith('django')]:
  del sys.modules[k]

# Force sys.path to have our own directory first, in case we want to import
# from it.
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))

# Django imports and other code go here...
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi

def main():
  # Run Django via WSGI.
  application = django.core.handlers.wsgi.WSGIHandler()
  util.run_wsgi_app(application)

if __name__ == '__main__':
  main()
  • Crea los modelos usando los Types y Properties delGAE
  • Si vas a usar ModelForms también. Recuerda que los forms normales y los formset son los de django.
  • Para hacer las queries, usa estos comandos.
  • Para ejecutar el proyecto: ./dev_appserver.py <projecto>
  • Para acceder al admin, y a una consola interactiva, puedes verlo desde aquí: http://localhost:8080/_ah/admin
  • Todo lo demás funciona igual. Eso sí, ojo con la librería contrib.auth, que tampoco existe, se usan cuentas de google.
  • Por supuesto, la mayoría de pluggables fallarán, porque hay que migrar a los nuevos modelos…

Tengo el amigo invisible más o menos listo, tengo que probar el envío de mails, y luego lo subiré a los servidores de Google. A ver si mañana lo termino.

Google App Engine

Llevo esta tarde peleándome con el Google App Engine, para portar el amigo invisible a esto. Y no ha sido trivial. Por un lado, te quedas sin admin. La consola de administración del GAE no es para nada lo mismo. Por otro lado, y mucho mucho mucho más importante, no puedes usar import pdb;pdb.set_trace() Cómo puedes debugar sin eso?!!

Las diferencias con django se producen en la parte de BBDD, ya que se sustituyen los models de django por el sistema de Google. La definición es sencilla, pero los métodos para hacer queries dejan mucho que desear. Y las exceptions lanzadas también son diferentes.

Ojo también con los forms. Los ModelForms se extienden de un paquete de GAE, mientras que los forms normales son los de Django.

Por último, es posible y fácil utilizar Django en su versión actual. Simplemente hay que definir un archivo main.py (y declararlo en el app.yaml), con el siguiente contenido:

import logging, os, sys

# Google App Engine imports.
from google.appengine.ext.webapp import util

# Remove the standard version of Django.
for k in [k for k in sys.modules if k.startswith('django')]:
  del sys.modules[k]

# Force sys.path to have our own directory first, in case we want to import
# from it.
sys.path.insert(0, os.path.abspath(os.path.dirname(__file__)))

# Django imports and other code go here...
os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
import django.core.handlers.wsgi

def main():
  # Run Django via WSGI.
  application = django.core.handlers.wsgi.WSGIHandler()
  util.run_wsgi_app(application)

if __name__ == '__main__':
  main()

Trucos de Django Admin

Django Admin me sigue pareciendo una herramienta clave dentro de django. Es terriblemente potente y flexible. Es verdad, como dice nuestro compañero de trespams, el admin no es para el usuario final, pero puede ser un herramienta super útil para el usuario interno. En dooplan usamos el admin (entre otras cosas) para el equipo de editores de los eventos.

Con el Admin cada editor tiene los permisos de acceso a lo que le corresponde, tienen filtros y búsquedas a su medida, formularios muy fáciles de rellenar (hasta campos autotext!), histórico de modificaciones… Es una plataforma que con muy poco esfuerzo nos ha ofrecido una solución potentísima, que un desarrollo a medida no lo habría hecho mejor (y a que coste…)

Pues bien, el otro día James Bennett proponía un par de trucos interesantes para hackear aún más el admin. Yo completo ese tutorial con otro truco interesante. Cómo mostrar un formulario para el alta y otro para la modificación de un mismo modelo. Este caso puede ser interesante para simplificar el alta de un objeto, pero mantener el control completo en caso de la modificación.

Simplemente hay que sobreescribir los métodos add_view() y change_view() del ModelAdmin. Siguiendo con el ejemplo propuesto por Bennett, si queremos que en el alta solo tuviéramos que entrar title, slug y body, y en la modificación quisieramos ocultar el slug (para evitar que se modifique la url) y la fecha podríamos hacer esto:

class EntryAdmin(admin.ModelAdmin):
    ...
    def add_view(self, *args, **kwargs):
        self.fields = ('title','slug','body')
        return super(EntryAdmin, self).add_view(*args, **kwargs)

    def change_view(self, *args, **kwargs):
        self.fields = ('title','body','subject','author')
        return super(EntryAdmin, self).change_view(*args, **kwargs)

Por supuesto, podemos ser aún más vagos y sobreescribir solo uno de los métodos, y dejar que el otro coja los parámetros por defecto:

class EntryAdmin(admin.ModelAdmin):
    ...
    fields = ('title','body','subject','author')

    def add_view(self, *args, **kwargs):
        self.fields = ('title','slug','body')
        return super(EntryAdmin, self).add_view(*args, **kwargs)

Esto también funcionaría

Mi primer snippet (chispas)

Hoy me ha salido casi sin querer mi primer djangosnippet. Es un filtro para el admin, para poder seleccionar ver solo los elementos con el campo a null, o los que tengan valor, o todos juntos.

Funciona cuando quieres filtrar un campo genérico (un numérico, un string…) y este campo es nullable. Si no tuvieras este filtro te aparecen todos los valores posibles (completamente inutil en este tipo de campo). Si el campo no es nullable, este filtro no se activa.

El filtro hay que aplicarlo como parche sobre un fichero de django.

España fantasma
Históricos
ecoestadistica.com
La Lista de Sinde
Ofertas del día