Opened 14 years ago
Closed 3 years ago
#17990 closed Bug (duplicate)
DISTINCT querysets with RANDOM ordering crash with DatabaseError in Postgres
| Reported by: | Paul Bailey | Owned by: | Ryan Cheley |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.4 |
| Severity: | Normal | Keywords: | |
| Cc: | Étienne Beaulé | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
When using distinct().order_by('?') with Postgres you get a query error.
My models:
class Category (models.Model): title = models.CharField(max_length=100) slug = models.SlugField(unique=True, max_length=200) class Post (models.Model): title = models.CharField(max_length=255) slug = models.SlugField(unique=True, max_length=200) publish = models.DateTimeField() categories = models.ManyToManyField(Category) body = models.TextField()
Causes Bug in Postgres but not SQLite:
return Post.objects.filter(categories__in=cats).exclude(id=self.id).order_by('?').distinct()[:5]
No Error:
return Post.objects.filter(categories__in=cats).exclude(id=self.id).distinct()[:5]
Traceback:
ERROR:django.request:Internal Server Error: /blog/online-photo-editors/
Traceback (most recent call last):
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 136, in get_response
response = response.render()
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/response.py", line 104, in render
self._set_content(self.rendered_content)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/response.py", line 81, in rendered_content
content = template.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 140, in render
return self._render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
return self.nodelist.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 823, in render
bit = self.render_node(node, context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 837, in render_node
return node.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 123, in render
return compiled_parent._render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 134, in _render
return self.nodelist.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 823, in render
bit = self.render_node(node, context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 837, in render_node
return node.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/loader_tags.py", line 62, in render
result = block.nodelist.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 823, in render
bit = self.render_node(node, context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/base.py", line 837, in render_node
return node.render(context)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/template/defaulttags.py", line 145, in render
len_values = len(values)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/db/models/query.py", line 85, in __len__
self._result_cache = list(self.iterator())
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/db/models/query.py", line 291, in iterator
for row in compiler.results_iter():
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 763, in results_iter
for rows in self.execute_sql(MULTI):
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 818, in execute_sql
cursor.execute(sql, params)
File "/home/webapp/pyenv/cr/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py", line 52, in execute
return self.cursor.execute(query, args)
DatabaseError: for SELECT DISTINCT, ORDER BY expressions must appear in select list
LINE 1: ..." = 4 ) AND NOT ("blog_post"."id" = 4 )) ORDER BY RANDOM() L...
Attachments (1)
Change History (9)
comment:1 by , 14 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
comment:2 by , 13 years ago
I solved this problem using GROUP BY instead of DISTINCT. I found this solution here:
comment:3 by , 12 years ago
Actually, an even easier fix would be to exclude the RANDOM from the distinct. That's in a patch. In a trivial case, that can be worked around like this:
Model.objects.extra(select={'rand': 'RANDOM()'}).distinct('pk').order_by('rand')
comment:4 by , 5 years ago
| Cc: | added |
|---|---|
| Resolution: | → fixed |
| Status: | new → closed |
| Summary: | Distinct + Random + Postgres = Bug → DISTINCT querysets with RANDOM ordering crash with DatabaseError in Postgres |
comment:6 by , 5 years ago
| Resolution: | fixed |
|---|---|
| Status: | closed → new |
It doesn't crash but it's not fixed, see Anssi's comment. I attached a regression test.
comment:7 by , 3 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:8 by , 3 years ago
| Resolution: | → duplicate |
|---|---|
| Status: | assigned → closed |
The solution offered by Anssi Kääriäinen and supported by the stackoverflow answer in ticket:17990#comment:2 point to this being a subset of the solution being worked on in 24462. Therefore it is being marked as resolved - duplicate
I don't think this will be easy to fix. The obvious fix is to add the random() to the select distinct list, but that of course breaks the distinct (you are doing distinct on random(), which isn't wanted). The only solution I can see is using an inner query with the distinct, then ordering by random() in the outer query. It should be possible to do. The usecase isn't common and the patch will likely be nontrivial.