#10913 closed Cleanup/optimization (fixed)
Document how related_name affects QuerySet filtering
| Reported by: | neithere | Owned by: | Tim Graham |
|---|---|---|---|
| Component: | Documentation | Version: | dev |
| Severity: | Normal | Keywords: | orm, related_name, |
| Cc: | greg@… | Triage Stage: | Accepted |
| Has patch: | no | Needs documentation: | yes |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The documentation states that by default the "backward" relationship Manager "is named FOO_set, where FOO is the source model name, lowercased". However, in the latest SVN snapshot the behaviour seems to be inconsistent.
models.py
from django.db import models
class Author(models.Model):
name = models.CharField(max_length=255)
class Book(models.Model):
title = models.CharField(max_length=255)
author = models.ForeignKey(Author) # by default, related_name='book_set'
The related_name argument is commented out. If not, everything works fine, but let's see what happens now:
In shell after syncdb:
>>> from fooapp.models import Author, Book
>>> Author.book_set
<django.db.models.fields.related.ForeignRelatedObjectsDescriptor object at 0x27f4e90>
>>> Author.book
Traceback (most recent call last):
File "<console>", line 1, in <module>
AttributeError: type object 'Author' has no attribute 'book'
>>> a=Author.objects.create(name='John')
>>> b=Book.objects.create(title='My Book', author=a)
>>> Author.objects.filter(book_set__exact=1)
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/usr/local/lib/python2.6/dist-packages/Django-1.1_beta_1-py2.6.egg/django/db/models/manager.py", line 129, in filter
return self.get_query_set().filter(*args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/Django-1.1_beta_1-py2.6.egg/django/db/models/query.py", line 466, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/usr/local/lib/python2.6/dist-packages/Django-1.1_beta_1-py2.6.egg/django/db/models/query.py", line 484, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/usr/local/lib/python2.6/dist-packages/Django-1.1_beta_1-py2.6.egg/django/db/models/sql/query.py", line 1613, in add_q
can_reuse=used_aliases)
File "/usr/local/lib/python2.6/dist-packages/Django-1.1_beta_1-py2.6.egg/django/db/models/sql/query.py", line 1511, in add_filter
negate=negate, process_extras=process_extras)
File "/usr/local/lib/python2.6/dist-packages/Django-1.1_beta_1-py2.6.egg/django/db/models/sql/query.py", line 1676, in setup_joins
"Choices are: %s" % (name, ", ".join(names)))
FieldError: Cannot resolve keyword 'book_set' into field. Choices are: book, id, name
>>> Author.objects.filter(book__exact=1)
[<Author: John>]
Change History (11)
comment:1 by , 17 years ago
| Resolution: | → invalid |
|---|---|
| Status: | new → closed |
comment:2 by , 14 years ago
| Cc: | added |
|---|---|
| Easy pickings: | unset |
| Resolution: | invalid |
| Severity: | → Normal |
| Status: | closed → reopened |
| Type: | → Uncategorized |
| UI/UX: | unset |
I think the OP is correct here, at least in that the ORM is inconsistent. The docs state that the default related name is FOO_set, and while this is true when accessing the manager, the OP gets differing behaviour when explicitly setting related_name='book_set' to the default when filtering (as do I). To spell it out again, the following will work:
class Event(models.Model):
...
class Image(models.Model):
event = models.ForeignKey(Event, related_name='image_set')
>>> Event.objects.filter(image_set__isnull=True)
Whereas this will throw a FieldError:
class Event(models.Model):
...
class Image(models.Model):
event = models.ForeignKey(Event)
>>> Event.objects.filter(image_set__isnull=True)
This ticket does not indicate "a misunderstanding about Django, how it works, and how to use it"; rather it points out a gotcha that needs to be fixed, or at the very least properly documented.
comment:2 by , 14 years ago
| Cc: | added |
|---|---|
| Easy pickings: | unset |
| Resolution: | invalid |
| Severity: | → Normal |
| Status: | closed → reopened |
| Type: | → Uncategorized |
| UI/UX: | unset |
I think the OP is correct here, at least in that the ORM is inconsistent. The docs state that the default related name is FOO_set, and while this is true when accessing the manager, the OP gets differing behaviour when explicitly setting related_name='book_set' to the default when filtering (as do I). To spell it out again, the following will work:
class Event(models.Model):
...
class Image(models.Model):
event = models.ForeignKey(Event, related_name='image_set')
>>> Event.objects.filter(image_set__isnull=True)
Whereas this will throw a FieldError:
class Event(models.Model):
...
class Image(models.Model):
event = models.ForeignKey(Event)
>>> Event.objects.filter(image_set__isnull=True)
This ticket does not indicate "a misunderstanding about Django, how it works, and how to use it"; rather it points out a gotcha that needs to be fixed, or at the very least properly documented.
comment:2 by , 14 years ago
| Easy pickings: | unset |
|---|---|
| Resolution: | invalid |
| Severity: | → Normal |
| Status: | closed → reopened |
| Type: | → Uncategorized |
| UI/UX: | unset |
I think the OP is correct here, at least in that the ORM is inconsistent. The docs state that the default related name is FOO_set, and while this is true when accessing the manager, the OP gets differing behaviour when explicitly setting related_name='book_set' to the default when filtering (as do I). To spell it out again, the following will work:
class Event(models.Model):
...
class Image(models.Model):
event = models.ForeignKey(Event, related_name='image_set')
>>> Event.objects.filter(image_set__isnull=True)
Whereas this will throw a FieldError:
class Event(models.Model):
...
class Image(models.Model):
event = models.ForeignKey(Event)
>>> Event.objects.filter(image_set__isnull=True)
This ticket does not indicate "a misunderstanding about Django, how it works, and how to use it"; rather it points out a gotcha that needs to be fixed, or at the very least properly documented.
comment:3 by , 14 years ago
Sorry about that, I was getting gateway timeouts so hit refresh a couple of times.
comment:4 by , 14 years ago
| Component: | Database layer (models, ORM) → Documentation |
|---|---|
| Needs documentation: | set |
| Triage Stage: | Unreviewed → Accepted |
| Type: | Uncategorized → Cleanup/optimization |
The code example you provide is working as intended. However, I'll accept this ticket as a documentation issue; a quick scan of the related_name docs didn't reveal anything describing this behavior.
comment:6 by , 13 years ago
| Status: | reopened → new |
|---|
comment:7 by , 12 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
| Summary: | Default related_name is broken → Document how related_name affects QuerySet filtering |
comment:8 by , 12 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
Everything you show looks correct. book_set is not a field, it is a type of queryset Manager that you can use to access the set of books by a particular Author instance. Therefore, since it is not a field, you cannot filter on it. Rather, you filter on the actual field you are interested in. If you have additional questions, please post to django-users, not the ticket tracker. What you have posted here indicates a misunderstanding about Django, how it works, and how to use it, not a bug in Django. The django-users mailing list will be a better place to get misunderstandings cleared up than the ticket tracker.