Opened 6 years ago

Closed 2 years ago

Last modified 2 years ago

#10913 closed Cleanup/optimization (fixed)

Document how related_name affects QuerySet filtering

Reported by: neithere Owned by: timo
Component: Documentation Version: master
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 Changed 6 years ago by kmtracey

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Resolution set to invalid
  • Status changed from new to 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.

comment:2 Changed 4 years ago by Greg Brown <greg@…>

  • Cc greg@… added
  • Easy pickings unset
  • Resolution invalid deleted
  • Severity set to Normal
  • Status changed from closed to reopened
  • Type set to 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 Changed 4 years ago by Greg Brown <greg@…>

  • Cc greg@… added
  • Easy pickings unset
  • Resolution invalid deleted
  • Severity set to Normal
  • Status changed from closed to reopened
  • Type set to 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 Changed 4 years ago by Greg Brown <greg@…>

  • Easy pickings unset
  • Resolution invalid deleted
  • Severity set to Normal
  • Status changed from closed to reopened
  • Type set to 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 Changed 4 years ago by gregplaysguitar

Sorry about that, I was getting gateway timeouts so hit refresh a couple of times.

comment:4 Changed 4 years ago by russellm

  • Component changed from Database layer (models, ORM) to Documentation
  • Needs documentation set
  • Triage Stage changed from Unreviewed to Accepted
  • Type changed from Uncategorized to 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:5 Changed 4 years ago by gregplaysguitar

Fair enough, thanks for the quick response.

comment:6 Changed 2 years ago by aaugustin

  • Status changed from reopened to new

comment:7 Changed 2 years ago by timo

  • Owner changed from nobody to timo
  • Status changed from new to assigned
  • Summary changed from Default related_name is broken to Document how related_name affects QuerySet filtering

comment:8 Changed 2 years ago by Tim Graham <timograham@…>

  • Resolution set to fixed
  • Status changed from assigned to closed

In 75bb6ba96660e2a06e18d99120c05db2bb9fa9cc:

Fixed #10913 -- Documented how related_name affects QuerySet filtering

Thanks neithere for the suggestion.

comment:9 Changed 2 years ago by Tim Graham <timograham@…>

In 06b149e220f98cd643a4445db1b5719daac0d56f:

[1.6.x] Fixed #10913 -- Documented how related_name affects QuerySet filtering

Thanks neithere for the suggestion.

Backport of 75bb6ba966 from master

Note: See TracTickets for help on using tickets.
Back to Top