Ich bin ... über den Weg gelaufen …
Traceback (most recent call last):
[..]
File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 393, in _clean_fields
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
File "/usr/local/lib/python3.7/site-packages/django_filters/widgets.py", line 201, in value_from_datadict
return value.split(',')
AttributeError: 'list' object has no attribute 'split'
und festgestellt, dass der Code bei …
https://github.com/carltongibson/django-filter/blob/1f47e36b614724a8735e0457fa511dcaf5448481/django_filters/widgets.py#L195 -L202
… ist nicht robust gegenüber der Rückgabe einer Liste durch super().value_from_datadict(data, files, name)
. Ich muss das mehr debuggen, aber vielleicht weißt du schon, was hier vor sich geht?
Hallo @moseb. Können Sie den von Ihnen verwendeten FilterSet-Code einfügen? Die letzten paar Zeilen der Rückverfolgung reichen aus, um festzustellen, warum diese Ausnahme aufgetreten ist.
Vollständige Rückverfolgung:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/wsgiref/handlers.py", line 137, in run
self.result = application(self.environ, self.start_response)
File "/usr/local/lib/python3.7/site-packages/django/contrib/staticfiles/handlers.py", line 65, in __call__
return self.application(environ, start_response)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/wsgi.py", line 141, in __call__
response = self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 75, in get_response
response = self._middleware_chain(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
response = response or self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
response = response or self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
response = response or self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
response = response or self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
response = response or self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/utils/deprecation.py", line 94, in __call__
response = response or self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django_global_request/middleware.py", line 15, in __call__
return self.get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 36, in inner
response = response_for_exception(request, exc)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 90, in response_for_exception
response = handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
response = get_response(request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 145, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 143, in _get_response
response = response.render()
File "/usr/local/lib/python3.7/site-packages/django/template/response.py", line 106, in render
self.content = self.rendered_content
File "/usr/local/lib/python3.7/site-packages/rest_framework/response.py", line 72, in rendered_content
ret = renderer.render(self.data, accepted_media_type, context)
File "/usr/local/lib/python3.7/site-packages/rest_framework/renderers.py", line 733, in render
context = self.get_context(data, accepted_media_type, renderer_context)
File "/usr/local/lib/python3.7/site-packages/rest_framework/renderers.py", line 710, in get_context
'filter_form': self.get_filter_form(data, view, request),
File "/usr/local/lib/python3.7/site-packages/rest_framework/renderers.py", line 642, in get_filter_form
html = backend().to_html(request, queryset, view)
File "/usr/local/lib/python3.7/site-packages/rest_framework_filters/backends.py", line 52, in to_html
return super().to_html(request, queryset, view)
File "/usr/local/lib/python3.7/site-packages/django_filters/rest_framework/backends.py", line 105, in to_html
return template.render(context, request)
File "/usr/local/lib/python3.7/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 171, in render
return self._render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.7/site-packages/crispy_forms/templatetags/crispy_forms_tags.py", line 199, in render
c = self.get_render(context).flatten()
File "/usr/local/lib/python3.7/site-packages/crispy_forms/templatetags/crispy_forms_tags.py", line 118, in get_render
actual_form.form_html = helper.render_layout(actual_form, node_context, template_pack=self.template_pack)
File "/usr/local/lib/python3.7/site-packages/crispy_forms/helper.py", line 308, in render_layout
template_pack=template_pack
File "/usr/local/lib/python3.7/site-packages/crispy_forms/layout.py", line 140, in render
return self.get_rendered_fields(form, form_style, context, template_pack, **kwargs)
File "/usr/local/lib/python3.7/site-packages/crispy_forms/layout.py", line 104, in get_rendered_fields
for field in self.fields
File "/usr/local/lib/python3.7/site-packages/crispy_forms/layout.py", line 104, in <genexpr>
for field in self.fields
File "/usr/local/lib/python3.7/site-packages/crispy_forms/utils.py", line 148, in render_field
html = template.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/backends/django.py", line 61, in render
return self.template.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 171, in render
return self._render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 163, in _render
return self.nodelist.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 309, in render
return nodelist.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 309, in render
return nodelist.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 937, in render
bit = node.render_annotated(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 904, in render_annotated
return self.render(context)
File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 302, in render
match = condition.eval(context)
File "/usr/local/lib/python3.7/site-packages/django/template/defaulttags.py", line 876, in eval
return self.value.resolve(context, ignore_failures=True)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 671, in resolve
obj = self.var.resolve(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 796, in resolve
value = self._resolve_lookup(context)
File "/usr/local/lib/python3.7/site-packages/django/template/base.py", line 837, in _resolve_lookup
current = getattr(current, bit)
File "/usr/local/lib/python3.7/site-packages/django/forms/boundfield.py", line 74, in errors
return self.form.errors.get(self.name, self.form.error_class())
File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 180, in errors
self.full_clean()
File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 381, in full_clean
self._clean_fields()
File "/usr/local/lib/python3.7/site-packages/django/forms/forms.py", line 393, in _clean_fields
value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name))
File "/usr/local/lib/python3.7/site-packages/django_filters/widgets.py", line 201, in value_from_datadict
return value.split(',')
AttributeError: 'list' object has no attribute 'split'
[12/Jul/2019 13:49:06] "GET /XXXXXXXX/?ordering=first_name HTTP/1.1" 500 59
Es stammt aus dem Durchsuchen einer Liste, in der django-rest-framework den Code generiert.
Hallo @moseb. Können Sie den von Ihnen verwendeten FilterSet-Code einfügen?
Um ehrlich zu sein, habe ich in diesem Bereich des Codes noch keine gefunden. Es könnte alles von DRF sein. Noch nicht sicher.
Ich bin mir bewusst, dass mein Fehlerbericht nicht ideal ist, aber er ist der beste, den ich im Moment habe. Verzeihung!
Ihre API-Ansicht sollte entweder filterset_class
oder filterset_fields
haben, oder wenn Sie eine ältere Version von django-filter verwenden, filter_class
und filter_fields
.
Ich habe Verwendung von filter_class
gefunden – also schätze ich, dass Sie mir gerade dabei geholfen haben, herauszufinden, dass die Migration zu django-filter 2.0 nicht richtig bis zu ihrem Ende durchgeführt wurde. Cool!
Gibt es etwas, das django-filter daran hindert, Pre-2.x-Reste zu erkennen und konzeptionell vor ihnen zu warnen? Warnt es, aber ich habe es verpasst? Wäre eine Code-Warnung darüber eine willkommene Ergänzung für einen Pull-Request?
v2.0 hat viele der bestehenden Verfallswarnungen entfernt, also könnten Sie versuchen, Ihre Testsuite gegen v1.0 und dann gegen v1.1 von django-filter auszuführen.
Angenommen, dies löst sich beim Update von selbst. Kommen Sie zurück, wenn nicht.
Es gibt jetzt eine reproduzierbare Demo des Problems unter https://github.com/moseb/django-filter-issue-1103-demo. Bitte erwägen Sie, dieses Thema erneut zu öffnen. Danke schön!
Ah, das hängt damit zusammen, dass ModelMultipleChoiceFilter
nicht mit dem CSV-Mixin kompatibel ist, sowie mit der in
-Suche. Zwei separate, aber verwandte Probleme hier.
Sie sollten keine in
-Suche für m2m-Felder benötigen, da der Multiple-Choice-Filter bereits ein ähnliches Verhalten bietet.
Hallo!
Ah, das hängt damit zusammen, dass
ModelMultipleChoiceFilter
nicht mit dem CSV-Mixin kompatibel ist, sowie mit derin
-Suche. Zwei separate, aber verwandte Probleme hier.
Gibt es für diese Probleme bestehende Tickets auf GitHub?
Es hört sich so an, als würde es das Problem allein nicht lösen, BaseCSVWidget.value_from_datadict
robuster zu machen, wie oben erwähnt? (Ich verstehe das Problem noch nicht ganz.)
Sie sollten keine
in
-Suche für m2m-Felder benötigen, da der Multiple-Choice-Filter bereits ein ähnliches Verhalten bietet.
in
ermöglicht die Prüfung gegen mehrere Werte über exact
. Wie überprüfe ich mehrere Werte, wenn ich ìn
nicht verwenden kann?
PS: Können wir dieses Ticket wieder öffnen?
Es hört sich so an, als würde es das Problem allein nicht beheben,
BaseCSVWidget.value_from_datadict
robuster zu machen, wie oben erwähnt? (Ich verstehe das Problem noch nicht ganz.)
Möglicherweise. Wenn der Wert bereits eine Liste ist, sollte er einfach fortfahren und diese Liste zurückgeben. Allerdings halte ich es nicht für sinnvoll, das CSV-Verhalten mit dem SelectMultiple
-Widget zu mischen.
in
ermöglicht die Prüfung gegen mehrere Werte überexact
. Wie überprüfe ich mehrere Werte, wenn ichìn
nicht verwenden kann?
Das ModelMultipleChoiceFilter
konstruiert eine OR-Abfrage aus Q-Objekten. Wenn Sie also eine Abfragezeichenfolge wie /api/mymodel?m2m=a&m2m=b
haben, erhalten Sie am Ende einen Filteraufruf wie
MyModel.objects.filter(Q(m2m='a') | Q(m2m='b'))
Mit der Version 2.1 wird lookup_expr
jetzt auf jedes Q-Objekt angewendet, sodass Sie am Ende erhalten würden
MyModel.objects.filter(Q(m2m__in='a') | Q(m2m__in='b'))
Das obige ist ungültig und würde kaputt gehen, aber es ist sinnvoll für contains
und andere Lookups, die mit Einzelwerten arbeiten sollen.
Kurz gesagt, alles, was Sie hier tun müssen, ist die exact
-Suche für Ihr m2m-Feld zu verwenden.
Ich denke, das Todo hier ist:
BaseCSVWidget
mit SelectMultiple
$ kompatibel, indem Sie den Wert zurückgeben, wenn es sich bereits um eine Liste handelt. Oder wenn es nicht kompatibel sein sollte, sollten wir zumindest einen nützlichen Fehler auf init liefern.Meta.fields
für m2m. Das Generieren einer in
-Suche nach ModelMultipleChoiceFilter
ist unsinnig. Wir sollten auch testen, was bei anderen Lookups wie isnull
passiert, die einen booleschen Wert erwarten.Ja, das sieht immer noch nicht nach einem Fehler aus, aber wie das alles funktioniert, ist unterdokumentiert, denke ich ...
Ich hatte gerade diesen Fehler und seine Erklärung ist in diesem Thread begraben, um es zusammenzufassen und zukünftigen Lesern eine lange Suche zu ersparen:
ManyToMany
-Felder, die in filterset_fields
der Viewsets deklariert sind, dürfen nicht in
enthalten
Eine Warnung zur Laufzeit wäre sehr wünschenswert.
@marcosox Gute Idee. Gerne sehe ich mir eine PR an, die das hinzufügt!
Hilfreichster Kommentar
Ich hatte gerade diesen Fehler und seine Erklärung ist in diesem Thread begraben, um es zusammenzufassen und zukünftigen Lesern eine lange Suche zu ersparen:
ManyToMany
-Felder, die infilterset_fields
der Viewsets deklariert sind, dürfen nichtin
enthaltenEine Warnung zur Laufzeit wäre sehr wünschenswert.