我有以下问题:
对于每个用户(或一组用户),我需要一个具有相同模型的不同数据库。我有办法找出用户与哪个数据库相关。问题是我总是必须对using
我所做的每个查询都使用该方法。
例如:
Thing.objects.using('appropriate_database').all()
有没有办法避免使用using
和隐含用户/数据库关系?
我有以下问题:
对于每个用户(或一组用户),我需要一个具有相同模型的不同数据库。我有办法找出用户与哪个数据库相关。问题是我总是必须对using
我所做的每个查询都使用该方法。
例如:
Thing.objects.using('appropriate_database').all()
有没有办法避免使用using
和隐含用户/数据库关系?
听起来像一个糟糕的设计,无法扩展到我。每次添加用户时都必须复制架构。
更好的设计应该有一个表 USER 与每个用户所需的实体具有一对多和多对多关系。
我们做到了!让我解释一下。
我们编写了一个自定义中间件并将其注册为我们的 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_ROUTERS = ('our.custom.database.Router',)
注意:默认settings.py
没有DATABASE_ROUTERS
变量。你必须创建它。
我们的自定义对和Router
具有相同的实现。这些方法唯一做的就是返回存储在我们的线程变量中的数据库名称。db_for_read
db_for_write
而已。现在我们不必在using
每次需要恢复或保存模型对象时调用。
您可以在模型上创建第二个经理:
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(...)...