J'ai une vue, AccountList
, qui essaie de rendre une table django_table2. Le code source de la vue :
class AccountList(SingleTableMixin, FilterView):
model = Account
table_class = AccountTable
template_name = 'accounts/account_list.html'
context_table_name = 'object_list'
ordering = ['vps']
filterset_class = AccountFilter
Cette vue utilise actuellement cet ensemble de filtres (de django_filters) :
import django_filters
from accounts.models import Account
class AccountFilter(django_filters.FilterSet):
class Meta:
model = Account
fields = ['is_suspended', 'is_abandoned']
is_suspended = django_filters.BooleanFilter(name='is_suspended', initial='False')
is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial='False')
def __init__(self, data=None, *args, **kwargs):
# if filterset is bound, use initial values as defaults
if data is not None:
# get a mutable copy of the QueryDict
data = data.copy()
for name, f in self.base_filters.items():
initial = f.extra.get('initial')
# filter param is either missing or empty, use initial as default
if not data.get(name) and initial:
data[name] = initial
super().__init__(data, *args, **kwargs)
En utilisant ce modèle :
{% if filter %}
<form action="" method="get" class="form form-inline">
{{ filter.form.as_p }}
<input type="submit" />
</form>
{% endif %}
{% render_table object_list %}
{% endblock %}
Ceci est mon de mon urls.py
path('', login_required(AccountList.as_view())),
Lorsque je visite ma page, 127.0.0.1:8000
, je constate que les filtres ne sont pas définis :
Mais si je fais 127.0.0.1:8000?page=1
, je vois que les filtres sont initialisés correctement :
Essayez d'utiliser une valeur booléenne False
réelle au lieu de la valeur de chaîne 'False'
.
Alors quand j'ai essayé ce qui suit:
is_suspended = django_filters.BooleanFilter(name='is_suspended', initial=False)
is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial=False)
Voici comment les filtres sont rendus sur 127.0.0.1:8000/
Même si le filtre a été rendu avec les bonnes valeurs, le filtre n'a eu aucun effet car je peux toujours voir les comptes suspendus ou abandonnés.
De plus, lorsque je visite la page 2 en appuyant sur le bouton 2
en bas, j'arrive à http://127.0.0.1:8000/?page=2
avec les filtres réinitialisés à Unknown
.
Voyez-vous une raison pour laquelle?
Désolé, rien d'évident ne me vient à l'esprit.
Pour le premier problème, je recommanderais de regarder la requête SQL résultante. Assurez-vous que les filtres suspended
et abandoned
sont effectivement appliqués.
Pour le deuxième problème, je vérifierais les données entrantes. Il est possible qu'une valeur non valide soit fournie aux filtres suspended
et abandoned
lors du changement de page.
J'ai inséré quelques déclarations d'impression et j'ai trouvé ce qui suit :
def __init__(self, data=None, *args, **kwargs):
if data is not None: # 1
data = data.copy()
for name, f in self.base_filters.items():
initial = f.extra.get('initial')
# filter param is either missing or empty, use initial as default
if not data.get(name) and initial:
data[name] = initial
super(BaseFilterSet, self).__init__(data, *args, **kwargs)
Il semble donc que data
soit None
. Saurez-vous pourquoi ma vue basée sur les classes ne passe pas data
dans AccountFilter
?
Hum. L'argument data
doit toujours être fourni par FilterView
.
data
vide pour la première et la deuxième page ?
Ce n'est pas adressable tel quel. Fermeture en attendant suffisamment d'informations pour identifier un problème.
Même problème ici après la mise à niveau vers 2.0. Une page par défaut ou un filtre vide doit être présent dans l'URL pour obtenir les résultats. Est-ce au moins documenté quelque part ?
Encore besoin de plus d'infos pour pouvoir reproduire...
page
? N'est-ce pas lié à votre pagination plutôt qu'à Django Filter ?
Quelles informations sont nécessaires exactement ? La mise à niveau vers 2.0 conduit au comportement décrit. La rétrogradation vers la 1.1.0 ramène tout à la normale. J'ai essayé de simplifier la vue et le jeu de filtres pour qu'ils soient aussi minimalistes que possible, le comportement persiste, il semble donc que cela devrait être assez facile à reproduire.
@moorchegue , un exemple minimal de cas de test ou de projet de test qui démontre le problème serait utile.
Il semble également que le problème concerne tout ce qui fournit votre logique de pagination. Oui, il peut y avoir une certaine incompatibilité avec la nouvelle version, mais les problèmes de débogage dans d'autres packages sont hors de portée. Vous devez démontrer un bogue dans Django Filter pour que nous puissions faire quoi que ce soit ici.
OK, donc le problème ici est avec la méthode is_valid()
introduite dans le cadre de #788.
Cela renvoie automatiquement False
lorsque data
vaut None
.
Dans la vue, nous définissons ensuite object_list
sur qs.none()
.
D'où le comportement observé.
Le test pour cela n'échoue pas car le modèle de test utilise filter.qs
plutôt que object_list
.
La solution immédiate consiste à définir strict = False
sur votre ensemble de filtres. Cela a pour conséquence que les paramètres de filtre non valides réels conduiront à un filtrage partiel plutôt que d'afficher des résultats vides, mais cela devrait être réalisable pour le moment. (Mieux vaut remplacer la logique de la vue get
bien sûr...)
Nous allons réfléchir et améliorer le traitement du cas non relié.
Hum. Le déficit primaire est ici la disparité entre la vue de object_list
et du filterSet .qs
. Le retour du comportement strict au FilterSet.qs
résoudrait ce problème.
De plus, il n'y a pas de gestion stricte/non stricte pour le backend DRF.
Je vais WIP ça.
@rpkilby Y a-t-il des progrès sur ce problème ?
Oui, j'ai commencé les relations publiques mais j'ai dû suspendre mon travail open source. Je devrais pouvoir reprendre là où je m'étais arrêté assez rapidement.
Notez que la solution de contournement devrait être de définir strict = False
sur votre descendant FilterMixin
(probablement le View
.
Ne pouvez-vous pas simplement changer la condition pour retourner le qs en cas de forme illimitée ?
par exemple
- if self.filterset.is_valid() or not self.get_strict():
+ if not self.filterset.is_bound or self.filterset.is_valid() or not self.get_strict():
https://github.com/carltongibson/django-filter/pull/1007
Merci.
Commentaire le plus utile
Oui, j'ai commencé les relations publiques mais j'ai dû suspendre mon travail open source. Je devrais pouvoir reprendre là où je m'étais arrêté assez rapidement.