Django - how to specify a database for a model?
-
29-09-2019 - |
문제
Is there a way to specify that a model (or app, even) should only ever use one particular database?
I am working with a legacy database that I don't want to change. I have two databases - the 'default' is an sqlite one that could be used for admin etc, and the legacy one. I used inspectdb to create a model for (part of) the legacy database, and it has managed = False
. But is there a way to specify in the model itself that it only applies to a particular database?
I see that you can specify using=databasename
in some query sets etc but this is no good for things like Databrowse (and possibly also generic views?). It might be a short-coming of Databrowse that you can't specify a database, but it just seems like the right place to specify it is the model...
Then I thought maybe the answer is to write a custom model manager that only refers to my legacy database - but the docs don't mention anything like that.
Do I just have a different mental model of how multiple databases might be used, to the Django world?
해결책
As far as I know you can't specify the database directly with the model since it would kind of prevent the app from ever being reusable, but from what I can see in the docs:
다른 팁
You can't specify a database for a model, but you can define it in a custom DB router class.
# app/models.py
class SomeModel(models.Model):
...
# app/dbrouters.py
from app.models import SomeModel
...
class MyDBRouter(object):
def db_for_read(self, model, **hints):
""" reading SomeModel from otherdb """
if model == SomeModel:
return 'otherdb'
return None
def db_for_write(self, model, **hints):
""" writing SomeModel to otherdb """
if model == SomeModel:
return 'otherdb'
return None
# app/settings.py
DATABASE_ROUTERS = ('app.dbrouters.MyDBRouter',)
...
DATABASES = {
...
'otherdb': {
....
}
}
I found that you can route models pretty simply with this manager:
class SecondDbManager(models.Manager):
def get_queryset(self):
qs = super().get_queryset()
# if `use_db` is set on model use that for choosing the DB
if hasattr(self.model, 'use_db'):
qs = qs.using(self.model.use_db)
return qs
Just add use_db='databasename'
and this manager to your model and it works.
Or to further simplify it I created a base model for it:
class SecondDbBase(models.Model):
use_db = 'my_second_db'
objects = SecondDbManager()
class Meta:
abstract = True
And with this all you need to do is extend it like so. Instead of:
class Customer(models.Model):
Just do this and it works:
class Customer(SecondDbBase):
PS. I'm not sure if it's a good practice or the best solution but it works and routing to other databases is a breeze :)
PSS. I've only ever used these for only reading and writing tables that are not managed by Django(managed = False
) so if you need to create migrations for them, I'm not sure if it works or not. Might still need to use DATABASE_ROUTERS
for that.