2010-02-26 16 views
15

Adjunto un método a la señal post_save de mi modelo Django. De esta forma, puedo borrar algunos elementos en caché siempre que se modifique el modelo.¿Por qué se sube post_save dos veces durante el guardado de un modelo de Django?

El problema que tengo es que la señal se activa dos veces cuando se guarda el modelo. No necesariamente duele nada (el código simplemente se equivocará) pero no puede ser correcto.

Un ejemplo rápido, simplemente imprimir el modelo a la consola (utilizando el servidor dev):

from blog.models import Post 
from django.db.models import signals 

def purge_cache(sender, **kwargs): 
    print 'Purging %s' % sender 

signals.post_save.connect(purge_cache, sender=Post) 

Esto es usando el establo 1.1.1 liberación de Django.

información actualizada:

Con la retroalimentación de los comentarios de todos, he modificado mi pregunta porque el tema está descubriendo ahora por qué el post_save está siendo disparado dos veces. Supongo que en este momento es que mi código models.py se importa dos veces y que post_save se está conectando varias veces.

¿Cuál sería la mejor manera de descubrir por qué se está importando/ejecutando dos veces?

+1

Si comente la línea de conexión post_delete' ', es la señal de 'post_save' levantó dos veces? – Desintegr

+2

mirando el código django y realmente no envía guardar(), ¿estás seguro de que recibirás la señal post_delete y no post_save dos veces? –

+0

@Desintegr - No puedo intentarlo por el momento, pero esa es una buena idea.Lo intentaré esta noche y actualizaré la pregunta. Si todavía ocurre después de eliminar el post_delete, simplemente cambiaré mi pregunta a "¿Por qué la señal post_save se genera dos veces?" :) ¿Tal vez el código models.py se está ejecutando dos veces y la señal se está conectando varias veces? –

Respuesta

12

Aparentemente, Python is sensitive to the way you import modules. En mi caso, no fue un problema con ningún código de importación dentro de mi aplicación de blog, sino un problema con la configuración de INSTALLED_APPS, que supongo que Django lo usa para hacer una importación inicial.

Dentro de mi blog de aplicaciones que estaba usando las importaciones como:

from blog.models import * 

Mi settings.py se configuró como:

INSTALLED_APPS = (
    'django.contrib.admin', 
    'django.contrib.auth', 
    ...snip... 
    'sorl.thumbnail', 
    'mysite.blog', 
) 

se añadió el prefijo "mysite" porque originalmente tenía ruta de importación problemas al implementar el sitio. Más tarde arreglé este problema (por lo que actuó de la misma manera que el servidor de desarrollo) al agregar varias rutas en mi script WSGI.

Extracción del prefijo "mysite" de la settings.py ha solucionado el problema:

INSTALLED_APPS = (
    'django.contrib.admin', 
    'django.contrib.auth', 
    ...snip... 
    'sorl.thumbnail', 
    'blog', 
) 
7

bien en busca de la raíz de este problema, puede utilizar solución rápida para evitar registrar la señal dos veces:

signals.post_save.connect(my_handler, MyModel, dispatch_uid="path.to.this.module") 

Source.

+1

Había visto esto, pero realmente parece un truco que agregaron porque no se podía molestar a la gente para arreglar sus importaciones. ¡Gracias por la ayuda! –

+2

Creo que no estoy de acuerdo con @LanceMcNearney anterior. Supongamos que está escribiendo un código de biblioteca. No puede controlar la forma en que los consumidores importan su código. –

+0

Bueno, django es conocido por su compatibilidad con versiones anteriores, esta solución permite versiones más nuevas para evitar el problema y aún conserva el comportamiento de versiones anteriores –

0

Aquí está el boleto sobre este problema: Django's signal framework may register listeners more than once #3951. Ahora está arreglado en la versión SVN de Django.

El problema es exactamente como dijiste: el módulo que registra la señal, se carga un par de veces, en algunos casos por diferentes rutas de importación, Django interpreta erróneamente cada módulo importado como módulos diferentes que registran el mismo señal.

+1

Todavía tengo este problema con django 1.6. Proporcionar un dispatch_uid no ayuda. – jvannistelrooy

Cuestiones relacionadas