如何在Django会话模型中设置自定义字段?

8

根据这个示例,我在Django中扩展了会话。简而言之,我添加了一个名为account_id的字段来保存会话所属用户的用户ID。

一切都很顺利,但我添加的自定义字段account_id在登录时没有被设置。要设置它:

from django.contrib import auth
from MyApp.models import CustomSession

def login(request):
    username = request.POST['username']
    password = request.POST['password']
    user = auth.authenticate(username=username, password=password)
    if user is not None:
        try:
            auth.login(request, user)
            session_key = request.session.session_key
            # CODE HERE
            if session_key is not None:
                return HttpResponse(json.dumps({'status': 'Success'}))
            else:
                return HttpResponse(json.dumps({'status': 'Fail'}))

我已经尝试将以下内容放入CODE HERE,但都没有起作用:
  1. request.session.model.account_id = user.id

  2. session = CustomSession.objects.get(pk=session_key)
    session.account_id = user.id
    session.modified = True
    
  3. request.session.account_id = user.id
  4. request.session[account_id] = user.id
在每次尝试中,数据库中的account_id都是NULL
我在这里漏掉了什么?

1
你为什么要这样做?在99.9%的情况下,不需要以这种方式连接会话和用户。 - trixn
@trixn 我正在尝试轻松获取在线用户列表。 - Utku
这将如何帮助您做到这一点? - Daniel Roseman
@DanielRoseman 当用户断开连接时,我会注销他们(用户使用WebSockets连接,因此我可以知道他们是否已连接)。因此,在任何给定的时间,会话表将告诉我在线用户列表。 - Utku
1
我不知道在扩展Django的Session类后应该把我的代码放在哪里。文档中包含代码,但没有包含放置位置。有人可以指导如何向数据库添加额外字段吗? - Vikash
2个回答

4

如果您想要在session表中自定义名称或创建自定义字段,您可以按照以下步骤进行。

定义自定义session后端:

my_project
    my_project/
        settings.py
        session_backend.py
        ...
    user/
        models.py
        ...

from django.contrib.sessions.backends.db import SessionStore as DBStore
import user


class SessionStore(DBStore):

    @classmethod
    def get_model_class(cls):
        return user.models.MySession

    def create_model_instance(self, data):
        """
        overriding the function to save the changes to db using `session["user_id"] = user.id` .
        This will create the model instance with the custom field values. 
        When you add more field to the custom session model you have to update the function 
        to handle those fields as well.
        """
        obj = super().create_model_instance(data)
        try:
            user_id = data.get('user_id')
        except (ValueError, TypeError):
            user_id = None

        obj.user_id = user_id
        return obj

然后在 settings.py 中导入您的自定义类。

SESSION_ENGINE = "my_project.session_backend"

在应用程序中的models.py文件中定义自定义模型,例如user

from django.contrib.sessions.models import Session


class MySession(Session):
    # you can also add custom field if required like this user column which can be the FK to the user table 
    user = models.ForeignKey('user', on_delete=models.CASCADE) 

    class Meta:
        app_label = "user"
        db_table = "my_session"

现在运行以下命令进行迁移:

python manage.py makemigrations
python manage.py migrate

完成 :)

3
谢谢,这个方法可行,但是由于递归导入的原因,我还必须将会话模型放在session_backend.py中。 - julian

1
你忽略了CustomSession是一个模型;你需要保存实例,而不是像版本2中所做的那样在其上设置“modified”。
session = CustomSession.objects.get(pk=session_key)
session.account_id = user.id
session.save()

没有运气。这个也不起作用。account_id 仍然是 NULL - Utku
我的猜测是Django在退出“login”方法时以某种方式重新保存了会话,但省略了“account_id”。 - Utku

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接