Django-tables2: 按列标题排序后重复的表格行

创建于 2016-08-03  ·  32评论  ·  资料来源: jieter/django-tables2

我遇到了一些行代替其他行多次呈现的问题。 有问题的表格曾经在 django 和 django-tables2 的早期版本上完美呈现。 我同时将它们升级到每个的最新版本(django 1.10,django-tables2 1.2.4)然后这个问题开始发生。

在此处查看此图像以进行演示: http :

当我加载表格而不按列选择排序顺序时,我没有看到这个问题。 单击列标题以更改排序顺序后,行将被复制。

到目前为止,我已经确定传递给 BoundRows 对象的数据是正确的,没有重复的项目。 但是,遍历绑定行会返回重复的条目。 因此,在进行迭代时,似乎某些东西可能正在更改数据对象。

这个问题发生在长度约为 150 的表上,我还没有(还)能够用较小的测试数据集重现这个问题。

此代码段显示了我用来缩小问题原因的测试代码。

--- 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)

最有用的评论

呜呜,终于修好了!

是的,我会在一个小时内发布。

所有32条评论

通过 list() 将查询集具体化可以阻止问题发生:

+++ 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))

感谢您的报告,不能将强制转换为列表作为解决方案,因为这不适用于更大的数据集。

您可以尝试降级 django-tables2 版本以确保更新 Django 版本没有问题吗?

是的,绝对不是解决方案 - 但它可能表明原因。 强制转换为 list 不是一个合适的解决方案的另一个原因是因为它似乎并不总是一个包含数据的查询集,在这种情况下 self.data.data 将不存在。

@wtfrank ,我明白了,但如果你能提供一个可重现的测试用例,它真的会有所帮助。 您是否尝试将 django-tables2 降级到您使用的先前版本?

我想我遇到了同样的问题:在我的表中,缺少一行,而另一行是重复的......对我来说,这是从 1.2.2 版开始的。
降级到 1.2.1 "fixxes" 对我来说是问题.... 有没有我可以提供的信息使搜索更容易?

一个最小的测试用例会非常好。 然后我们可以运行 git bisect 来找到错误的提交。

我目前正在研究一个测试用例,但奇怪的是我无法在我的测试环境中重现这个问题......

在本地(使用 ./manage runserver 使用 sqlite)一切正常,而在生产中(运行 uwsgi 和 mysql)存在欺骗问题......(两种环境都运行在相同的版本上)

查询集不包含任何重复......但是在呈现 table.html 时,查询集缺少一个对象,而另一个对象是重复的......

希望尽快通过测试用例回复您:)

该问题也在 1.2.6 版本中出现。 我认为这是#329 或#330 的问题,但到目前为止我找不到修复它的方法。

这些仅适用于 1.2.6,因此我不希望它们成为此错误的来源。

抱歉,我无法提供适当的可重现案例,但我刚刚遇到了这个问题(或者,至少,我相信是这个问题)并且可以看出它肯定发生在 1.2.1 和 1.2.2 之间.

每当我降级到 1.2.1 时,一切看起来都很好。 当我升级到 1.2.2 或更高版本时(当然,我从最新的 1.2.6 开始),我总是丢失第一行(我在 DB 中拥有的三行)并获得另一个副本而不是它。 例如,在 1.2.1 上时,我有:

| 日期 | 命中| ... |
| --- | --- | --- |
| 2016-10-08 | 123 | ... |
| 2016-10-07 | 第321话 ... |
| 2016-10-06 | 0 | ... |

在 1.2.2-1.2.6 上,我一直得到这个:

| 日期 | 命中| ... |
| --- | --- | --- |
| 2016-10-06 | 0 | ... |
| 2016-10-07 | 第321话 ... |
| 2016-10-06 | 0 | ... |

我在 Python 2.7.12 上使用 Django 1.9.9,项目是使用 pydanny/cookiecutter-django 启动的(虽然在那之后进行了大量修改),我的代码如下所示:

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只有verbose_name{,_plural}东西,视图是一个简单的DetailView看起来像这样:

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

DB(PostgreSQL 9.6)中有三行,所有行都具有相同的source_id (我只有一行),因此它们都与查询匹配。 奇怪的是,如果我更换.filter(source=...).all()问题似乎消失了。

这就是我所能弄清楚的。 希望它有帮助。 我想,我现在只会坚持使用 1.2.1 :)

感谢您展示您的游记,我稍后会研究这个问题。

我刚刚遇到了同样的问题,通过 list() 将查询集具体化在我们这边也不是一个可行的解决方案。

