me encontré con…
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'
y encontré que el código en...
https://github.com/carltongibson/django-filter/blob/1f47e36b614724a8735e0457fa511dcaf5448481/django_filters/widgets.py#L195 -L202
… no es robusto con respecto a super().value_from_datadict(data, files, name)
devolviendo una lista. Necesito depurar esto más, pero tal vez ya sabes lo que está pasando aquí.
Hola @moseb. ¿Puedes pegar el código FilterSet que estás usando? Las últimas líneas del seguimiento son suficientes para determinar por qué se produjo esta excepción.
Rastreo completo:
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 de navegar por una lista donde django-rest-framework genera el código.
Hola @moseb. ¿Puedes pegar el código FilterSet que estás usando?
Para ser honesto, todavía no he encontrado ninguno en esa área del código. Podría ser todo por DRF. No estoy seguro todavía.
Soy consciente de que mi informe de error no es el ideal, pero es el mejor que tengo en este momento. ¡Lo siento!
Su vista de API debe tener filterset_class
o filterset_fields
, o si está usando una versión anterior de django-filter, filter_class
y filter_fields
.
Encontré el uso de filter_class
, así que supongo que me ayudó a encontrar que la migración a django-filter 2.0 no se realizó correctamente hasta el final. ¡Frio!
¿Hay algo que impida que django-filter detecte los restos anteriores a 2.x y advierta sobre ellos, conceptualmente? ¿Avisa pero me lo perdí? ¿Sería una advertencia de código sobre estos una adición bienvenida para una solicitud de extracción?
v2.0 eliminó muchas de las advertencias de obsolescencia existentes, por lo que puede intentar ejecutar su conjunto de pruebas contra v1.0 y luego v1.1 de django-filter.
Suponiendo que esto se resolverá solo cuando actualice. Vuelve si no.
Hay una demostración reproducible del problema ahora en https://github.com/moseb/django-filter-issue-1103-demo. Considere volver a abrir este problema. ¡Gracias!
Ah, esto está relacionado con que ModelMultipleChoiceFilter
no es compatible con la combinación de CSV, así como con la búsqueda in
. Dos temas separados pero relacionados aquí.
No debería necesitar una búsqueda de in
para campos m2m, ya que el filtro de opción múltiple ya proporciona un comportamiento similar.
¡Hola!
Ah, esto está relacionado con que
ModelMultipleChoiceFilter
no es compatible con la combinación de CSV, así como con la búsquedain
. Dos temas separados pero relacionados aquí.
¿Existen tickets en GitHub para estos problemas?
¿Parece que hacer BaseCSVWidget.value_from_datadict
más robusto como se mencionó anteriormente por sí solo no solucionará el problema? (Todavía no entiendo completamente el problema).
No debería necesitar una búsqueda de
in
para campos m2m, ya que el filtro de opción múltiple ya proporciona un comportamiento similar.
in
permite comparar múltiples valores por encima exact
. Si no puedo usar ìn
, ¿cómo compruebo si hay varios valores?
PD: ¿Podemos reabrir este ticket?
¿Parece que hacer
BaseCSVWidget.value_from_datadict
más robusto como se mencionó anteriormente por sí solo no solucionará el problema? (Todavía no entiendo completamente el problema).
Posiblemente. Si el valor ya es una lista, debería continuar y devolver esa lista. Dicho esto, no creo que tenga sentido mezclar el comportamiento CSV con el widget SelectMultiple
.
in
permite verificar múltiples valores sobreexact
. Si no puedo usarìn
, ¿cómo compruebo si hay varios valores?
El ModelMultipleChoiceFilter
construye una consulta OR a partir de objetos Q. Entonces, si tiene una cadena de consulta como /api/mymodel?m2m=a&m2m=b
, terminaría con una llamada de filtro como
MyModel.objects.filter(Q(m2m='a') | Q(m2m='b'))
Con la versión 2.1, el lookup_expr
ahora se aplica a cada objeto Q, por lo que terminaría con
MyModel.objects.filter(Q(m2m__in='a') | Q(m2m__in='b'))
Lo anterior no es válido y se rompería, sin embargo, tiene sentido para contains
y otras búsquedas que están destinadas a trabajar con valores únicos.
Entonces, en resumen, todo lo que necesita hacer aquí es usar la búsqueda exact
para su campo m2m.
Creo que el todo aquí es:
BaseCSVWidget
sea compatible con SelectMultiple
devolviendo el valor si ya es una lista. O si no debería ser compatible, al menos deberíamos proporcionar un error útil en init.Meta.fields
por m2m. Generar una búsqueda de $ in
para ModelMultipleChoiceFilter
tiene sentido. También deberíamos probar qué sucede con otras búsquedas como isnull
, que espera un valor booleano.Sí, esto todavía no parece un error , pero supongo que cómo funciona todo está poco documentado...
Acabo de tener este error y su explicación está enterrada en este hilo, así que para recapitular y ahorrar una larga búsqueda para futuros lectores:
Los campos ManyToMany
declarados en los conjuntos de vistas filterset_fields
no deben contener in
Una advertencia en tiempo de ejecución sería muy apreciada.
@marcosox Buena idea. ¡Feliz de ver un PR agregando eso!
Comentario más útil
Acabo de tener este error y su explicación está enterrada en este hilo, así que para recapitular y ahorrar una larga búsqueda para futuros lectores:
Los campos
ManyToMany
declarados en los conjuntos de vistasfilterset_fields
no deben contenerin
Una advertencia en tiempo de ejecución sería muy apreciada.