django_table2テーブルをレンダリングしようとしているビューAccountList
があります。 ビューのソースコード:
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
このビューは現在、(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)
このテンプレートの使用:
{% if filter %}
<form action="" method="get" class="form form-inline">
{{ filter.form.as_p }}
<input type="submit" />
</form>
{% endif %}
{% render_table object_list %}
{% endblock %}
これは私のurls.pyからのものです
path('', login_required(AccountList.as_view())),
自分のページ127.0.0.1:8000
にアクセスすると、フィルターが設定されていないことがわかります。
しかし、 127.0.0.1:8000?page=1
を実行すると、フィルターが正しく初期化されていることがわかります。
文字列値'False'
代わりに、実際のFalse
ブール値を使用してみてください。
だから私が以下を試したとき:
is_suspended = django_filters.BooleanFilter(name='is_suspended', initial=False)
is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial=False)
これは、フィルターが127.0.0.1:8000/
レンダリングされる方法です。
フィルタが正しい値でレンダリングされたとしても、一時停止または放棄されたアカウントを確認できるため、フィルタは効果がありませんでした。
さらに、下部にある2
ボタンを押してページ2にアクセスすると、フィルターがUnknown
リセットされた状態でhttp://127.0.0.1:8000/?page=2
に到達します。
理由はわかりますか?
申し訳ありませんが、明らかなことは何も思い浮かびません。
最初の問題については、結果のSQLクエリを確認することをお勧めします。 suspended
およびabandoned
フィルターが実際に適用されていることを確認してください。
2番目の問題では、受信データを確認します。 ページを変更するときに、 suspended
およびabandoned
フィルターに無効な値が指定されている可能性があります。
いくつかのprintステートメントを挿入したところ、次のことがわかりました。
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)
したがって、 data
はNone
です。 私のクラスベースのビューがdata
をAccountFilter
渡さない理由を知っていますか?
うーん。 data
引数は、常にFilterView
指定する必要があります。
1ページ目と2ページ目の両方でdata
空ですか?
これはそのままでは対処できません。 問題を特定するのに十分な情報が保留中です。
2.0にアップグレードした後も同じ問題が発生します。 結果を取得するには、デフォルトページまたは空のフィルターのいずれかがURLに存在する必要があります。 これは少なくともどこかに文書化されていますか?
再現するには、さらに多くの情報が必要です...
page
? これは、Django Filterではなく、ページ付けと関係がありませんか?
正確にどのような情報が必要ですか? 2.0にアップグレードすると、説明されている動作になります。 1.1.0にダウングレードすると、すべてが正常に戻ります。 ビューとフィルターセットをできるだけ最小限に単純化しようとしましたが、動作は持続するため、これはかなり簡単に再現できるはずです。
@moorchegue 、問題を実証する最小限のサンプルテストケースまたはテストプロジェクトが役立ちます。
また、問題はページ付けロジックを提供しているものにあるようです。 はい、新しいバージョンとの互換性がない可能性がありますが、他のパッケージのデバッグの問題は範囲外です。 ここでできることを行うには、DjangoFilterのバグを示す必要があります。
さて、ここでの問題は、#788の一部として導入されたis_valid()
メソッドにあります。
data
がNone
場合、これは自動的にFalse
返します。
ビューでは、 object_list
をqs.none()
ます。
したがって、観察された動作。
このためのテストは、テストテンプレートを使用しているので、失敗していませんfilter.qs
ではなくobject_list
。
差し迫った回避策は、フィルターセットにstrict = False
を設定することです。 これは、実際の無効なフィルターパラメータが空の結果を表示するのではなく、部分的なフィルタリングにつながるという結果をもたらしますが、今のところは機能するはずです。 (もちろん、ビューget
ロジックをオーバーライドすることをお勧めします...)
バインドされていないケースの処理について考え、改善します。
うーん。 ここでの主な欠点は、ビューのobject_list
とFilterSetの.qs
間の不一致です。 厳密な動作をFilterSet.qs
戻すと、それが修正されます。
さらに、DRFバックエンドには厳密/非厳密な処理はありません。
これを拭きます。
@rpkilbyこの問題に進展はありますか?
うん-PRを始めたが、私のオープンソースの仕事を保留にしなければならなかった。 中断したところからすぐに再開できるはずです。
回避策は、 FilterMixin
子孫(おそらくView
strict = False
を設定することであることに注意してください。
無制限のフォームの場合にqsを返すように条件を変更することはできませんか?
例えば
- 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
ありがとう。
最も参考になるコメント
うん-PRを始めたが、私のオープンソースの仕事を保留にしなければならなかった。 中断したところからすぐに再開できるはずです。