Django-tables2: Baris tabel yang digandakan setelah diurutkan berdasarkan tajuk kolom

Dibuat pada 3 Agu 2016  ·  32Komentar  ·  Sumber: jieter/django-tables2

Saya mengalami masalah ketika beberapa baris dirender beberapa kali menggantikan baris lainnya. Tabel yang dimaksud digunakan untuk merender dengan sangat baik pada versi sebelumnya dari Django dan Django-tables2. Saya memutakhirkan keduanya secara bersamaan ke versi terbaru masing-masing (Django 1.10, Django-tables2 1.2.4) kemudian masalah ini mulai terjadi.

Lihat gambar ini di sini untuk demonstrasi: http://imgur.com/a/pPRT8

Ketika saya memuat tabel tanpa memilih urutan berdasarkan kolom, saya tidak melihat masalah ini. Setelah saya mengklik tajuk kolom untuk mengubah urutan pengurutan, maka baris diduplikasi.

Sejauh ini saya telah mengidentifikasi bahwa data yang dikirimkan ke objek BoundRows benar, tanpa item duplikat. Namun iterasi melalui baris terikat mengembalikan entri yang digandakan. Jadi sepertinya ada sesuatu yang mengubah objek data saat iterasi berlangsung.

Masalah ini terjadi pada tabel dengan panjang ~150, dan saya belum (belum) dapat mereproduksi masalah ini dengan kumpulan data pengujian yang lebih kecil.

Cuplikan ini menunjukkan kode pengujian yang saya gunakan untuk mempersempit penyebab masalah.

--- a/django_tables2/rows.py
+++ b/django_tables2/rows.py
@@ -8,6 +8,7 @@ from django.utils import six
 from .columns.linkcolumn import BaseLinkColumn
 from .utils import A, AttributeDict, call_with_appropriate, computed_values

+import sys

 class BoundRow(object):
     """
@@ -187,9 +188,17 @@ class BoundRows(object):
     def __init__(self, data, table):
         self.data = data
         self.table = table
+        for d in data:
+            print >>sys.stderr, d
+
+        print >>sys.stderr, "end data"
+

     def __iter__(self):
         for record in self.data:
+            print >>sys.stderr, "__iter__", record
             yield BoundRow(record, table=self.table)
bug

Komentar yang paling membantu

wooo, akhirnya diperbaiki!

Ya, saya akan merilisnya dalam waktu satu jam.

Semua 32 komentar

Mengkristalisasi queryset melalui list() menghentikan masalah yang terjadi:

+++ b/django_tables2/rows.py
@@ -8,6 +8,7 @@ from django.utils import six
 from .columns.linkcolumn import BaseLinkColumn
 from .utils import A, AttributeDict, call_with_appropriate, computed_values

+import sys

 class BoundRow(object):
     """
@@ -187,9 +193,26 @@ class BoundRows(object):
     def __init__(self, data, table):
         self.data = data
         self.table = table


     def __iter__(self):
+        print >>sys.stderr, type(list(self.data.data))

Terima kasih telah melaporkan, casting ke daftar tidak dapat diterima sebagai solusi karena itu tidak akan berfungsi dengan kumpulan data yang lebih besar.

Bisakah anda mencoba untuk menurunkan versi Django-tables2 anda untuk memastikan itu tidak menjadi masalah dengan memperbarui versi Django anda?

Ya jelas bukan solusi - tapi itu mungkin indikasi penyebabnya. Alasan lain casting ke daftar bukanlah solusi yang cocok adalah karena tampaknya tidak selalu menjadi kumpulan kueri yang menyimpan data, dalam hal ini self.data.data tidak akan ada.

@wtfrank , saya mengerti, tetapi itu akan sangat membantu jika Anda dapat memberikan kasus uji yang dapat direproduksi. Apakah Anda mencoba menurunkan versi Django-tables2 ke versi sebelumnya yang Anda gunakan?

Saya pikir saya mengalami masalah yang sama: Di tabel saya, satu baris hilang, dan satu lagi adalah duplikat... Bagi saya ini dimulai dengan versi 1.2.2.
Menurunkan versi ke 1.2.1 "memperbaiki" masalah bagi saya.... Apakah ada informasi yang dapat saya berikan untuk mempermudah pencarian?

Kasus uji minimal akan sangat menyenangkan untuk dimiliki. Kami kemudian dapat menjalankan git bisect untuk menemukan komit yang buruk.

