Opened 2 years ago
Last modified 2 years ago
#33838 closed Bug
Querying issue with ForeignKeys where db_constraint=False — at Version 1
Reported by: | Alex Bailey | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 4.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
models.py
from django.db import models class Person(models.Model): name = models.CharField(max_length=25) class Book(models.Model): foo = models.ForeignKey(Person, db_constraint=False, on_delete=models.DO_NOTHING, related_name='foo') bar = models.ForeignKey(Person, db_constraint=False, on_delete=models.DO_NOTHING, related_name='bar')
setup
from .models import Book, Person alex = Person.objects.create(name='Alex') Book.objects.create(foo=alex, bar=alex) Book.objects.create(foo=alex, bar_id=999) Book.objects.create(foo_id=999, bar=alex)
shell
>>> from django.db.models import Q #Correct: Returns both books where foo__name == 'Alex' >>> Book.objects.filter(foo__name='Alex') <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]> #Correct: Returns both books where bar__name == 'Alex' >>> Book.objects.filter(bar__name='Alex') <QuerySet [<Book: Book object (1)>, <Book: Book object (3)>]> #Only returns one book, expected to return all 3. >>> Book.objects.filter(Q(foo__name='Alex') | Q(bar__name='Alex')) <QuerySet [<Book: Book object (1)>]>
I am working with an existing DB where it is possible for a Person
to no longer exist, hence the lack of db_constraint
in the ForeignKey
.
Books
can refer to non-existent Persons
but it still seems like expected behavior would be for the queryset OR to return all 3 books. I believe this is coming from the Django ORM doing an INNER JOIN. The 3rd query should be a simple union of the first 2 queries.
All 3 books fit into the expected query of books WHERE foo__name = 'Alex' OR bar__name = 'Alex'
but the Django behavior does not reflect this.