如何存储和检索 Django 会话变量 to/from 数据库?

How can I store and retrieve Django session variable to/from database?

我的 Django 网站目前由两台机器使用负载均衡器提供服务。我想从一台机器上维护与用户相对应的会话。我知道我可以将我的负载均衡器配置为使用粘性会话,这样来自用户的所有请求都将由同一台服务器提供服务。 但是我想使用会话变量来实现相同的目的。

这就是我如何将该会话变量存储在中央数据库中,任何服务器都可以从该数据库访问该用户的会话,因此任何服务器都可以通过使用该会话变量存储来为其提供服务。 但是我无法理解流程以及如何在 Django 中实现相同的流程。

所以我的问题是如何为用户将会话保存在数据库中,以便任何服务器能够访问它并相应地处理请求。在这种情况下,那些 login() 和 logout 将如何工作?

我也有多个数据库。我计划将一个用于用户身份验证和其他内容,另一个用于与网站相关的数据存储。或者任何人至少可以向我解释如何实现这一目标的流程。

我假设您已经对系统进行了扩展,并且目前您正在使用负载均衡器从两台机器上为您的网站提供服务。您想知道在不使用粘性会话的情况下,我们如何为其会话维护服务器和客户端之间的连接。

您还在评论中说您可能拥有多个数据库,这些数据库可以服务于不同的事物,也可以托管在某个远程位置。此外,由于您已指定您的数据库之一将处理与用户相关的内容和其他与网站相关的内容。

首先,我想给你一个关于如何实现这一点的工作流程:

  • 在您的 setting.py 文件中指定多个数据库。
  • 为您的每项任务建立一个中央数据库
  • 无论何时保存任何数据(如果未指定路由器),使用 using 参数指定您指的是哪个数据库。
  • 与其每次手动指定数据库,不如使用 Router 更好。
  • 请记住用户身份验证和会话,您不必将其显式存储在数据库中,一旦您在 setting.py 文件中指定它,django 就会处理它。因为您所有的服务器机器都将连接到同一个数据库以进行身份​​验证和填充。
  • 您的所有服务器都将使用同一个中央数据库来存储客户端和服务器之间 HTTP 连接的会话变量,从而维护状态。

所以这是对如何实现相同目标的简要概述。现在让我们在代码中看到这一点。

在 setting.py 文件中指定多个数据库

DATABASES 词典中指定您要使用的所有数据库。当您没有明确指定要将数据保存到的数据库时,将使用默认值,所有其他内容都将使用默认值进行读写。如果您明确想要为每个数据库指定,那么您需要小心始终指定要用于 store/retrieval 的数据库。

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'app_data',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': 'XXXX',
    },
    'auth_db': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'auth_db',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': 'XXXX',
    },
}

为用户和网站相关内容明确指定不同的数据库

DATABASES = {
    'default': {},
    'auth_db': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'auth_db',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': 'XXXX',
    },
    'customers': {
        'ENGINE': 'django.db.backends.postgresql',
        'NAME': 'customers',
        'USER': 'mydatabaseuser',
        'PASSWORD': 'mypassword',
        'HOST': '127.0.0.1',
        'PORT': 'XXXX',
    }
}

Django 要求定义一个默认的数据库条目,但如果不使用,参数字典可以留空。在这种情况下,您必须明确指定在保存数据时将使用哪个数据库,或者您可以为此指定 ROUTER

如果您尝试访问未在 DATABASES setting 中定义的数据库,Django 将引发 django.db.utils.ConnectionDoesNotExist 异常。

正在同步数据库

migrate 管理命令一次对一个数据库进行操作。默认情况下,它在 default 数据库上运行,但通过提供 --database 选项,您可以告诉它同步不同的数据库。

示例:

$ python manage.py migrate --database=users
$ python migrate --database=customers

路由来自不同数据库的用户身份验证和网站相关数据

我们希望自动处理,而不是每次都使用 using 参数指定数据库名称。我们需要处理路由。首先,我们想要一个知道将对 auth 和 contenttypes 应用程序的查询发送到 auth_db

的路由器
class AuthRouter:
    """
    A router to control all database operations on models in the
    auth and contenttypes applications.
    """
    route_app_labels = {'auth', 'contenttypes'}

    def db_for_read(self, model, **hints):
        """
        Attempts to read auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.route_app_labels:
            return 'auth_db'
        return None

    def db_for_write(self, model, **hints):
        """
        Attempts to write auth and contenttypes models go to auth_db.
        """
        if model._meta.app_label in self.route_app_labels:
            return 'auth_db'
        return None

    def allow_relation(self, obj1, obj2, **hints):
        """
        Allow relations if a model in the auth or contenttypes apps is
        involved.
        """
        if (
            obj1._meta.app_label in self.route_app_labels or
            obj2._meta.app_label in self.route_app_labels
        ):
           return True
        return None

    def allow_migrate(self, db, app_label, model_name=None, **hints):
        """
        Make sure the auth and contenttypes apps only appear in the
        'auth_db' database.
        """
        if app_label in self.route_app_labels:
            return db == 'auth_db'
        return None

类似地,您可以为其他数据库创建路由器。

最后,在设置文件中,我们添加以下内容(将 path.to. 替换为定义路由器的模块的实际 Python 路径):

DATABASE_ROUTERS = ['path.to.AuthRouter', 'path.to.OtherDBRouter']

处理路由器的顺序很重要。路由器将按照它们在 DATABASE_ROUTERS 设置中列出的顺序进行查询。在此示例中,AuthRouter 在 OtherDBRouter 之前处理,因此,在做出任何其他决定之前处理有关 auth 中模型的决定。

Retrieving/Storing数据from/to数据库。

安装此设置后,运行 一些 Django 代码:

>>> # This retrieval will be performed on the 'auth_db' database
>>> fred = User.objects.get(username='fred')
>>> fred.first_name = 'Frederick'

>>> # This save will also be directed to 'auth_db'
>>> fred.save()

默认路由方案确保对象保持“粘性”到其原始数据库(即,从 foo 数据库检索的对象将保存在同一数据库中)。默认路由方案确保如果未指定数据库,所有查询都会回退到默认数据库。

正在创建模型

现在您一定在考虑如何在这种情况下为不同的数据库创建模型,以便我们可以使用 Django 的 ORM 功能。

在这种情况下,您必须指定到数据库名称的映射。

在您的 setting.py 文件中添加

DATABASE_APPS_MAPPING = {'user_data': 'auth_db',
                        'customer_data':'customers'}

相应机型修改为

class User(models.Model):
    username = models.Charfield(ax_length=100)
    class Meta:
        app_label = 'user_data'

class Customer(models.Model):
    name = models.TextField(max_length=100)
    class Meta:
        app_label = 'customer_data'

有关详细信息和为 store/retrieval 手动选择数据库的信息。 Django 还提供了一个 API 允许您在代码中保持对数据库使用的完全控制。手动指定的数据库分配将优先于路由器分配的数据库。 请参考docs.