Django-filter: (2.0) FilterView selalu mengembalikan QuerySet kosong untuk FilterSet yang tidak terikat.

Dibuat pada 29 Jun 2018  ·  19Komentar  ·  Sumber: carltongibson/django-filter

Saya memiliki tampilan, AccountList , yang mencoba membuat tabel Django_table2. Kode sumber tampilan:

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

Tampilan ini sedang menggunakan filterset ini (dari 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)

Menggunakan templat ini:

{% if filter %}
    <form action="" method="get" class="form form-inline">
        {{ filter.form.as_p }}
        <input type="submit" />
    </form>
{% endif %}

{% render_table object_list %}

{% endblock %}

Ini saya dari urls.py saya

path('', login_required(AccountList.as_view())),

Ketika saya mengunjungi halaman saya, 127.0.0.1:8000 , saya melihat bahwa filter tidak disetel:
enter image description here

Tetapi kemudian jika saya melakukannya 127.0.0.1:8000?page=1 , saya melihat filter diinisialisasi dengan benar:

enter image description here

Apa yang menyebabkan filter saya tidak memiliki nilai default ketika saya tidak menambahkan page=1 ke url saya?

Bug

Komentar yang paling membantu

Yap - memulai PR tetapi harus menunda pekerjaan open source saya. Saya harus bisa melanjutkan di mana saya tinggalkan segera.

Semua 19 komentar

Coba gunakan nilai boolean False aktual alih-alih nilai string 'False' .

Jadi ketika saya mencoba yang berikut ini:

is_suspended = django_filters.BooleanFilter(name='is_suspended', initial=False)
is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial=False)

Beginilah cara filter dirender pada 127.0.0.1:8000/

image

Meskipun filter diberikan dengan nilai yang tepat, filter tidak berpengaruh karena saya masih dapat melihat akun yang ditangguhkan atau ditinggalkan.

Selain itu, ketika saya mengunjungi halaman 2 dengan menekan tombol 2 di bagian bawah, saya mendapatkan http://127.0.0.1:8000/?page=2 dengan filter diatur ulang ke Unknown .

image

Apakah Anda melihat alasan mengapa?

Maaf - tidak ada yang jelas muncul dalam pikiran.

Untuk masalah pertama, saya akan merekomendasikan melihat kueri SQL yang dihasilkan. Pastikan filter suspended dan abandoned benar-benar diterapkan.
Untuk masalah kedua, saya akan memeriksa data yang masuk. Ada kemungkinan bahwa nilai yang tidak valid diberikan ke filter suspended dan abandoned saat mengubah halaman.

Saya memasukkan beberapa pernyataan cetak dan saya menemukan yang berikut:

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)

Jadi sepertinya data adalah None . Akankah Anda mengetahui mengapa tampilan berbasis kelas saya tidak meneruskan data ke AccountFilter ?

Hm. Argumen data harus selalu disediakan oleh FilterView .

https://github.com/carltongibson/django-filter/blob/b1f1c6592ef64a2172ec39040607a9c0b0714140/django_filters/views.py#L39 -L46

Apakah data kosong untuk halaman pertama dan kedua?

Ini tidak dapat dialamatkan sebagaimana adanya. Menutup info yang cukup tertunda untuk mengidentifikasi masalah.

Masalah yang sama di sini setelah memutakhirkan ke 2.0. Halaman default atau filter kosong harus ada di URL untuk mendapatkan hasilnya. Apakah ini setidaknya didokumentasikan di suatu tempat?

Masih membutuhkan lebih banyak info untuk dapat mereproduksi ...

page ? Bukankah ini berkaitan dengan pagination Anda, daripada Filter Django?

Info apa yang dibutuhkan sebenarnya? Upgrade ke 2.0 mengarah ke perilaku yang dijelaskan. Menurunkan versi ke 1.1.0 membuat semuanya kembali normal. Saya mencoba menyederhanakan tampilan dan filter set seminimal mungkin, perilakunya tetap ada, jadi sepertinya ini cukup mudah untuk direproduksi.

@moorchegue , contoh kasus uji atau proyek uji minimal yang menunjukkan masalah ini akan sangat membantu.

Sepertinya masalahnya ada pada apa pun yang menyediakan logika pagination Anda. Ya, mungkin ada beberapa ketidakcocokan dengan versi baru, tetapi masalah debug di paket lain berada di luar jangkauan. Anda perlu mendemonstrasikan bug di Django Filter agar ada apapun yang bisa kita lakukan di sini.

Oke, jadi masalahnya di sini adalah dengan metode is_valid() yang diperkenalkan sebagai bagian dari #788.

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/django_filters/filterset.py#L202 -L206

Ini secara otomatis mengembalikan False ketika data adalah None .

Dalam tampilan kami kemudian mengatur object_list ke qs.none() .

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/django_filters/views.py#L80 -L83

Oleh karena itu perilaku yang diamati.

Pengujian untuk ini tidak gagal karena template pengujian menggunakan filter.qs daripada object_list .

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/tests/templates/tests/book_filter.html#L3 -L5

Solusi langsungnya adalah menyetel strict = False pada filterset Anda. Ini memiliki konsekuensi bahwa parameter filter tidak valid yang sebenarnya akan mengarah ke pemfilteran sebagian daripada menampilkan hasil kosong, tetapi seharusnya bisa diterapkan untuk saat ini. (Lebih baik mengesampingkan logika tampilan get tentu saja ...)

Kami akan memikirkan dan meningkatkan penanganan untuk kasus yang tidak terikat.

Hm. Kekurangan utama di sini adalah perbedaan antara object_list dan .qs FilterSet. Memindahkan perilaku ketat kembali ke FilterSet.qs akan memperbaikinya.

Selain itu, tidak ada penanganan yang ketat/tidak ketat untuk backend DRF.

Saya akan menghapus ini.

@rpkilby Apakah ada kemajuan dalam masalah ini?

Yap - memulai PR tetapi harus menunda pekerjaan open source saya. Saya harus bisa melanjutkan di mana saya tinggalkan segera.

Perhatikan bahwa solusinya adalah dengan mengatur strict = False pada FilterMixin turunan Anda (mungkin View .

Tidak bisakah Anda mengubah kondisi untuk mengembalikan qs jika bentuk tidak terbatas?

misalnya

-        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

Terima kasih.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat