Wann wird get, get_queryset, get_context_data in Django verwendet?

74

Ich habe kürzlich erfahren, dass Sie die get-Methode überschreiben sollten, wenn Sie speziell etwas anderes als die Standardansicht tun möchten:

class ExampleView(generic.ListView):
    template_name = 'ppm/ppm.html'

    def get(self, request):
        manager = request.GET.get('manager', None)
        if manager:
            profiles_set = EmployeeProfile.objects.filter(manager=manager)
        else:
            profiles_set = EmployeeProfile.objects.all()
            context = {
                'profiles_set': profiles_set,
                'title': 'Employee Profiles'
            }

Das ist einfach genug, aber wann sollte ich es verwenden get_querysetoder get_context_datadarüber hinaus get? Mir scheint, dass sie im Grunde das Gleiche tun oder fehlt mir nur etwas? Kann ich sie zusammen verwenden? Dies ist für mich eine große Verwirrung.

Um es noch einmal zu wiederholen: In welchen Fällen würde ich verwenden, um zu überwinden get_querysetoder get_context_dataumgekehrt?

nastyn8
quelle
3
Andererseits; Sie sollten selten überschreiben get, und schon gar nicht in diesem Fall. Hier sollten Sie nur überschreiben get_context_data.
Daniel Roseman

Antworten:

147

Sie machen tatsächlich verschiedene Dinge.

get()

Dies ist ein Top-Level - Verfahren, und es gibt einen für jede HTTP - Verb - get(), post(), patch()etc. Sie würden es außer Kraft setzen , wenn Sie etwas tun wollen , bevor ein Antrag der Ansicht verarbeitet wird, oder danach. Dies wird jedoch nur aufgerufen, wenn eine Formularansicht zum ersten Mal geladen wird, nicht, wenn das Formular gesendet wird. Grundlegendes Beispiel in der Dokumentation . Standardmäßig wird nur die konfigurierte Vorlage gerendert und der HTML-Code zurückgegeben.

class MyView(TemplateView):
    # ... other methods

    def get(self, *args, **kwargs):
        print('Processing GET request')
        resp = super().get(*args, **kwargs)
        print('Finished processing GET request')
        return resp

get_queryset()

Wird von ListViews verwendet - bestimmt die Liste der Objekte, die Sie anzeigen möchten. Standardmäßig erhalten Sie nur alles für das von Ihnen angegebene Modell. Durch Überschreiben dieser Methode können Sie diese Logik erweitern oder vollständig ersetzen. Django-Dokumentation zu diesem Thema .

class FilteredAuthorView(ListView):
    template_name = 'authors.html'
    model = Author

    def get_queryset(self):
        # original qs
        qs = super().get_queryset() 
        # filter by a variable captured from url, for example
        return qs.filter(name__startswith=self.kwargs['name'])

get_context_data()

Diese Methode wird verwendet, um ein Wörterbuch zu füllen, das als Vorlagenkontext verwendet werden soll. Zum Beispiel füllt ListViews das Ergebnis get_queryset()wie author_listim obigen Beispiel aus. Sie werden diese Methode wahrscheinlich am häufigsten überschreiben, um Dinge hinzuzufügen, die in Ihren Vorlagen angezeigt werden sollen.

def get_context_data(self, **kwargs):
    data = super().get_context_data(**kwargs)
    data['page_title'] = 'Authors'
    return data

Und dann können Sie in Ihrer Vorlage auf diese Variablen verweisen.

<h1>{{ page_title }}</h1>

<ul>
{% for author in author_list %}
    <li>{{ author.name }}</li>
{% endfor %}
</ul>

Um Ihre Hauptfrage zu beantworten, haben Sie so viele Methoden, dass Sie Ihre benutzerdefinierte Logik auf einfache Weise punktgenau festhalten können. Dadurch kann Ihr Code nicht nur lesbarer und modularer, sondern auch besser getestet werden.

Die Dokumentation sollte alles erklären. Wenn immer noch nicht genug, finden Sie möglicherweise auch die Quellen hilfreich. Sie werden sehen, wie alles mit Mixins implementiert wird, die nur möglich sind, weil alles unterteilt ist.

Anonym
quelle
13
Mit CCBV ist es noch einfacher zu verstehen, wie klassenbasierte Ansichten zusammengestellt werden, als die Quelle zu lesen.
Dustin Wyatt
Wird es richtig sein zu implizieren, dass es besser ist, get_query_set () zu verwenden, um das erste Ergebnis zu filtern, wenn Sie mit einem Larga-Datensatz arbeiten, um zu vermeiden, dass eine so große Liste im Speicher ist?
Manza
Wahrscheinlich. Sie können auch in die Vorlagen schneiden .
Anonym
Wenn ich das Kontextobjekt (z. B. aus mehreren Abfragen verschiedener Modelle) mit get_context_data()erstelle, warum brauche ich es dann noch get_query_set()und wie kann ich es entfernen, wenn ich es nicht verwende?
user5359531
1
Schöne Erklärung danke. Sie möchten die Überschrift get_query_set () in get_queryset () (ohne Unterstrich) ändern
Kaan Karaca
10

Schauen wir uns die Standardimplementierung der ListView- getMethode an:

https://github.com/django/django/blob/92053acbb9160862c3e743a99ed8ccff8d4f8fd6/django/views/generic/list.py#L158

class BaseListView(MultipleObjectMixin, View):
    """
    A base view for displaying a list of objects.
    """
    def get(self, request, *args, **kwargs):
        self.object_list = self.get_queryset()
        allow_empty = self.get_allow_empty()

        if not allow_empty:
            # When pagination is enabled and object_list is a queryset,
            # it's better to do a cheap query than to load the unpaginated
            # queryset in memory.
            if (self.get_paginate_by(self.object_list) is not None
                    and hasattr(self.object_list, 'exists')):
                is_empty = not self.object_list.exists()
            else:
                is_empty = len(self.object_list) == 0
            if is_empty:
                raise Http404(_("Empty list and '%(class_name)s.allow_empty' is False.")
                        % {'class_name': self.__class__.__name__})
        context = self.get_context_data()
        return self.render_to_response(context)

Sie werden feststellen, dass dies get_querysetin der ersten Zeile aufgerufen wird. Sie können dies einfach überschreiben, wenn Sie den Abfragesatz Ihres Modells nach dem Anwenden von Filterung / Bestellung usw. nur zurückgeben möchten.

Sie müssen dafür nicht die gesamte getMethode überschreiben , da Ihnen all diese bereitgestellten Funktionen fehlen, z. B. Paginierung, 404 Überprüfungen usw.

get_context_data führt das resultierende Abfrageset zusammen mit Kontextdaten wie Querystring-Parametern für die Paginierung usw. zusammen.

Was ich empfehlen würde, wäre, ab und zu mit der Quelle von django zu sprechen und zu versuchen, sie ein wenig zu verstehen, damit Sie die am besten geeignete Methode erkennen, die Sie überschreiben / ersetzen können.

fips
quelle