#30335 closed Bug (fixed)
TypeError: unhashable type: 'list' when paginating queryset with KeyTransform annotation
| Reported by: | Jaap Roes | Owned by: | Can Sarıgöl |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 2.2 |
| Severity: | Release blocker | Keywords: | postgresql jsonb keytransform annotation pagination |
| Cc: | Can Sarıgöl | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
We have encountered a unexpected error when trying to upgrade an application from Django 2.1 to 2.2.
In our application we have the requirement to order a queryset on a value that's found in a nested datastructure stored in a JSON field. To do this we use KeyTransforms to annotate the queryset with this value and order on this annotation. This queryset is then paginated.
This used to work in Django 2.1, but now raises a TypeError in Django 2.2.
I created a minimal example to reproduce the error:
models.py:
from django.db import models
from django.contrib.postgres.fields import JSONField
class Example(models.Model):
data = JSONField(default=dict)
tests.py:
from django.test import TestCase
from django.core.paginator import Paginator
from django.contrib.postgres.fields.jsonb import KeyTextTransform, KeyTransform
from .models import Example
class TestKeyTransformPagination(TestCase):
def setUp(self):
Example.objects.create(data={
'translations': [
{'title': 'Ladies and gentleman'},
{'title': 'Dames en heren'}
]
})
Example.objects.create(data={
'translations': [
{'title': 'Apples and pears'},
{'title': 'Appels en peren'}
]
})
# The next example queryset raises: TypeError: unhashable type: 'list'
# qs = Example.objects.order_by('data__translations__0__title')
# qs[0]
#
# This is a workaround to achieve the desired ordering
extract_title = KeyTextTransform('title', KeyTransform('0', KeyTransform('translations', 'data')))
self.qs = Example.objects.annotate(title=extract_title).order_by('title')
def test_queryset(self):
self.assertEqual('Apples and pears', self.qs[0].data['translations'][0]['title'])
def test_pagination(self):
# Works on 2.1.x and master, raises TypeError: unhashable type: 'list' on 2.2
paginator = Paginator(self.qs, per_page=10)
page = paginator.page(1)
self.assertEqual('Apples and pears', page.object_list[0].data['translations'][0]['title'])
While investigating this issue I discovered that this error does not happen on the current master.
After bisecting I can tell that commit 3767c7ff391d5f277e25bca38ef3730ddf9cea9c (Fixed #29244) introduces (or exposes) the exception and 3f32154f40a855afa063095e3d091ce6be21f2c5 (Fixed #30188) fixes the error.
Is it possible to backport the fix for #30188 to Django 2.2 so we can upgrade our application?
Change History (9)
comment:1 by , 7 years ago
comment:2 by , 7 years ago
| Severity: | Normal → Release blocker |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
Thanks for the report. I can reproduce with the provided example. (Passes on 2.1.x, fails on 2.2.x)
comment:4 by , 7 years ago
Replying to Can Sarıgöl:
Hi, is this can be a solution? PR
That looks good, it seems that it would also remove the need for our workaround, which I'm always in favor of :-)
comment:6 by , 7 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:7 by , 7 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
By the way, I'm not sure if
Example.objects.order_by('data__translations__0__title')[0]is supposed to work? It currently raises aTypeErrorwhich is why we are usingannotatewithKeyTransforms as a work around.