基于当前登录用户的Django数据库路由
在基于当前登录用户的Django数据库路由,django,python-3.x,django-rest-framework,Django,Python 3.x,Django Rest Framework,在视图类中,您可以调用self.request.user并基于此执行操作。在我的情况下,我希望能够根据当前登录的用户切换数据库。是否仍然可以将self.request调用注入到db\u for_read()和db\u for_write()方法中,如下所示 class DataBaseRouter(object): def db_for_read(self, model, **hints): user = self.request.user if use
视图
类中,您可以调用self.request.user
并基于此执行操作。在我的情况下,我希望能够根据当前登录的用户切换数据库。是否仍然可以将self.request
调用注入到db\u for_read()
和db\u for_write()
方法中,如下所示
class DataBaseRouter(object):
def db_for_read(self, model, **hints):
user = self.request.user
if user.id == 1:
return "master"
return "default"
def db_for_write(self, model, **hints):
user = self.request.user
if user.id == 1:
return "master"
return "default"
您可以使用
routermiddlewar
检查用户是否登录,然后将所有查询
重定向到您选择的特定数据库,如果您使用基于视图的
执行查询,这将非常有帮助
class RouterMiddleware (object):
def process_view( self, request, view_func, args, kwargs ):
# Check the user logged in
user = self.request.user
# Call your functions to set the database by passing the user.id
def process_response( self, request, response ):
# Make the database to default here if you wish to use it no longer
return response
class DataBaseRouter(object):
def db_for_read(self, model, user_id=None, **hints):
if user.id == 1:
return "master"
return "default"
def db_for_write(self, model, user_id=None, **hints):
if user.id == 1:
return "master"
return "default"
这是我根据您的要求修改的
请确保将RouterMiddleware
添加到中间件类中
尝试此操作。这很简单。安装它,并按如下方式配置和使用
设置.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'my_local_database',
'USER': 'postgres',
'PASSWORD': 'my-pass',
'HOST': '127.0.0.1',
'PORT': '5432',
},
'master': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'my_master_database',
'USER': 'postgres',
'PASSWORD': 'my-pass',
'HOST': 'example.com',
'PORT': '5432',
},
}
DATABASE_ROUTERS = ['dynamic_db_router.DynamicDbRouter']
from dynamic_db_router import in_database
from my_app.models import MyModel
def index(request):
#Picking the DB based on logged in user or you can do this in middile ware as well.
use_db = "default"
user = self.request.user
if user.id == 1:
use_db = "master"
# Fetching data from selected databases.
with in_database(use_db):
input = MyModel.objects.filter(field_a="okay")
output = complex_query_function(input)
我的应用程序/视图.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'my_local_database',
'USER': 'postgres',
'PASSWORD': 'my-pass',
'HOST': '127.0.0.1',
'PORT': '5432',
},
'master': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'my_master_database',
'USER': 'postgres',
'PASSWORD': 'my-pass',
'HOST': 'example.com',
'PORT': '5432',
},
}
DATABASE_ROUTERS = ['dynamic_db_router.DynamicDbRouter']
from dynamic_db_router import in_database
from my_app.models import MyModel
def index(request):
#Picking the DB based on logged in user or you can do this in middile ware as well.
use_db = "default"
user = self.request.user
if user.id == 1:
use_db = "master"
# Fetching data from selected databases.
with in_database(use_db):
input = MyModel.objects.filter(field_a="okay")
output = complex_query_function(input)
为了解决这个问题,我创建了一个新模型,其中只有一个
userid
字段。然后在路由器中,当为读写指定db时,我从该模型中获取数据,因此不需要任何请求参数。我只是在我的基本模板中添加了一个简短的ajax代码,这样每当我的网站被打开时,它都会从request.user中获取用户id,并更改模型行,这样当前的用户id就会像这样更改。@kartheek的答案将是一个更简单的解决方案,如果您能够灵活地在项目中安装该包的话。如果您不想检查和更改每个视图函数的数据库,可以使用中间件处理器。嘿,谢谢您的回答@kt14!我最终同意了你的答案,因为我发现它比kartheek的更容易实现。不过我确实有一个担心。有没有可能是多个请求在几乎相同的时间调用,把事情搞砸了?例如,Request1>user.id=1 Request2>user.id=2 Response1>获取user.id=2导致错误我认为这不应该是任何问题,因为django将为用户传递的每个请求创建一个新的请求对象,无论两个不同的用户同时查询,查询将通过上下文处理器,并且将选择特定的数据库,因此就我所知不会有交叉交互。@kt14嗨,我真的不明白我们如何将user.id注入router类。在链接的代码段中,我们使用threading.local()来共享这个,但我无法使它在django 2.1.4上工作。可能对此有一些更改?好的,很抱歉,这是因为使用了Django版本的中间件。添加了init和call,现在一切都好了。嘿@Kartheek,谢谢你的回答!虽然我很感激,但我最终还是选择了kt14,因为我发现他的答案更容易实现,因为我的项目涉及近百个视图,因此为每个视图编写代码是不可行的。谢谢你抽出时间@Lorenzo我提到了内联注释,您可以将该逻辑转移到中间件。这是另一种实施方式。不管怎样,我很高兴你找到了解决办法。