URL-Parameter und Logik in Django-Klassenansichten (TemplateView)

94

Mir ist unklar, wie es am besten ist, in Django 1.5 auf URL-Parameter in klassenbasierten Ansichten zuzugreifen.

Folgendes berücksichtigen:

Aussicht:

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'
    ),
)

Ich möchte auf den yearParameter in meiner Ansicht zugreifen , damit ich folgende Logik ausführen kann:

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
        })

Wie würde man am besten auf den URL-Parameter in CBVs wie den oben genannten zugreifen, der in Unterklassen unterteilt ist, TemplateViewund wo sollte man die Logik idealerweise so platzieren, z. in einer Methode?

Nayan
quelle
Es gibt die Möglichkeit des einfachen extra_contextDiktats in django2, siehe hier
Timo

Antworten:

113

Verwenden Sie self.argsoder self.kwargsso , um auf die URL-Parameter in klassenbasierten Ansichten zuzugreifenself.kwargs['year']

Ngenator
quelle
1
Ist es richtig verstanden, dass ich keine Variablen direkt in der Ansicht erstellen soll, wie ich es oben habe? (etwas daran, dass sie hartnäckig sind). Ich verstehe auch nicht, wo ich Logik wie oben platzieren soll, z. in welcher Methode? Auch wenn ich year = self.kwargs['year']in der Ansicht mache, bekomme ich NameError: self not defined.
2
Technisch sollten Sie dies nicht tun, da sie sich auf Klassenebene befinden und Klassenvariablen sind. Was die NameError, wo versuchst du zu tun year = self.kwargs['year']? Sie sollten es in einer Methode tun, Sie können es nicht auf Klassenebene tun. Sie verwenden beispielsweise a, TemplateViewwas bedeutet, dass Sie die Logik für Ihre get_context_dataÜberschreibung ausführen würden.
Ngenator
4
Nur zum Referenzieren: Die Dokumentation zu self.request, self.args usw. finden Sie unter docs.djangoproject.com/de/1.10/topics/class-based-views/…
LShi
Sie können dies auch in der def __init__(self):Funktion in der Klasse tun, wenn Sie außerhalb anderer Funktionen darauf zugreifen möchten.
Rahat Zaman
60

Falls Sie einen URL-Parameter wie folgt übergeben:

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

Sie können in der klassenbasierten Ansicht darauf zugreifen, indem Sie Folgendes verwenden self.request.GET(weder in self.argsnoch in dargestellt 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)
Niekas
quelle
4
Vielen Dank! Das hat mich verwirrt ... Ich lese immer wieder Dinge, die implizieren, dass HTTP-Parameter in den kwargs enthalten sind.
Foobarbecue
Können Sie das get_queryset () der Oberklasse von MyClassBasedView anzeigen? Ich würde es einfach tun qs=<Object>.objects.<method>
Timo
24

Ich fand diese elegante Lösung und für Django 1.5 oder höher, wie hier ausgeführt :

Die generischen klassenbasierten Ansichten von Django enthalten jetzt automatisch eine Ansichtsvariable im Kontext. Diese Variable zeigt auf Ihr Ansichtsobjekt.

In Ihren 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)

Die Versandlösung finden Sie in dieser Frage .
Da die Ansicht bereits im Vorlagenkontext übergeben wird, müssen Sie sich darüber keine Gedanken machen. In Ihrer Vorlagendatei yearly.html können Sie auf diese Ansichtsattribute einfach zugreifen, indem Sie:

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

Sie können Ihre URLconf so lassen , wie sie ist.

Es ist erwähnenswert, dass das Abrufen von Informationen in den Kontext Ihrer Vorlage get_context_data () überschreibt, sodass der Action-Bean- Fluss des Django irgendwie unterbrochen wird .

Evhz
quelle
8

Bisher konnte ich nur über die Methode get_queryset auf diese URL-Parameter zugreifen, obwohl ich es nur mit einer ListView und nicht mit einer TemplateView versucht habe. Ich werde den URL-Parameter verwenden, um ein Attribut für die Objektinstanz zu erstellen, und dann dieses Attribut in get_context_data verwenden, um den Kontext zu füllen:

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
Tor der Hölle
quelle
Ich finde das seltsam, gibt es einen Fehler oder etwas, wenn Sie versuchen, dies zu tun context['year'] = self.kwargs['year']? Es sollte überall in der Klasse zugänglich sein.
Ngenator
@Ngenator: Ich habe gerade ein sauberes Django-Projekt eingerichtet, um es zu überprüfen, und es stellt sich heraus, dass Sie korrekt sind. Ich bin mir nicht sicher, was dies in meinem ursprünglichen Code verhindert hat, aber ich werde es herausfinden :). Vielen Dank für das Heads-up
Hellsgate
7

Wie wäre es einfach mit Python-Dekoratoren, um dies verständlich zu machen:

class Yearly(TemplateView):

    @property
    def year(self):
       return self.kwargs['year']
danizen
quelle
Ich mag diesen. Die Eigenschaft ist wiederverwendbar.
Cezar