Opened 3 years ago

Last modified 3 years ago

#19580 new Cleanup/optimization

Unify reverse foreign key and m2m querying behavior

Reported by: akaariai Owned by: nobody
Component: Database layer (models, ORM) Version: master
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no


Currently when querying unsaved reverse relations the behavior differs.

Using model:

class Foo(models.Model):
    fk = models.ForeignKey('self', related_name='fk_rev')
    m2m = models.ManyToManyField('self')

and test case:


We get [] from the first filter, but an error

ValueError: "<Foo: Foo object>" needs to have a value for field "from_foo" before this many-to-many relationship can be used.

from the second filter.

So, m2m fields can't be filtered if the object isn't saved, but reverse fk fields can be filtered.

There is a (slightly stale) patch for #17541 which makes fk fields and m2m fields work consistently. The changes in behavior are:

* Nullable many-to-many and foreign key relations will return an empty
  queryset when the relation field is null. For many-to-many this was
  previously an error (no change for foreign keys).

* Trying to add objects to a foreign key relation when the relation field
  is null is now an error (no change for m2m).

* Trying to use a relation of any kind when the object isn't saved is now
  an error (no change for m2m).

I think we can squeeze these changes in as bug-fixes. These are slight backwards compatibility changes, but to me it seems that almost always the changes will be visible only in code that isn't working as intended. If these are seen as something likely breaking working code, then I don't see any way to make the APIs consistent.

The #17541 patch is available from:

Change History (2)

comment:1 Changed 3 years ago by akaariai

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement set
  • Triage Stage changed from Unreviewed to Design decision needed
  • Type changed from Uncategorized to Cleanup/optimization
  • Version changed from 1.4 to master

Reviewing my own ticket as "DDN".

comment:2 Changed 3 years ago by aaugustin

  • Triage Stage changed from Design decision needed to Accepted

Yes, it's better to error loudly on operations that can't work because the database didn't generate an id for the object yet.

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