Code

Opened 4 years ago

Closed 4 years ago

Last modified 3 years ago

#13432 closed (fixed)

OneToOneField between two databases fails

Reported by: piquadrat 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:

Description

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 piquadrat 4 years ago.

Download all attachments as: .zip

Change History (4)

Changed 4 years ago by piquadrat

comment:1 Changed 4 years ago by russellm

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset
  • Triage Stage changed from Unreviewed to Accepted

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 4 years ago by russellm

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

(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 3 years ago by jacob

  • milestone 1.2 deleted

Milestone 1.2 deleted

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.