Opened 10 years ago
Closed 10 years ago
#24986 closed Bug (fixed)
Selecting distinct on lower() function throws AttributeError("'Func' object has no attribute 'column'")
| Reported by: | Wojciech Bartosiak | Owned by: | Valentina Mukhamedzhanova |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | dev |
| Severity: | Normal | Keywords: | F(), ORM, distinct |
| Cc: | josh.smeaton@… | 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 (last modified by )
I have simple table:
class Author(models.Model):
name = models.CharField(max_length=40)
I want to write Query using Django ORM to be similar to:
SELECT DISTINCT LOWER(name) from my_app_author;
I finally ended with:
Author.objects.annotate(
name_lower=Func(F('name'), function='lower')
).distinct('name_lower')
But I'm receiving error:
Traceback (most recent call last):
File "/opt/venv/lib/python3.4/site-packages/django/db/models/query.py", line 138, in __repr__
data = list(self[:REPR_OUTPUT_SIZE + 1])
File "/opt/venv/lib/python3.4/site-packages/django/db/models/query.py", line 162, in __iter__
self._fetch_all()
File "/opt/venv/lib/python3.4/site-packages/django/db/models/query.py", line 965, in _fetch_all
self._result_cache = list(self.iterator())
File "/opt/venv/lib/python3.4/site-packages/django/db/models/query.py", line 238, in iterator
results = compiler.execute_sql()
File "/opt/venv/lib/python3.4/site-packages/django/db/models/sql/compiler.py", line 829, in execute_sql
sql, params = self.as_sql()
File "/opt/venv/lib/python3.4/site-packages/django/db/models/sql/compiler.py", line 381, in as_sql
distinct_fields = self.get_distinct()
File "/opt/venv/lib/python3.4/site-packages/django/db/models/sql/compiler.py", line 545, in get_distinct
result.append("%s.%s" % (qn(alias), qn2(target.column)))
AttributeError: 'Func' object has no attribute 'column'
but when i write:
Author.objects.annotate(
name_lower=Func(F('name'), function='lower')
).distinct('something')
I'm receiving an error:
django.core.exceptions.FieldError: Cannot resolve keyword 'something' into field. Choices are: id, name, name_lower, src_id
As database driver I'm using 'ENGINE': 'django.contrib.gis.db.backends.postgis'
Change History (14)
comment:1 by , 10 years ago
comment:2 by , 10 years ago
| Description: | modified (diff) |
|---|
comment:3 by , 10 years ago
| Severity: | Release blocker → Normal |
|---|---|
| Triage Stage: | Unreviewed → Accepted |
| Version: | 1.8 → master |
comment:4 by , 10 years ago
+1 to non-release-blocker. It would be nice to have this, but I don't think this is a severe limitation in the expressions feature. In other words, this is just an ordinary bug.
comment:5 by , 10 years ago
I don't know why you'd think that'd work, especially since the error tells you that "something" isn't actually a field on the model. Am I missing something here?
So why You can see name_lower on the choices list ?
Choices are: id, name, name_lower, src_id
comment:6 by , 10 years ago
Because name_lower is added to the field list when you use the annotation. The field "something" does not exist and was not annotated in your example.
comment:7 by , 10 years ago
I believe the OP was only using something to point out that name_lower doesn't work in spite of being given as an option in the error message.
On a separate note: You should be able to get the query you described initially with
Author.objects.annotate(
name_lower=Func(F('name'), function='lower')
).values('name_lower').distinct()
or something similar.
comment:9 by , 10 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:10 by , 10 years ago
| Cc: | added |
|---|
comment:12 by , 10 years ago
I think the patch looks okay (I proposed some cosmetic improvements to the test). Josh, could you check it?
comment:13 by , 10 years ago
| Triage Stage: | Accepted → Ready for checkin |
|---|
Author.objects.annotate( name_lower=Func(F('name'), function='lower') ).distinct('name_lower')I don't think we implemented Expression support for
distinct(). Accepting on that basis - it shouldn't (famous last words..) be too difficult to implement.Author.objects.annotate( name_lower=Func(F('name'), function='lower') ).distinct('something')I've removed release blocker and 1.8 target, as this is a new feature not previously available. It should be able to go into 1.9 provided there's a patch, but I'm not sure that we'd backport a fix to 1.8.
I don't know why you'd think that'd work, especially since the error tells you that "something" isn't actually a field on the model. Am I missing something here?