Saya sedang mencari kasus uji saat ini, tetapi anehnya saya tidak dapat mereproduksi masalah di lingkungan pengujian saya ...

Secara lokal (menggunakan ./manage runserver menggunakan sqlite) semuanya baik-baik saja, sementara dalam produksi (menjalankan uwsgi dan mysql) ada masalah dupes ... (kedua lingkungan berjalan pada versi yang sama)

Queryset tidak mengandung dupes.... Tetapi pada saat table.html dirender, queryset kehilangan satu objek dan objek lainnya adalah duplikat...

Kembali kepada Anda segera dengan test case semoga :)

Masalah juga terjadi di versi 1.2.6. Saya pikir ini sth dengan #329 atau #330 tetapi sejauh ini saya tidak dapat menemukan cara untuk memperbaikinya.

Itu hanya berlaku untuk 1.2.6, jadi saya tidak berharap mereka menjadi sumber bug ini.

Maaf, saya tidak dapat memberikan kasus yang dapat direproduksi dengan benar, tetapi saya baru saja mendapatkan masalah ini (atau, setidaknya, saya yakin ini masalah ini) dan dapat mengatakan bahwa itu pasti terjadi antara 1.2.1 dan 1.2.2 .

Setiap kali saya menurunkan versi ke 1.2.1, semuanya terlihat baik-baik saja. Ketika saya memutakhirkan ke 1.2.2 atau lebih tinggi (tentu saja saya sudah mulai dengan 1.2.6 terbaru), saya secara konsisten kehilangan baris pertama (dari tiga yang saya miliki di DB) dan mendapatkan salinan baris lain sebagai gantinya. Misalnya, ketika pada 1.2.1 saya memiliki:

| tanggal | hits | ... |
| --- | --- | --- |
| 2016-10-08 | 123 | ... |
| 07-10-2016 | 321 | ... |
| 2016-10-06 | 0 | ... |

Pada 1.2.2-1.2.6 saya secara konsisten mendapatkan ini sebagai gantinya:

| tanggal | hits | ... |
| --- | --- | --- |
| 2016-10-06 | 0 | ... |
| 07-10-2016 | 321 | ... |
| 06-10-2016 | 0 | ... |

Saya menggunakan Django 1.9.9 pada Python 2.7.12, proyek dimulai menggunakan pydanny/cookiecutter-Django (walaupun banyak dimodifikasi setelah itu), dan kode saya terlihat seperti ini:

class DailySummaryTable(tables.Table):
    class Meta:
        model = DailySummary
        attrs = {"class": "paleblue"}
        empty_text = _("No stats yet")
        fields = ("date", "hits", ...long boring list...)
        # order_by = ("-date",)
        # orderable = False

Meta Model hanya memiliki barang verbose_name{,_plural} , dan tampilannya adalah DetailView yang terlihat seperti ini:

class SourceDetailView(LoginRequiredMixin, DetailView):
    model = Source
    ...
    def get_context_data(self, **kwargs):
        ctx = super(...)
        ctx["stats"] = DailySummaryTable(DailySummary.objects.filter(source=self.object))
        return ctx

Dan ada tiga baris di DB (PostgreSQL 9.6), semuanya memiliki source_id (saya hanya punya satu), jadi semuanya cocok dengan kueri. Anehnya, Jika saya mengganti .filter(source=...) dengan .all() masalahnya sepertinya hilang.

Itu saja yang bisa saya pahami. Semoga membantu. Saya kira, saya akan tetap menggunakan 1.2.1 untuk saat ini :)

Terima kasih telah menunjukkan pengembaraan Anda, saya akan melihat masalah ini nanti.

Saya baru saja mengalami masalah yang sama, mengkristalkan queryset melalui list() juga bukan solusi yang layak di pihak kami.

@op-alex-reid dapatkah Anda mencoba mengubah kasus penggunaan Anda menjadi kasus uji minimal yang dapat direproduksi?

Saya mengalami masalah yang sama (Django==1.9, Django-tables==1.2.3) dengan kode berikut:

class UserPlayerTable(tables.Table):
    actions = tables.LinkColumn('player:my_players_detail', args=[A('slug')],
                                text=_('View / Edit'),
                                verbose_name=_('View / Edit'), empty_values=())
    embed = tables.LinkColumn('player:my_players_embed', args=[A('slug')],
                                text=_('View / Embed now'),
                                verbose_name=_('View / Embed now'), empty_values=())

    class Meta:
        template = 'tables/table.html'
        model = Player
        fields = ('created', 'slug', 'actions', 'embed')
        attrs = {"class": "changeset"}
        order_by = ['-created']
        orderable = False

