J'ai rencontré …
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'
et a constaté que le code à…
https://github.com/carltongibson/django-filter/blob/1f47e36b614724a8735e0457fa511dcaf5448481/django_filters/widgets.py#L195 -L202
… n'est pas robuste en ce qui concerne super().value_from_datadict(data, files, name)
retournant une liste. J'ai besoin de déboguer davantage, mais peut-être savez-vous déjà ce qui se passe ici ?
Salut @moseb. Pouvez-vous coller le code FilterSet que vous utilisez ? Les dernières lignes de la trace sont suffisantes pour déterminer pourquoi vous rencontrez cette exception.
Retraçage complet :
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
C'est en parcourant une liste où django-rest-framework génère le code.
Salut @moseb. Pouvez-vous coller le code FilterSet que vous utilisez ?
Pour être honnête, je n'en ai pas encore trouvé dans cette zone du code. Il pourrait être tout par DRF. Pas encore sûr.
Je suis conscient que mon rapport de bogue n'est pas idéal, mais c'est le meilleur que j'ai en ce moment. Pardon!
Votre vue API doit avoir soit filterset_class
ou filterset_fields
, ou si vous utilisez une ancienne version de django-filter, filter_class
et filter_fields
.
J'ai trouvé l'utilisation de filter_class
- donc je suppose que vous venez de m'aider à trouver que la migration vers django-filter 2.0 n'a pas été correctement effectuée jusqu'à la fin. Cool!
Y a-t-il quelque chose qui empêche django-filter de détecter les restes pré-2.x et d'en avertir, conceptuellement? Est-ce qu'il avertit mais je l'ai manqué? Un avertissement de code à ce sujet serait-il un ajout bienvenu pour une demande d'extraction ?
La v2.0 a supprimé de nombreux avertissements de dépréciation existants, vous pouvez donc essayer d'exécuter votre suite de tests avec la v1.0 puis la v1.1 de django-filter.
En supposant que cela se résoudra lors de la mise à jour. Revenez sinon.
Il y a maintenant une démo reproductible du problème sur https://github.com/moseb/django-filter-issue-1103-demo. Merci d'envisager de rouvrir ce sujet. Merci!
Ah, cela est lié au fait ModelMultipleChoiceFilter
n'est pas compatible avec le mixin CSV, ainsi qu'à la recherche in
. Deux questions distinctes mais liées ici.
Vous ne devriez pas avoir besoin d'une recherche in
pour les champs m2m, car le filtre à choix multiples fournit déjà un comportement similaire.
Salut!
Ah, cela est lié au fait
ModelMultipleChoiceFilter
n'est pas compatible avec le mixin CSV, ainsi qu'à la recherchein
. Deux questions distinctes mais liées ici.
Existe-t-il des tickets sur GitHub pour ces problèmes ?
Il semble que rendre BaseCSVWidget.value_from_datadict
plus robuste, comme mentionné ci-dessus, ne résoudra pas le problème ? (Je ne comprends pas encore tout à fait le problème.)
Vous ne devriez pas avoir besoin d'une recherche
in
pour les champs m2m, car le filtre à choix multiples fournit déjà un comportement similaire.
in
permet de vérifier plusieurs valeurs sur exact
. Si je ne peux pas utiliser ìn
, comment puis-je vérifier plusieurs valeurs ?
PS : Peut-on rouvrir ce ticket ?
Il semble que rendre
BaseCSVWidget.value_from_datadict
plus robuste, comme mentionné ci-dessus, ne résoudra pas le problème ? (Je ne comprends pas encore tout à fait le problème.)
Peut-être. Si la valeur est déjà une liste, il suffit de continuer et de renvoyer cette liste. Cela dit, je ne pense pas qu'il soit logique de mélanger le comportement CSV avec le widget SelectMultiple
.
in
permet de vérifier plusieurs valeurs surexact
. Si je ne peux pas utiliserìn
, comment puis-je vérifier plusieurs valeurs ?
Le ModelMultipleChoiceFilter
construit une requête OU à partir d'objets Q. Donc, si vous avez une chaîne de requête comme /api/mymodel?m2m=a&m2m=b
, vous vous retrouverez avec un appel de filtre comme
MyModel.objects.filter(Q(m2m='a') | Q(m2m='b'))
Avec la version 2.1, le lookup_expr
est maintenant appliqué à chaque objet Q, donc vous vous retrouveriez avec
MyModel.objects.filter(Q(m2m__in='a') | Q(m2m__in='b'))
Ce qui précède n'est pas valide et ne fonctionnerait pas, mais cela a du sens pour contains
et d'autres recherches destinées à fonctionner avec des valeurs uniques.
Donc, en bref, tout ce que vous avez à faire ici est d'utiliser la recherche exact
pour votre champ m2m.
Je pense que le todo ici est:
BaseCSVWidget
compatible avec SelectMultiple
en retournant la valeur si c'est déjà une liste. Ou s'il ne devrait pas être compatible, nous devrions au moins fournir une erreur utile sur init.Meta.fields
pour m2m. Générer une recherche in
pour ModelMultipleChoiceFilter
est absurde. Nous devrions également tester ce qui se passe pour d'autres recherches comme isnull
, qui attend un booléen.Oui, cela ne ressemble toujours pas à un bogue , mais la façon dont tout cela fonctionne est sous-documentée, je suppose ...
Je viens d'avoir cette erreur et son explication est enterrée dans ce fil, donc pour récapituler et économiser une longue recherche pour les futurs lecteurs :
Les champs ManyToMany
déclarés dans les ensembles de vues filterset_fields
ne doivent pas contenir in
Un avertissement lors de l'exécution serait très apprécié.
@marcosox Bonne idée. Heureux de regarder un PR ajoutant cela !
Commentaire le plus utile
Je viens d'avoir cette erreur et son explication est enterrée dans ce fil, donc pour récapituler et économiser une longue recherche pour les futurs lecteurs :
Les champs
ManyToMany
déclarés dans les ensembles de vuesfilterset_fields
ne doivent pas contenirin
Un avertissement lors de l'exécution serait très apprécié.