У меня возникла проблема, когда некоторые строки отображаются несколько раз вместо других строк. Данная таблица отлично отображалась в более ранних версиях django и django-tables2. Я обновил их обоих одновременно до последней версии каждого (django 1.10, django-tables2 1.2.4), после чего эта проблема начала возникать.
См. Это изображение здесь для демонстрации: http://imgur.com/a/pPRT8
Когда я загружаю таблицу, не выбирая порядок сортировки по столбцу, я не вижу этой проблемы. Как только я нажимаю заголовок столбца, чтобы изменить порядок сортировки, строки дублируются.
Пока что я определил, что данные, переданные в объект 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)
Кристаллизация набора запросов через 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?
Да, определенно не решение, но это может указывать на причину. Другая причина, по которой приведение к списку не является подходящим решением, заключается в том, что это не всегда кажется набором запросов, в любом случае хранящим данные, и в этом случае self.data.data не существует.
@wtfrank , я понимаю, но было бы очень
Я думаю, что столкнулся с той же проблемой: в моей таблице одна строка отсутствует, а другая дублируется ... Для меня это началось с версии 1.2.2.
Переход на 1.2.1 "решает" проблему для меня .... Могу ли я предоставить какую-либо информацию, чтобы облегчить поиск?
Было бы неплохо иметь минимальный тестовый пример. Затем мы можем запустить 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, конечно), я постоянно теряю первую строку (из трех, которые есть в БД) и вместо нее получаю копию другой. Например, когда на 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 | ... |
Я использую Django 1.9.9 на Python 2.7.12, проект был запущен с использованием 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
И в БД есть три строки (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 () _ является вариантом (и исправлением на данный момент), поскольку в таблице не более 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-tables2 == 1.2.9 в проекте Django == 1.10, где я также использую django-filters == 1.0.1.
Интересно, что удвоение строк в моей таблице происходит только в том случае, если
есть много записей для отображения
(поэтому, если я включу разбиение на страницы с 25 записями на страницу, все в порядке, но если я покажу полный набор данных, я получу несколько идентичных записей)
таблица отсортирована по столбцу, который не содержит строк
(все в порядке, если я сортирую по столбцу, который содержит, например, имена, но сортировка по столбцам с датами, целыми числами или логическими значениями приводит к проблемам)
Переход на 1.2.1 решает проблему, но на самом деле это не вариант.
Кроме того, кажется, что дубликаты отображаются вместо реальных записей, а не в дополнение к ним , потому что счетчик {{filter.qs.count}} такой, каким должен быть.
Я надеюсь, что это немного поможет разобраться в проблеме, потому что в остальном мне очень нравится работать с django-tables2.
Спасибо за вашу работу!
@ n0ctua спасибо!
Можете ли вы посмотреть на точные выполненные запросы и, возможно, поделиться ими здесь?
У меня тоже была эта проблема, и я понимаю, почему это происходит со мной, поэтому решил опубликовать, поскольку подозреваю, что у других есть это по той же причине. _ (Хотя я не пробовал с другими версиями django-tables2, поэтому могу ошибаться, так как не понимаю, почему это остановило бы это ... Хотя ... на самом деле думая об этом, я бы предположил, что это потому что в более старых версиях таблицы без разбивки на страницы выполняли один запрос к базе данных вместо запроса для каждой строки - подробнее об этом ниже ...) _
Это потому, что _SQL order by
для неуникальных полей не является детерминированным_, поэтому при объединении с помощью top n
вы снова и снова получаете одни и те же первые n строк. (Кроме того, по какой-то причине, когда я создаю Table
без разбивки на страницы, он генерирует запрос для _every_ row. 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
Что вы думаете?
@wtfrank , @intiocean @ n0ctua @ op-alex-reid @fliphess Я только что отправил в коммитов, которые могут это исправить. Вы можете проверить?
@intiocean Если это источник проблемы, я думаю, что мы сможем решить эту проблему только частично, задокументировав такое поведение.
Я могу подтвердить, что это исправляет не разбитые на страницы таблицы @jieter. Это также улучшает производительность для таблиц без разбивки на страницы, поскольку теперь существует только один запрос вместо одного для каждой строки.
Проверять:
С 962f502 и сортировкой по столбцу «Примечания» -> дублирование
С f853078 и сортировкой по столбцу «Примечания» -> без дублирования 🎉
Есть ли шанс сделать релиз @jieter?
wohoo, наконец-то исправлено!
Да, отпущу в течении часа.
выпущен 1.4.0
Отлично, спасибо @jieter!
@jieter и @intiocean большое вам спасибо за исправление! Теперь работает отлично.
Привет, я только что столкнулся с этой проблемой в версии 1.21.2 и Django == 2.0.6. Благодаря комментарию intiocean
исправил с установкой дополнительного упорядочивания по 'pk'.
Самый полезный комментарий
wohoo, наконец-то исправлено!
Да, отпущу в течении часа.