Domanda

Django view punta a una funzione, il che può rappresentare un problema se si desidera modificare solo una parte della funzionalità.Sì, potrei avere milioni di argomenti con parole chiave e anche di più con istruzioni if ​​nella funzione, ma stavo pensando più a un approccio orientato agli oggetti.

Ad esempio, ho una pagina che visualizza un utente.Questa pagina è molto simile alla pagina che visualizza un gruppo, ma non è ancora così simile da utilizzare semplicemente un altro modello di dati.Il gruppo ha anche membri ecc...

Un modo potrebbe essere quello di indirizzare le visualizzazioni ai metodi della classe e quindi estendere quella classe.Qualcuno ha provato questo approccio o ha qualche altra idea?

È stato utile?

Soluzione

Ho creato e utilizzato le mie classi di visualizzazione generiche, definendo __call__ quindi un'istanza della classe è richiamabile.Mi piace veramente;mentre le visualizzazioni generiche di Django consentono una certa personalizzazione tramite argomenti di parole chiave, le visualizzazioni generiche OO (se il loro comportamento è suddiviso in una serie di metodi separati) possono avere una personalizzazione molto più dettagliata tramite sottoclassi, il che mi consente di ripetermi molto meno.(Mi stanco di riscrivere la stessa logica di creazione/aggiornamento della vista ogni volta che ho bisogno di modificare qualcosa che le visualizzazioni generiche di Django non consentono del tutto).

Ho pubblicato del codice su djangosnippets.org.

L'unico vero svantaggio che vedo è la proliferazione di chiamate di metodi interni, che potrebbero in qualche modo influire sulle prestazioni.Non penso che questo sia un grosso problema;è raro che l'esecuzione del codice Python rappresenti un collo di bottiglia nelle prestazioni in un'app Web.

AGGIORNAMENTO:Quello di Django visioni generiche sono ora basati sulla classe.

AGGIORNAMENTO:FWIW, ho cambiato la mia opinione sulle visualizzazioni basate sulla classe da quando è stata scritta questa risposta.Dopo averli utilizzati estensivamente su un paio di progetti, sento che tendono a portare a un codice che è soddisfacentemente SECCO da scrivere, ma molto difficile da leggere e mantenere in seguito, perché la funzionalità è distribuita in così tanti posti diversi e le sottoclassi sono così dipendenti su ogni dettaglio implementativo delle superclassi e dei mixin.Adesso lo sento TemplateResponse e i decoratori di visualizzazione sono una risposta migliore per scomporre il codice di visualizzazione.

Altri suggerimenti

Avevo bisogno di utilizzare visualizzazioni basate su classi, ma volevo poter utilizzare il nome completo della classe nel mio URLconf senza dover sempre creare un'istanza della classe di visualizzazione prima di utilizzarla.Ciò che mi ha aiutato è stata una metaclasse sorprendentemente semplice:

class CallableViewClass(type):
    def __call__(cls, *args, **kwargs):
        if args and isinstance(args[0], HttpRequest):
            instance = super(CallableViewClass, cls).__call__()
            return instance.__call__(*args, **kwargs)
        else:
            instance = super(CallableViewClass, cls).__call__(*args, **kwargs)
            return instance


class View(object):
    __metaclass__ = CallableViewClass

    def __call__(self, request, *args, **kwargs):
        if hasattr(self, request.method):
            handler = getattr(self, request.method)
            if hasattr(handler, '__call__'):
                return handler(request, *args, **kwargs)
        return HttpResponseBadRequest('Method Not Allowed', status=405)

Ora posso sia istanziare le classi di visualizzazione sia utilizzare le istanze come funzioni di visualizzazione, OPPURE posso semplicemente puntare il mio URLconf alla mia classe e fare in modo che la metaclass istanzia (e chiami) la classe di visualizzazione per me.Funziona controllando il primo argomento to __call__ – se è a HttpRequest, deve trattarsi di una richiesta HTTP effettiva poiché non avrebbe senso tentare di istanziare una classe di visualizzazione con un HttpRequest esempio.

class MyView(View):
    def __init__(self, arg=None):
        self.arg = arg
    def GET(request):
        return HttpResponse(self.arg or 'no args provided')

@login_required
class MyOtherView(View):
    def POST(request):
        pass

# And all the following work as expected.
urlpatterns = patterns(''
    url(r'^myview1$', 'myapp.views.MyView', name='myview1'),
    url(r'^myview2$', myapp.views.MyView, name='myview2'),
    url(r'^myview3$', myapp.views.MyView('foobar'), name='myview3'),
    url(r'^myotherview$', 'myapp.views.MyOtherView', name='otherview'),
)

(Ho pubblicato uno snippet per questo su http://djangosnippets.org/snippets/2041/)

Se stai semplicemente visualizzando i dati dei modelli, perché non utilizzare il file Viste generiche di Django?Sono progettati per consentirti di mostrare facilmente i dati da un modello senza dover scrivere la tua vista e cose sulla mappatura dei parametri URL sulle viste, il recupero dei dati, la gestione dei casi limite, il rendering dell'output, ecc.

Puoi sempre creare una classe, sovrascrivere il file __call__ funzione e quindi puntare il file URL a un'istanza della classe.Puoi dare un'occhiata a FormWizard lezione per vedere come si fa.

Mi sembra che tu stia cercando di combinare cose che non dovrebbero essere combinate.Se devi eseguire un'elaborazione diversa nella tua visualizzazione a seconda che si tratti di un oggetto Utente o Gruppo che stai cercando di visualizzare, dovresti utilizzare due diverse funzioni di visualizzazione.

D'altra parte possono esserci idiomi comuni che vorresti estrarre dalle tue visualizzazioni di tipo object_detail...forse potresti usare un decoratore o solo funzioni di supporto?

-Dan

A meno che tu non voglia fare qualcosa di un po' complesso, utilizzare le visualizzazioni generiche è la strada da percorrere.Sono molto più potenti di quanto suggerisce il nome e, se stai solo visualizzando i dati del modello, visualizzazioni generiche faranno il lavoro.

Le visualizzazioni generiche saranno solitamente la strada da percorrere, ma alla fine sei libero di gestire gli URL come preferisci.FormWizard esegue le operazioni in modo basato sulle classi, così come alcune app per API RESTful.

Fondamentalmente con un URL ti vengono fornite una serie di variabili e il posto in cui fornire un richiamabile, ciò che richiamabile fornisci dipende completamente da te - il modo standard è fornire una funzione - ma alla fine Django non pone restrizioni su ciò che fai.

Sono d'accordo sul fatto che qualche altro esempio su come farlo sarebbe utile, FormWizard è probabilmente il punto di partenza.

Se vuoi condividere funzionalità comuni tra le pagine ti suggerisco di guardare i tag personalizzati.Sono abbastanza facile da creare, e sono molto potenti.

Anche, i modelli possono estendersi da altri modelli.Ciò ti consente di avere un modello di base per impostare il layout della pagina e di condividerlo con altri modelli che riempiono gli spazi vuoti.Puoi nidificare i modelli a qualsiasi profondità;permettendoti di specificare il layout su gruppi separati di pagine correlate in un unico posto.

Puoi utilizzare le visualizzazioni generiche di Django.Puoi facilmente ottenere la funzionalità desiderata tramite le visualizzazioni generiche di Django

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top