Parametri URL e logica nelle viste basate su classi Django (TemplateView)


94

Non mi è chiaro come sia meglio accedere ai parametri URL nelle viste basate su classi in Django 1.5.

Considera quanto segue:

Visualizza:

from django.views.generic.base import TemplateView


class Yearly(TemplateView):
    template_name = "calendars/yearly.html"

    current_year = datetime.datetime.now().year
    current_month = datetime.datetime.now().month

    def get_context_data(self, **kwargs):
        context = super(Yearly, self).get_context_data(**kwargs)
        context['current_year'] = self.current_year
        context['current_month'] = self.current_month
        return context

URLCONF:

from .views import Yearly


urlpatterns = patterns('',
    url(
        regex=r'^(?P<year>\d+)/$',
        view=Yearly.as_view(),
        name='yearly-view'
    ),
)

Voglio accedere al yearparametro nella mia vista, quindi posso fare logica come:

month_names = [
    "January", "February", "March", "April", 
    "May", "June", "July", "August", 
    "September", "October", "November", "December"
]

for month, month_name in enumerate(month_names, start=1):
    is_current = False
    if year == current_year and month == current_month:
        is_current = True
        months.append({
            'month': month,
            'name': month_name,
            'is_current': is_current
        })

Come si accede al meglio al parametro url in CBV come il precedente che è sottoclasse TemplateViewe dove si dovrebbe idealmente posizionare la logica in questo modo, ad es. in un metodo?


C'è l'opzione del semplice extra_contextdict in django2, vedi qui
Timo

Risposte:


113

Per accedere ai parametri dell'URL nelle viste basate sulla classe, usa self.argso self.kwargscosì per accedervi facendoself.kwargs['year']


1
Si è capito correttamente che non dovrei creare variabili direttamente nella vista come ho sopra? (qualcosa sul fatto che siano persistenti). Inoltre non capisco dove dovrei posizionare la logica come sopra, ad es. in quale metodo? Anche quando lo faccio year = self.kwargs['year']nella vista ottengo NameError: self not defined.

2
Tecnicamente non dovresti dato che sono a livello di classe e sono variabili di classe. Per quanto riguarda il NameError, dove stai cercando di fare year = self.kwargs['year']? Dovresti farlo in un metodo, non puoi farlo a livello di classe. Quindi, ad esempio, stai usando un TemplateViewche significa che faresti la logica nel tuo get_context_dataoverride.
Ngenator

4
Solo per riferimento: la documentazione su self.request, self.args ecc. Può essere trovata in docs.djangoproject.com/en/1.10/topics/class-based-views/…
LShi

Inoltre puoi farlo in def __init__(self):funzione nella classe se vuoi accedervi al di fuori di altre funzioni.
Rahat Zaman

60

Nel caso in cui passi un parametro URL in questo modo:

http://<my_url>/?order_by=created

Puoi accedervi nella visualizzazione basata sulla classe utilizzando self.request.GET(non è presentato self.argsné in self.kwargs):

class MyClassBasedView(ObjectList):
    ...
    def get_queryset(self):
        order_by = self.request.GET.get('order_by') or '-created'
        qs = super(MyClassBasedView, self).get_queryset()
        return qs.order_by(order_by)

4
Grazie! Questo mi ha confuso ... Continuo a leggere cose che implicano che i parametri HTTP saranno nei kwargs.
barbecue per barbecue

Puoi mostrare il get_queryset () della superclasse di MyClassBasedView? Vorrei solo fare qs=<Object>.objects.<method>
Timo

24

Ho trovato questa soluzione elegante, e per django 1.5 o versioni successive, come sottolineato qui :

Le viste generiche basate su classi di Django ora includono automaticamente una variabile di visualizzazione nel contesto. Questa variabile punta al tuo oggetto di visualizzazione.

Nel tuo views.py:

from django.views.generic.base import TemplateView    

class Yearly(TemplateView):
    template_name = "calendars/yearly.html"
    # Not here 
    current_year = datetime.datetime.now().year
    current_month = datetime.datetime.now().month

    # dispatch is called when the class instance loads
    def dispatch(self, request, *args, **kwargs):
        self.year = kwargs.get('year', "any_default")

    # other code

    # needed to have an HttpResponse
    return super(Yearly, self).dispatch(request, *args, **kwargs)

La soluzione di spedizione trovata in questa domanda .
Poiché la visualizzazione è già passata all'interno del contesto del modello, non è necessario preoccuparsene. Nel tuo file modello yearly.html, è possibile accedere a questi attributi di visualizzazione semplicemente:

{{ view.year }}
{{ view.current_year }}
{{ view.current_month }}

Puoi mantenere il tuo urlconf così com'è.

Vale la pena ricordare che l'inserimento di informazioni nel contesto del modello sovrascrive get_context_data (), quindi in qualche modo interrompe il flusso del bean di azione di django .


8

Finora sono stato in grado di accedere a questi parametri URL solo dall'interno del metodo get_queryset, anche se l'ho provato solo con un ListView e non con un TemplateView. Userò il parametro url per creare un attributo sull'istanza dell'oggetto, quindi utilizzerò quell'attributo in get_context_data per popolare il contesto:

class Yearly(TemplateView):
    template_name = "calendars/yearly.html"

    current_year = datetime.datetime.now().year
    current_month = datetime.datetime.now().month

    def get_queryset(self):
        self.year = self.kwargs['year']
        queryset = super(Yearly, self).get_queryset()
        return queryset

    def get_context_data(self, **kwargs):
        context = super(Yearly, self).get_context_data(**kwargs)
        context['current_year'] = self.current_year
        context['current_month'] = self.current_month
        context['year'] = self.year
        return context

Lo trovo strano, c'è un errore o qualcosa del genere quando provi a fare context['year'] = self.kwargs['year']? Dovrebbe essere accessibile ovunque nella classe.
Ngenator

@ Ngenator: ho appena impostato un progetto django pulito per ricontrollare e risulta che hai ragione. Non sono sicuro di cosa lo impedisse nel mio codice originale, ma lo scoprirò :). Grazie per l'
avviso

7

Che ne dici di usare solo decoratori Python per rendere questo intelligibile:

class Yearly(TemplateView):

    @property
    def year(self):
       return self.kwargs['year']

Mi piace questa. La proprietà è riutilizzabile.
cezar
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.