Django-filter: Erlauben, das Abrufen eines Abfragesatzes in einem FilterSet zu überschreiben

Erstellt am 21. Juni 2017  ·  4Kommentare  ·  Quelle: carltongibson/django-filter

Der Titel mag etwas verwirrend sein. Es wäre schön, eine generische Methode filter , die jedes Mal aufgerufen wird, wenn ein Abfragesatz abgerufen und nach Feldern gefiltert wird. Ja, ich kann die Eigenschaft qs überschreiben, zuerst einen gefilterten Abfragesatz abrufen und dann Prefetches anwenden. _Es ist jedoch nicht klar, ob dies Nebenwirkungen haben kann und der Zugriff auf die an den Filter übergebenen Daten sicher ist._

Da ist mein Anwendungsfall.
Ich filtere ein Abfrageset nach einer M2M-Beziehung (wie in queryset.filter(items__field="foo") ). Ich möchte jedoch auch vorab abgerufene Elemente nach diesem Feld filtern.

Mit anderen Worten, mein Filter sieht so aus:

# In my filterset
def filter_items_by_field(self, queryset, name, value):
        queryset = queryset.all().filter(
            items__field=value,
        )
        prefetched_items = Prefetch(
            'items',
            Item.objects..filter(
                field=value,
            ),
        )
        return queryset.prefetch_related(prefetched_items)

# In my vieset
def get_queryset(self):
        queryset = super().get_queryset()
        # This should be applied everytime
        prefetched_items = Prefetch(
            'items',
            Item.objects..filter(
                another_field=some_value,
            ),
        )
        return queryset.prefetch_related(prefetched_items)

Ein einzelner Filter wie dieser funktioniert wie erwartet. Ich habe jedoch möglicherweise mehrere filter_items_by_* Filter + ich muss dieselbe Filterung für den Abfragesatz aus dem Prefetch für alle Filter anwenden. Und mehrere Filter sind kein Problem, da sie sich in meinem Fall gegenseitig ausschließen. Aber ein Filter + generisch wird eine Ausnahme verursachen.

Der Punkt ist, dass ich nur einen Prefetch für dieselbe Suche anwenden kann. Also, in meinem Fall bekomme ich einfach eine Ausnahme.

Ich habe eine vorübergehende Problemumgehung für dieses Problem: alle filter_items_by_* beim Prefetch eine obligatorische Filterung durch.
Und in filter_queryset (nachdem die Filterung angewendet wurde), wenn items nicht vorab abgerufen werden (was schlecht ist, da ich durch Abfragen geschützte Attribute inspiziere), wende ich den Vorabruf mit der obligatorischen Filterung an. Aber es sollte einen besseren Weg geben, mit solchen Situationen umzugehen.

Ich hoffe, mein Beispiel ist klar genug.

Hilfreichster Kommentar

Hallo @Alexx-G. Ein 2.0-Release ist noch ein Ausweg, aber es wird einige Änderungen an der API geben, die sich speziell dieser Frage widmen. Zusamenfassend,

  • Sie sollten die Methode .filter_queryset() überschreiben. Das Attribut .qs im Grunde dafür verantwortlich, .filter_queryset() aufzurufen und das Ergebnis zwischenzuspeichern.
  • Sie können die Filterwerte für das Prefetching von self.form.cleaned_data .

Alle 4 Kommentare

Hallo @Alexx-G. Ich denke, dies könnte mit einer gewissen Abstimmung zwischen dem Filterset und den relevanten Filterklassen möglich sein. Im Wesentlichen würde der Filter eine Prefetch Instanz an seinen parent Filtersatz anhängen. FilterSet.qs würde dann bei Bedarf einfach prefetch_related anrufen.

Das heißt, was ist der Anwendungsfall dafür? Ich würde argumentieren, dass es wahrscheinlich geeignetere Orte gibt, um das Prefetching zu handhaben.

Ich denke, dies könnte mit einer gewissen Abstimmung zwischen dem Filterset und den relevanten Filterklassen möglich sein.

Ich habe mein Problem bereits gelöst, indem ich die Eigenschaft qs überschrieben habe, aber auch hier ist es nicht offensichtlich und nicht dokumentiert. Mit anderen Worten, ich kann nicht sicher sein, dass einige interne Änderungen in der Basisklasse sich nicht auf mein Filterset auswirken (ok, ich habe die Version gepinnt, aber trotzdem..)

Das heißt, was ist der Anwendungsfall dafür? Ich würde argumentieren, dass es wahrscheinlich geeignetere Orte gibt, um das Prefetching zu handhaben.

Ich glaube, ich habe oben meinen Anwendungsfall beschrieben. Es macht keinen Sinn, Filterung und Vorabruf zu trennen, da der Vorabruf von Filtern abhängt. Und wenn ich sie trenne, muss ich dieselben Überprüfungen für Filter duplizieren.

Mit anderen Worten, wenn es eine Beschreibung des öffentlichen Auftrags der qs-Eigenschaft oder einen dokumentierten Hook dafür gäbe, würde dies die Anpassung des Filtersatzes verbessern.

Hallo @Alexx-G. Ein 2.0-Release ist noch ein Ausweg, aber es wird einige Änderungen an der API geben, die sich speziell dieser Frage widmen. Zusamenfassend,

  • Sie sollten die Methode .filter_queryset() überschreiben. Das Attribut .qs im Grunde dafür verantwortlich, .filter_queryset() aufzurufen und das Ergebnis zwischenzuspeichern.
  • Sie können die Filterwerte für das Prefetching von self.form.cleaned_data .

Vielen Dank für Ihre Mühe!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen