2010-06-09 7 views
16

Ho lo stesso enigma di presented in this question, ma applicato all'author.User di Django.Come convertire request.user in un proxy auth.User class?

ho questo modello di delega:

class OrderedUser(User): 
    def __unicode__(self): 
     return self.get_full_name() 

    class Meta: 
     proxy=True 
     ordering=["first_name", "last_name"] 

E alcuni dei miei altri modelli utilizzano un OrderedUser invece di un django.contrib.auth.models.User come tipi di campo.

Nel mio punto di vista ho quindi utilizzare il request.user per compilare un campo e - come previsto - un errore:

'Cannot assign "<User...>": <field> must be a "OrderedUser" instance' 

ho potuto solo fare OrderedUser.objects.get(request.user.id), ma questo è un colpo in più per il database.

Quindi, come convertire una classe del modello base nella sua classe proxy?

risposta

14

E 'un altro colpo di database, ma questo funzionerà:

OrderedUser.objects.get(pk=request.user.pk) 

Modifica Si potrebbe provare:

o = OrderedUser() 
o.__dict__ = request.user.__dict__ 
+0

destro. C'è un meccanismo che non coinvolge un colpo al DB? – cethegeek

+2

Sì, copiare il ditt ha fatto il trucco. Grazie Daniele. – cethegeek

+3

Grazie per questo suggerimento. Una cosa che ho trovato però, quando si utilizza questo in un context_processor per passare un oggetto utente ai template ... devi farlo in modo diverso se l'utente non ha effettuato il login. Come hai fatto, o finisce sempre come un oggetto OrderedUser (discendente dall'utente), ma se l'utente non ha effettuato l'accesso, dovrebbe essere di tipo AnonymousUser. Quindi testerei se 'request.user.is_authenticated()' e se è così, solo allora fare quanto sopra. Altrimenti, fare 'o = request.user'. –

10

non ho potuto ottenere il metodo di copia dict a lavorare su Python 2.7 .4 e Django 1.6. Non l'ho tracciato fino in fondo, ma penso che avesse qualcosa a che fare con il fatto che fosse un oggetto pigro.

cosa ha funzionato per me:

request.user.__class__ = OrderedUser 

evita la chiamata del database e dà accesso alla roba di autenticazione di base e tutti i miei comportamenti estesi.

per rendere l'atto request.user come la classe proxy sempre, ho messo l'assegnazione nel middleware dopo il middleware di autenticazione e prima qualsiasi delle mie applicazioni potrebbero fare riferimento a esso. Poiché il middleware viene richiamato su ogni richiesta, assicurarsi che l'utente sia autenticato prima di impostare la classe. Usando il tuo esempio, ecco come il codice middleware potrebbe essere:

from yourapp.models import OrderedUser 

class OrderedUserMiddleware(): 
    def process_request(self, request): 
     if hasattr(request, 'user') and request.user.is_authenticated(): 
      request.user.__class__ = OrderedUser 

E ricorda di registrare il middleware dopo l'autenticazione:

MIDDLEWARE_CLASSES = [ 
    # ...middleware from the guts of Django, none of your middle wares yet... 
    'django.contrib.auth.middleware.AuthenticationMiddleware', 
    # ...more middleware from the guts of Django, none of your middlewares yet... 
    'yourapp.middleware.OrderedUserMiddleware', 
    # ...more middleware from you other middlewares... 
] 
+0

Proprio la cosa che sto cercando. – Charlesliam

+0

Funziona alla grande, tranne che non ho potuto ottenere il middleware che lavora con l'autenticazione django-rest-framework e ho dovuto ricorrere all'impostazione di __class__. – MrDBA

Problemi correlati