@op-alex-reid 可以尝试将您的用例变成最小的可重现测试用例吗?

我有同样的问题(Django==1.9,django-tables==1.2.3),代码如下:

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

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

有趣的是,当我设置orderable = True ,问题不会发生。

在我的情况下,通过 list() _is_ 一个选项(以及现在的修复)使查询集结晶,因为表中最多只有 5 行。

谢谢你的例子!

我尝试使用以下代码重现它:

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

但这不会产生重复的行...

我今天遇到了同样的问题。 我在 Django==1.10 项目中使用 django-tables2==1.2.9,在那里我也使用了 django-filters==1.0.1。

有趣的是,我的表中的行加倍仅在以下情况下发生

  1. 有很多条目要显示
    (所以如果我启用每页 25 条记录的分页,一切都很好,但是如果我显示完整的数据集,我会得到多个相同的条目)

  2. 该表按包含非字符串的列排序
    (如果我按包含例如名称的列排序,一切都很好,但按带有日期、整数或布尔值的列排序会导致麻烦)

降级到 1.2.1 解决了这个问题,但这并不是一个真正的选择。
此外,受骗者似乎代替,而不是显示

我希望这有助于深入了解问题的根源,因为除此之外,我真的很喜欢使用 django-tables2。

感谢您的所有工作!

@n0ctua谢谢!

您能否查看执行的确切查询并在此处分享它们?

我也刚刚遇到了这个问题,并且明白为什么我会遇到这个问题,所以我想我会发帖,因为我怀疑其他人也有同样的原因。 _(虽然,我还没有尝试过其他版本的 django-tables2,所以我可能是错的,因为我不明白为什么这会阻止这种情况发生......虽然......实际上考虑一下我会假设这是因为在旧版本中,非分页表对数据库运行了单个查询,而不是对每一行进行查询——下面有更多详细信息...)_

这是因为 _SQL order by在非唯一字段上不是确定性的_ 所以当与top n您一次又一次地得到相同的前 n 行。 (另外,由于某种原因,当我创建一个没有分页的Table ,它会为 _every_ 行生成一个查询。IE top 1 )。

我不确定这里的最佳解决方案是什么? 我认为保证这会起作用的唯一方法是始终将最终的order by放在唯一的字段上。 理想情况下是主键? 另外,可能值得在文档警告中添加一些注释吗?

作为一个单独的问题,但真正会减少这种情况发生的频率(并加速对非分页表的查询)是,如果不是对表中的每一行运行top 1查询,而是只运行一个获取所有结果的查询。

@intiocean对非分页表的查询数量很奇怪,不知道为什么会发生这种情况,也不应该发生。 这个测试用例显示了问题:

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

我曾尝试为失败的分页案例创建测试,但未成功。 我不明白为什么,但在分页的情况下一切似乎都正常工作......我想如果按非唯一字段排序,我会得到看起来好像在多个页面上重复的行。

@intiocean我想我用 10f5e968bc10552be0ad02ee566513b5d274d5c5 修复了它

@jieter太棒了! 我可以理解为什么这可以解决非分页表的问题,但仍然认为当数据分布在不同页面时按非唯一列排序可能会导致同一行出现在多个页面上,因为top n ... limit x offset y

你怎么看?

类似于: http :

@wtfrank , @intiocean @n0ctua @op-alex- reid @fliphess我只是向 master 推送了一些可能解决这个问题的提交。 你能验证吗?

@intiocean如果这是此问题的根源,我认为我们只能通过记录此行为来部分解决此问题。

我可以确认这修复了非分页表@jieter。 这也提高了非分页表的性能,因为现在每行只有一个查询,而不是一个。

检查:
使用 962f502 并按“注释”列排序 -> 重复
image

使用 f853078 并按“注释”列排序 -> 没有重复 🎉
image

你有机会发布@jieter吗?

呜呜,终于修好了!

是的,我会在一个小时内发布。

1.4.0发布

太棒了,谢谢@jieter!

@jieter@intiocean 非常感谢你们解决这个问题! 现在完美运行。

嗨,我刚刚在 1.21.2 版本和 Django==2.0.6 上遇到了这个问题。 感谢intiocean评论,通过“pk”设置附加排序来修复它。

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

foldedpaper picture foldedpaper  ·  6评论

mpasternak picture mpasternak  ·  9评论

blite picture blite  ·  3评论

applegrew picture applegrew  ·  17评论

brianmay picture brianmay  ·  6评论