#19652 closed Bug (fixed)
Fix for #19524 introduced a backward compatiblity issue with related managers on 1.5.X
| Reported by: | Simon Charette | Owned by: | Simon Charette |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 1.5-beta-1 |
| Severity: | Release blocker | Keywords: | none EmptyQuerySet none |
| Cc: | Triage Stage: | Accepted | |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
The fix for #19524 which was backported to the 1.5.X branch caused the following regression:
class ObjectQuerySet(models.query.QuerySet): def extra_qs_method(self): pass class ObjectManager(models.Manager): use_for_related_fields = True def get_query_set(self): return ObjectQuerySet(self.model, using=self._db) class RelatedObject(models.Model): pass class Object(models.Model): related = models.ForeignKey(RelatedObject, related_name='objs') objects = ObjectManager() RelatedObject().objs.extra_qs_method()
Raises
AttributeError: 'EmptyQuerySet' object has no attribute 'extra_qs_method'
It works perfectly on master since QuerySet.none() returns an instance of the correct class while setting it's underlying's query to empty and on < 1.5.X since prior to this backport there was no instance.pk check to return an EmptyQuerySet.
Attachments (1)
Change History (17)
comment:1 by , 13 years ago
| Severity: | Normal → Release blocker |
|---|
comment:2 by , 13 years ago
comment:3 by , 13 years ago
Isn't it technically possible to have a nullable custom foreign key field? (There could be at most one object with a null pk.)
comment:4 by , 13 years ago
| Triage Stage: | Unreviewed → Accepted |
|---|
A pk can't be NULL, but if you use to_field, then you could have NULLs on both sides. We definitely want the semantics of SQL's JOIN ON (lhs.fk_val = rhs.to_field). This means that if either/both of those are NULL, then the result is "no match". (SQL's funny trinary boolean logic, NULL = NULL => UNKNOWN.)
If we go an try to change this we will have endless amount of problems.
comment:6 by , 13 years ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:7 by , 13 years ago
To avoid the NULL = NULL issue, you could just go with a more explicit queryset.filter(Q(pk=1) & ~Q(pk=1)).
comment:8 by , 13 years ago
The correct approach seems to be to filter using pk__in=[] which ensures no query is executed.
I am too tired to write a patch today. If anybody else wants to tackle this I won't object...
by , 13 years ago
| Attachment: | 0001-Fixed-19652-Fixed-a-regression-introduced-by-9d6d0de.patch added |
|---|
comment:10 by , 13 years ago
| Has patch: | set |
|---|
comment:11 by , 13 years ago
Every use of .none() pre-1.6 will cause this same bug. This is a "feature" of using .none(), and the reason .none() was changed in 1.6. Still, I think it is a good idea to fix this one as this is a regression. Existing code will fail, and the fix is trivial.
I will commit the patch to 1.5.
comment:12 by , 13 years ago
| Resolution: | → fixed |
|---|---|
| Status: | assigned → closed |
comment:16 by , 13 years ago
| Component: | ORM aggregation → Database layer (models, ORM) |
|---|
The likely fix is to do queryset.filter(pk=None) instead of queryset.none(). User visible effect is the same as what is now done in master.