2010-08-17 18 views
40

Nella mia applicazione, voglio creare voci in certe tabelle quando un nuovo utente si iscrive. Ad esempio, voglio creare un profilo utente che faccia riferimento alla loro azienda e ad altri record per loro. Ho implementato questo con un segnale post_save:Come posso evitare che le apparecchiature siano in conflitto con il codice segnale post_save di django?

def callback_create_profile(sender, **kwargs): 
    # check if we are creating a new User 
    if kwargs.get('created', True): 
     user = kwargs.get('instance') 
     company = Company.objects.create(name="My Company") 
     employee = Employee.objects.create(company=company, name_first=user.first_name, name_last=user.last_name) 
     profile = UserProfile.objects.create(user=user, employee=employee, partner=partner) 
# Register the callback 
post_save.connect(callback_create_profile, sender=User, dispatch_uid="core.models") 

Questo funziona bene quando viene eseguito. Posso usare l'amministratore per creare un nuovo utente e anche le altre tre tabelle ottengono le voci con ragionevolezza. (Tranne che, il dipendente dal momento che user.first_name e user.last_name non sono compilati nel modulo di amministrazione quando salva. Non riesco ancora a capire perché sia ​​fatto così)

Il problema è venuto quando Ho eseguito la mia suite di test. Prima di questo, avevo creato una serie di proiettori per creare queste voci nelle tabelle. Ora ottengo un errore che afferma:

IntegrityError: duplicate key value violates unique constraint "core_userprofile_user_id_key" 

Penso che questo sia perché ho già creato un record aziendali, dei dipendenti e di profilo nel dispositivo con ID "1" e ora il segnale post_save sta cercando di ricrearlo.

I miei regali sono: posso disabilitare questo segnale post_save durante l'esecuzione di dispositivi? Posso rilevare che sono in esecuzione come parte della suite di test e non creare questi record? Dovrei cancellare questi record dalle fixture ora (anche se il segnale imposta solo i valori di default non i valori che voglio testare)? Perché il codice di caricamento del dispositivo non sovrascrive solo i record creati?

Come fanno le persone?

risposta

59

Penso di aver trovato un modo per farlo. V'è un parametro 'crudo' nei kwargs passati in lungo con i segnali in modo da poter sostituire la mia prova di cui sopra con questo:

if (kwargs.get('created', True) and not kwargs.get('raw', False)): 

grezzo viene utilizzato quando loaddata è in esecuzione. Questo sembra fare il trucco.

E 'menzionato qui: http://code.djangoproject.com/ticket/13299

Sarebbe bello se questo è stato documentato: http://docs.djangoproject.com/en/1.2/ref/signals/#django.db.models.signals.post_save

+0

+1. Non lo sapevo. Lo terremo a mente. –

+0

2 anni dopo, questo è il modo migliore che ho trovato per gestire questo. Dovevo farlo per il modello di profilo utente personalizzato (AUTH_PROFILE_MODULE) dove avrebbe creato un piccolo elenco di utenti predefiniti dalla mia app. Ho semplicemente controllato all'interno del mio segnale personalizzato se 'raw' in kwargs. – Jordan

+1

Ottima soluzione! Mi hai risparmiato un sacco di mal di testa stamattina. Per semplificare un po ', si potrebbe usare l'argomento named 'created' e rimuovere le parentesi ridondanti: ' 'se creato e non kwargs.get (' raw ', False):' ' –

1

Ho affrontato un problema simile in uno dei miei progetti. Nel mio caso i segnali stavano rallentando anche i test. Alla fine ho abbandonato i segnali per sostituire il metodo Model.save().

Nel tuo caso, tuttavia, non penso che abbia senso ottenere ciò ignorando i metodi save(). In tal caso, puoi provare questo. Attenzione, l'ho provato solo una volta. Lo sembrava funzionare ma non è stato testato a fondo.

  1. Creare your own test runner.
  2. Prima di caricare i dispositivi, disconnect la funzione callback_create_profile dal segnale User classe 'post_save.
  3. Lascia caricare gli apparecchi.
  4. Collegare nuovamente la funzione al segnale.
+0

Oh che sarebbe un approccio così ... non sapevo si potesse staccare segnali. – poswald

14

Questa è una vecchia questione, ma la soluzione che ho trovato più semplice è quello di utilizzare l'argomento 'crudo' , passato per caricare i dati, e decorare le funzioni listener, ad esempio:

from functools import wraps 


def disable_for_loaddata(signal_handler): 
    @wraps(signal_handler) 
    def wrapper(*args, **kwargs): 
     if kwargs['raw']: 
      print "Skipping signal for %s %s" % (args, kwargs) 
      return 
     signal_handler(*args, **kwargs) 
    return wrapper 

e poi

@disable_for_loaddata 
def callback_create_profile(sender, **kwargs): 
    # check if we are creating a new User 
    ... 
+0

Vale la pena sottolineare che il m2m i segnali non forniscono il flag "raw". Non sono sicuro di come aggirare questo. –

Problemi correlati