Opened 6 years ago
Last modified 9 months ago
#29762 new Cleanup/optimization
Document how database routers are used for related object access
Reported by: | Vackar Afzal | Owned by: | nobody |
---|---|---|---|
Component: | Documentation | Version: | 2.0 |
Severity: | Normal | Keywords: | oracle, multidb |
Cc: | Ülgen Sarıkavak | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
When run a filter query like this:
my_instance = MyModel.objects.using('NonDefaultDBConn').filter(some_field='XXXX') my_instance.local_field #This works my_instance.fk_field #This doesn't work
It fails when trying to access my_instance.fk_field as it defaults to using the 'default' connection and not 'NonDefaultDBConn'
I would assume that when fetching a model using 'NonDefaultDBConn' that all subsequent lookups should go through 'NonDefaultDBConn' and not 'default'
If this is not the case, and this is expected behaviour how can I force fk lookups to go through 'NonDefaultDBConn'
I know I can run
MyLinkedModel.objects.filter(x_instance=my_instance)
But this is massively in-efficient both from a performance and code maintainability point of view.
I am using Django 2.0 with the Oracle backend.
Change History (8)
comment:1 by , 6 years ago
Resolution: | → needsinfo |
---|---|
Status: | new → closed |
Type: | Uncategorized → Bug |
comment:2 by , 6 years ago
Resolution: | needsinfo |
---|---|
Status: | closed → new |
Apologies I should have been clearer with the problem, it's similar to what is being described here:
https://stackoverflow.com/questions/40457351/why-is-the-database-used-by-django-subqueries-not-sticky
My application has a single 'MetaSchema' and 'n' identical ApplicationSchemas.
The default connection points to the meta-schema, and the default router routes everything via 'defaut'
AppModel1 is not present in the default 'MetaSchema', but is present in all of the ApplicationSchemas
Running this fails on the second line:
obj = AppModel1.objects.using('ApplicationSchema1').first() obj.objects.fk_field # <--- This fails
However, looking at the router configuration for the tests, I think it may be a misconfiguration issue on my part. It looks like I need to setup the router as follows:
class TestRouter: def db_for_read(self, model, instance=None, **hints): if instance: return instance._state.db or 'default' return 'default' .....
Is this something worth mentioning / or highlighting in the Documentation?
comment:3 by , 6 years ago
The test router isn't used for the test that I linked to. I also tried this and it works fine in the test:
dive = Book.objects.using('other').first() self.assertEqual(dive.editor.name, "Chris Mills")
Are you using a database router in your project?
comment:4 by , 6 years ago
I am indeed, and that's probably what's causing the odd behaviour:
class MyRouter(object): def db_for_read(self, model, **hints): return 'default' def db_for_write(self, model, **hints): return 'default' def allow_relation(self, obj1, obj2, **hints): return True def allow_migrate(self, db, app_label, model_name=None, **hints): return db == 'default'
comment:5 by , 6 years ago
Component: | Database layer (models, ORM) → Documentation |
---|---|
Summary: | Explicit 'Using' with foreign Key on model → Document how database routers are used for related object access |
Type: | Bug → Cleanup/optimization |
Right, so you're overriding the default behavior of using the database from which the object was fetched.
comment:6 by , 6 years ago
Triage Stage: | Unreviewed → Accepted |
---|
comment:8 by , 9 months ago
Cc: | added |
---|
The behavior you describe shouldn't happen. There are tests in Django's test suite that demonstrates. I also tried this:
Please provide a test case or a sample project that reproduces the problem you're seeing.