dan

UserPlayerTable(Player.objects.filter(user=context['impersonate_user']))

Menariknya, ketika saya set orderable = True , masalah tidak terjadi.

Dalam kasus saya, mengkristalkan queryset melalui list() _is_ sebuah opsi (dan perbaikan untuk saat ini), karena hanya ada paling banyak 5 baris dalam tabel.

Terima kasih untuk contohnya!

Saya mencoba mereproduksi ini menggunakan kode ini:

class Player(models.Model):
    person = models.ForeignKey(Person)
    created = models.DateTimeField(auto_now_add=True)
    score = models.PositiveIntegerField()

def test_issue_361(per_page=5):

    bob = Person.objects.create(first_name='Bob', last_name='Builder')
    eve = Person.objects.create(first_name='Eve', last_name='Dropper')

    for i in range(10):
        Player.objects.create(person=bob, score=randint(0, 200))
        Player.objects.create(person=eve, score=randint(200, 400))
        Player.objects.create(person=bob, score=5)
        Player.objects.create(person=eve, score=5)

    class UserPlayerTable(tables.Table):
        class Meta:
            model = Player
            fields = ('person.name', 'score',)
            order_by = ['-score']
            orderable = False

    queryset = Player.objects.filter(score=5)

    table = UserPlayerTable(queryset)
    RequestConfig(request, paginate={'per_page': per_page}).configure(table)
    html = table.as_html(request)

    # count the number of rows, subtract one for the header
    assert (html.count('<tr') - 1) == per_page

tetapi ini tidak menghasilkan baris yang digandakan ...

Saya mengalami masalah yang sama hari ini. Saya menggunakan Django-tables2==1.2.9 dalam proyek Django==1.10, di mana saya juga menggunakan Django-filters==1.0.1.

Cukup menarik penggandaan baris di meja saya hanya terjadi jika

  1. ada banyak entri untuk ditampilkan
    (jadi jika saya mengaktifkan pagination dengan 25 catatan per halaman semuanya baik-baik saja, tetapi jika saya menampilkan dataset lengkap saya mendapatkan beberapa entri yang identik)

  2. tabel diurutkan berdasarkan kolom yang berisi non-string
    (semuanya baik-baik saja jika saya mengurutkan berdasarkan kolom yang berisi misalnya nama, tetapi mengurutkan berdasarkan kolom dengan tanggal, int, atau bool menghasilkan masalah)

Menurunkan versi ke 1.2.1 memecahkan masalah, tetapi itu sebenarnya bukan pilihan.
Lebih jauh lagi, penipuan tampaknya ditampilkan sebagai ganti dan bukan di samping entri nyata, karena jumlah {{filter.qs.count}} adalah sebagaimana mestinya.

Saya harap ini sedikit membantu untuk menyelesaikan masalah, karena selain itu saya sangat menikmati bekerja dengan Django-tables2.

Terima kasih untuk semua pekerjaan Anda!

@n0ctua terima kasih!

Bisakah Anda melihat kueri persis yang dieksekusi dan mungkin membagikannya di sini?

Saya baru saja mengalami masalah ini juga dan mengerti mengapa itu terjadi pada saya, jadi saya pikir saya akan memposting karena saya curiga orang lain memilikinya karena alasan yang sama. _(Meskipun, saya belum mencoba dengan versi lain dari Django-tables2, jadi saya mungkin salah karena saya tidak mengerti mengapa itu akan menghentikan ini terjadi ... Meskipun ... sebenarnya memikirkannya saya akan berhipotesis bahwa ini adalah karena dalam versi yang lebih lama tabel non-paginasi menjalankan satu kueri terhadap db alih-alih kueri untuk setiap baris – detail lebih lanjut tentang ini di bawah...)_

Itu karena _SQL order by pada bidang non-unik tidak deterministik_ jadi ketika digabungkan dengan top n Anda mendapatkan n baris teratas yang sama berulang kali. (Juga, untuk beberapa alasan ketika saya membuat Table tanpa pagination, itu menghasilkan kueri untuk _setiap_ baris. IE top 1 ).

