2010-04-27 19 views
114

Acabo de comenzar a implementar oyentes de señal en un proyecto django. Mientras entiendo lo que son y cómo usarlos. Me está costando trabajo averiguar dónde debo ponerlos. La documentación del sitio Django tiene esto que decir:¿Dónde deberían manejarse las señales en un proyecto django?

Where should this code live?

Se puede poner el manejo de señales y código de registro en cualquier lugar que desee. Sin embargo, deberá asegurarse de que el el módulo en el que se encuentra se importe desde el principio para que el manejo de la señal se registre antes de que se envíen las señales . Esto hace que models.py de su aplicación sea un buen lugar para poner registro de controladores de señal.

Si bien es una buena sugerencia, tener clases o métodos no modelo en mi models.py simplemente me da un mal sentido.

Entonces, ¿cuál es la mejor práctica/regla para almacenar y registrar manejadores de señal?

Respuesta

34

Realmente me gusta hacerlos classmethods del modelo en sí. Eso mantiene todo dentro de una clase, y significa que no tiene que preocuparse de importar nada.

+0

Me gusta eso. ¡Gracias! –

+2

¿Y dónde suele conectar controladores a las señales? – DataGreed

+1

@DataGreed: en la parte inferior de los modelos correspondientes.py. –

13

Acabo de leer el artículo this acerca de las mejores prácticas a la hora de diseñar sus proyectos/aplicaciones, y sugiere que todas las señales de despachador personal deben ir en un archivo llamado signals.py. Sin embargo, eso no resuelve completamente su problema, ya que aún necesita importarlos en algún lugar, y cuanto antes se importen, mejor.

La sugerencia del modelo es buena. Como ya definió todo en su archivo signals.py, no debería tomar más de una línea en la parte superior del archivo. Esto es similar a la forma en que se presenta el archivo admin.py (con las definiciones de clase en la parte superior y el código para registrar todas las clases de administración personalizadas en la parte inferior), si define las señales y las conecta en el mismo archivo.

Espero que ayude! En definitiva, se reduce a lo que prefieres.

+0

También quería poner mis manejadores de señal en un archivo 'signals.py', pero no sabía cómo debería llamarse después. Al importarlo en mi archivo 'models.py', obtuve una solución muy limpia, sin" contaminar "mi archivo models.py. ¡Gracias! :) –

+9

hay una importación cruzada allí: signals.py intenta importar el modelo de models.py –

39

Me acabo de enterar de esto, y como mis señales no están relacionadas con el modelo, pensé en agregar mi solución.

Estoy registrando varios datos al iniciar/cerrar sesión, y necesitaba engancharme en django.contrib.auth.signals.

he puesto los manejadores de señales en un archivo signals.py, y luego las señales importadas desde el archivo __init__.py módulo, ya que creo que se llama tan pronto como la aplicación se pone en marcha (prueba con una declaración print sugiere que se llama incluso antes el archivo de configuración se lee.)

# /project/__init__.py 
import signals 

y en signals.py

# /project/signals.py 
from django.contrib.auth.signals import user_logged_in 

def on_logged_in(sender, user, request, **kwargs): 
    print 'User logged in as: \'{0}\''.format(user) 

user_logged_in.connect(on_logged_in) 

soy bastante nuevo en Django (/ Python), de modo estoy abierto a cualquier persona que me dice que esto es una idea terrible !

+3

Esto parece lógico, pero sugiero hacerlo a nivel de aplicación. – Nils

+2

Cuidado, esta lógica muy probablemente dará como resultado el disparo de señales duplicadas. 'user_logged_in.connect (on_logged_in)' debería pasar en el argumento 'dispatch_uid'. Más en https: //docs.djangoproject.com/en/dev/topics/signals/# prevention-duplicate-signals. –

+0

Gracias por eso, es bueno saberlo. Estoy registrando todos los inicios de sesión usando este método (registrando IP/agente de usuario), y no he tenido ningún duplicado hasta ahora, ¡aunque eso no significa que un pequeño cambio en la línea no cause problemas! –

6

models.py y señales.En cada aplicación han sido los lugares recomendados para conectar señales, sin embargo, no son la mejor solución, en mi opinión, para mantener enviadas señales y controladores. El envío debería ser la razón por la que las señales y los controladores se inventaron en django.

Estuve luchando durante mucho tiempo, y finalmente nos dimos cuenta de la solución.

crear un módulo de conexión en la carpeta de aplicación

por lo que tenemos:

app/ 
    __init__.py 
    signals.py 
    models.py 
    connectors.py 

en app/connectors.py, definimos los gestores de señales y conectarlos. Se proporciona un ejemplo:

from signals import example_signal 
from models import ExampleModel 
from django.db.models.signals import post_save, post_delete 

def hanndler(sender, *args, **kwargs): 
    pass 

post_save.connect(hander, sender=ExampleModel) 

