我有以下问题:
我需要为每个用户(或一组用户)使用相同模型的不同数据库。我有办法找出用户与哪个数据库相关。问题是我总是必须在我做的每个查询中使用using
方法。
例如:
Thing.objects.using('appropriate_database').all()
有没有办法避免使用using
并以某种方式隐含用户/数据库关系?
答案 0 :(得分:1)
听起来像一个糟糕的设计无法扩展到我。每次添加用户时都必须复制模式。
更好的设计会让表USER与每个用户所需的实体之间存在一对多和多对多的关系。
答案 1 :(得分:1)
我们做到了!让我解释一下。
我们编写了一个自定义中间件,并将其注册为settings.py文件中的中间件类。
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'our.custom.middleware.Class',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)
此中间件具有process_request方法,该方法创建线程变量(from threading import local
)以存储当前用户的相应数据库名称。由于每个请求都由不同的线程处理,我们知道我们的变量值不会被另一个线程意外更改。
下一步是创建一个Database Router并注册它。
DATABASE_ROUTERS = ('our.custom.database.Router',)
注意:默认settings.py
没有DATABASE_ROUTERS
变量。你必须创建它。
我们的自定义Router
与db_for_read
和db_for_write
具有相同的实现。这些方法唯一做的就是返回存储在我们的线程变量上的数据库名称。
就是这样。现在,每次我们需要恢复或保存模型对象时,我们都不必调用using
。
答案 2 :(得分:0)
您可以在模特上创建第二个经理:
class MyModelManager(models.Manager):
def get_query_set(self):
return super(MyModelManager, self).get_query_set().using('appropriate_database')
class MyModel(models.Model):
# "objects" is the default manager
objects_db2 = MyModelManager()
field1 = models.CharField(...)
class MyModel2(models.Model):
objects_db2 = MyModelManager()
...
然后使用查询MyModel.objects_db2.filter(...).order_by(...)...