Saya tidak yakin apa solusi terbaik di sini? Saya pikir satu-satunya cara untuk menjamin ini akan berhasil adalah dengan selalu memiliki order by final berada di bidang yang unik. Idealnya kunci utama? Juga, mungkin perlu menambahkan beberapa catatan ke dokumen yang memperingatkan tentang ini?

Sebagai masalah terpisah tetapi masalah yang benar-benar akan mengurangi seberapa sering hal ini terjadi (dan mempercepat kueri untuk tabel yang tidak diberi halaman) adalah jika alih-alih menjalankan kueri top 1 untuk setiap baris dalam tabel akan hanya menjalankan satu kueri yang mengambil semua hasil.

@intiocean jumlah kueri untuk tabel non-paginasi ini cukup aneh, tidak yakin mengapa ini terjadi, dan itu tidak boleh terjadi. Kasus uji ini menunjukkan masalah:

def test_single_query_for_non_paginated_table(settings):
    '''
    A non-paginated table should not generate a query for each row, but only
    one query to count the rows and one to fetch the rows.
    '''
    from django.db import connection
    settings.DEBUG = True

    for i in range(10):
        Person.objects.create(first_name='Bob %d' % randint(0, 200), last_name='Builder')

    num_queries_before = len(connection.queries)

    class PersonTable(tables.Table):
        class Meta:
            model = Person
            fields = ('first_name', 'last_name')

    table = PersonTable(Person.objects.all())
    request = build_request('/')
    RequestConfig(request, paginate=False).configure(table)
    table.as_html(request)

    # print '\n'.join(q['sql'] for q in connection.queries)
    assert len(connection.queries) - num_queries_before == 2

Saya telah mencoba, tidak berhasil, untuk membuat tes untuk kasus paginasi yang gagal. Saya tidak mengerti mengapa tetapi semuanya tampak berfungsi seperti biasa dalam kasus yang diberi halaman ... Saya pikir saya akan mendapatkan baris yang muncul seolah-olah diduplikasi pada beberapa halaman jika diurutkan berdasarkan bidang yang tidak unik.

@intiocean saya pikir saya memperbaikinya dengan 10f5e968bc10552be0ad02ee566513b5d274d5c5

@jieter Hebat! Saya dapat melihat mengapa itu akan menyelesaikan masalah dengan tabel non-paginasi tetapi masih berpikir bahwa memesan dengan kolom yang tidak unik ketika data tersebar di halaman yang berbeda dapat mengakibatkan baris yang sama muncul di beberapa halaman karena top n ... limit x offset y

Bagaimana menurutmu?

Mirip dengan: http://stackoverflow.com/questions/31736700/duplicate-elements-in-Django-paginate-after-order-by-call

@wtfrank , @intiocean @n0ctua @op-alex-reid @fliphess Saya baru saja mendorong beberapa komit untuk dikuasai yang mungkin memperbaiki ini. Bisakah Anda memverifikasi?

@intiocean Jika itu adalah sumber masalah ini, saya pikir kami hanya dapat memperbaiki masalah ini sebagian dengan mendokumentasikan perilaku ini.

Saya dapat mengonfirmasi bahwa ini memperbaiki tabel non-paginasi @jieter. Ini juga meningkatkan kinerja untuk tabel non-paginasi karena sekarang hanya ada satu kueri, bukan satu untuk setiap baris.

Memeriksa:
Dengan 962f502 dan menyortir berdasarkan kolom 'Catatan' -> duplikasi
image

Dengan f853078 dan mengurutkan berdasarkan kolom 'Catatan' -> tidak ada duplikasi
image

Adakah kemungkinan Anda bisa melakukan rilis @jieter?

wooo, akhirnya diperbaiki!

Ya, saya akan merilisnya dalam waktu satu jam.

dirilis 1.4.0

Luar biasa, terima kasih @jieter!

@jieter dan @intiocean terima kasih banyak untuk memperbaiki ini! Bekerja dengan sempurna sekarang.

Hai, saya baru saja mengalami masalah ini pada versi 1.21.2 dan Django==2.0.6. Berkat komentar intiocean , perbaiki dengan mengatur pemesanan tambahan dengan 'pk'.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

blite picture blite  ·  3Komentar

mpasternak picture mpasternak  ·  9Komentar

foldedpaper picture foldedpaper  ·  6Komentar

brianmay picture brianmay  ·  6Komentar

applegrew picture applegrew  ·  17Komentar