Opened 8 years ago

Closed 8 years ago

Last modified 7 years ago

#13432 closed (fixed)

OneToOneField between two databases fails

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


When model A is in the default database and model B is in another database, and there is a OneToOne relation between the two models, the lookup fails (raising a DoesNotExist, or if the tables aren't in both databases, a ProgrammingError). Writing works, only reading fails. I have no idea of the ORM internals, so I might be completely wrong, but I think the cause is a simple copy&paste error. Fix and test is in the patch.

Attachments (1)

one_to_one_multidb.diff (2.4 KB) - added by Benjamin Wohlwend 8 years ago.

Download all attachments as: .zip

Change History (4)

Changed 8 years ago by Benjamin Wohlwend

Attachment: one_to_one_multidb.diff added

comment:1 Changed 8 years ago by Russell Keith-Magee

Triage Stage: UnreviewedAccepted

This is a case of being technically correct, for the wrong reason.

You are correct that self.related.model is technically the right argument to pass in. However, it doesn't make a huge difference in practice, because self.related.model and instance.class must route to compatible databases (i.e., you must be able to find objects of both types on the same database). If there is a relationship between the two objects, they must be on databases that allow joins.

In the example you give, the two models are on different databases - which would be prohibited on any database that honors referential integrity. Your example should have an "allows_join" method that prohibits cross-database joins, which would prohibit the creation of the UserProfile instance in the first place.

There are cases where you will be able to get away with the type of router you describe - if you use MySQL/MyISAM or SQLite, and you don't ever issue a User.objects.filter(userprofile__flavor='foo') query, for instance; but in general I would advise against this unless you have really thought through the consequences.

There is an edge case where model-based load balancing behavior might cause this issue to be observed, but only in the sense that queries would be directed to the wrong slave (answers wouldn't be wrong, just served by the wrong database), so the problem is still worth solving. I'll also use this as an opportunity to add some tests for o2o relations, which weren't fully tested previously.

comment:2 Changed 8 years ago by Russell Keith-Magee

Resolution: fixed
Status: newclosed

(In [13037]) Fixed #13432 -- Corrected the logic for router use on OneToOne? fields; also added a bunch of tests for OneToOneField? queries. Thanks to piquadrat for the report.

comment:3 Changed 7 years ago by Jacob

milestone: 1.2

Milestone 1.2 deleted

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