después en models.py, se añade la siguiente línea al final del archivo:

from app import connector 

todo lo hecho aquí.

De esta manera, podemos poner señales en signals.py, y todos los controladores en connectors.py. Sin desorden en modelos y señales.

Espero que brinde otra solución.

+0

Entonces, ¿qué entra en signals.py? Parece que de su ejemplo solo son las señales personalizadas. Por lo general, solo combinamos las señales y los conectores ya que la mayoría no tendrá señales personalizadas. – dalore

+0

@dalore sí, todas las señales personalizadas se ponen en signals.py. Tenemos muchas señales personalizadas. Pero si no tiene muchos, este archivo podría omitirse. – samuel

179

Esto se añadió a la documentation cuando Django 1.7 fue puesto en libertad:

En sentido estricto, el manejo de señales y el código de registro pueden vivir en cualquier lugar que te gusta, aunque se recomienda evitar el módulo raíz de la aplicación y sus modelos módulo para minimizar los efectos secundarios de la importación de código.

En la práctica, los controladores de señal se suelen definir en un submódulo de señales de la aplicación a la que se refieren. Los receptores de señal están conectados en el método ready() de la clase de configuración de la aplicación. Si está utilizando el decorador de receptor(), simplemente importe el submódulo de señales dentro de listo().

Modificado en Django 1.7: Como ready() no existía en las versiones anteriores de Django, el registro de la señal generalmente ocurría en el módulo de modelos.

La mejor práctica es definir sus controladores en handlers.py en un submódulo de señales, p. un archivo que se parece a:

yourapp/señales/handlers.py:

from django.db.models.signals import pre_save 
from django.dispatch import receiver 
from myapp.models import MyModel 

@receiver(pre_save, sender=MyModel) 
def my_handler(sender, **kwargs): 
    pass 

El mejor lugar para registrar su manejador de la señal es entonces en la AppConfig de la aplicación que lo define, mediante el ready() método. Esto se verá así:

yourapp/apps.py:

from django.apps import AppConfig 

class TasksConfig(AppConfig): 
    name = 'tasks' 
    verbose_name = "Tasks" 

    def ready(self): 
     import yourproject.yourapp.signals.handlers #noqa 

Asegúrese de que está cargando su AppConfig especificando que sea directamente en INSTALLED_APPS de su settings.py, o en el de __init__ tu aplicación Consulte see the ready() documentation para obtener más información.

Nota: Si va a proporcionar señales para otras aplicaciones a escuchar también, así, los pusieron en la __init__ en su módulo de señales, por ejemplo, un archivo que se parece a:

yourapp/señales/__ init__.py

import django.dispatch 

task_generate_pre_save = django.dispatch.Signal(providing_args=["task"]) 

Otra aplicación puede entonces escuchar su señal mediante la importación y registrarlo, por ejemplo, from yourapp.signals import task_generate_pre_save. Separar las señales de sus manejadores mantiene las cosas limpias.

Instrucciones de Django 1.6:

Si todavía está atascado en Django 1.6 o inferior, a continuación, usted haría lo mismo (definir sus manipuladores en yourapp/señales/handlers.py), sino que usar AppConfig, cargaría los manejadores a través del __init__.py de su aplicación, por ejemplo algo así como:

yourapp/__ init__.py

import signals 

Esto no es tan agradable como por el método de lista(), ya que a menudo causa problemas de importación circulares.

+3

como documentaiton dice que sobrescribe listo, es posible que desee hacer algo como super (ReportsConfig, self) .ready() en caso de que django alguna vez decida poblar ready() con algo (a partir de 1.7.0 está actualmente vacío) –

+2

Creo que esta respuesta es la mejor porque es la única que aborda los efectos secundarios de las importaciones. Vine aquí buscando las mejores prácticas, porque estoy limpiando una aplicación, que se rompe exactamente debido a este tipo de efectos secundarios. La aplicación se ejecuta en django 1.6 y las mejores prácticas solo funcionan en django 1.7. La solución temporal de permitir que las señales de importación '__init__' no funcionen para mí, entonces me pregunto si hay otro lugar desde el que pueda importar señales hasta que estemos listos para actualizar a una versión posterior de django. – kasperd

+0

¿No debería haber 'de. import handlers' (o similar) en 'yourapp/signals/__ init __. py'? – dhobbs

0

Los guardo en un archivo separado signals.py, en models.py después de definir todos los modelos. Los importo y conecto modelos a señales.

signals.py

# necessary imports 

def send_mail_on_save(<args>): 
    # code here 

models.py

# imports 
class mymodel(models.Model): 
    # model here 

# import signals 
from signals import send_mail_on_save 
# connect them 
post_save.connect(send_mail_on_save,sender=mymodel) 

Esto proporciona Me separación lógica, por supuesto, no hay nada malo en mantenerlos en models.py, Pero es más manejable de esta manera.

Espero que esto ayude !!

Cuestiones relacionadas