【问题标题】:Django, BigIntegerField, and django.contrib.auth.user.idDjango、BigIntegerField 和 django.contrib.auth.user.id
【发布时间】:2010-01-07 19:38:05
【问题描述】:

Django 现在提供了一个 BigIntegerField 用于 django 模型(在 svn trunk 和 1.2 alpha-1 版本中可用)。

我需要我的 django.contrib.auth.user 模型将 BigIntegerField 作为其自动递增的主键,而它目前使用自动递增的 IntegerField 作为其主键。此外,无论哪里 contrib.auth.user 用作 ForeginKey,它也需要是 BigIntegerField。

实现这一目标的最佳和最安全的方法是什么?

【问题讨论】:

标签: django biginteger django-contrib


【解决方案1】:

虽然我不确定为什么您需要在 User 上使用 BigIntegerField(您必须拥有大量用户),但它很容易实现。首先,您需要获得像South 这样的数据库迁移系统。我们将使用它对您当前的数据进行少量迁移。如果您的数据库中没有任何内容,则忽略这部分并跳到最后。

我会先创建一个继承自 contrib.auth 版本的自定义用户类,如下所示:

from django.contrib.auth.models import User, UserManager
from django.db import models

class BigUser(User):
    id = models.BigIntegerField(pk = True)

    objects = UserManager() 
    #this lets you transperantly use any 
    #query methods that you could on User

然后使用 South 的数据迁移功能将你们所有人的 User.objects.all() 复制到新的 BigUser 模型中。

然后在需要的每个模型中添加一个外键。 请勿删除原来的 FK,否则您的链接将丢失。添加新密钥后,再进行一次架构迁移。

然后进行另一次数据迁移,将 FK 从旧用户模型复制到新的 BigUser 模型。迁移该数据。

然后可以安全地将旧 FK 删除到 User 模型。

如果您想避免更改其余代码以使用 BigUser 的新字段名称,您可以使用 South rename-field 实用程序(South 无法自动检测字段重命名,因此请务必阅读文档)。

如果您在数据库中没有任何数据,那么您可以简单地实现上面的类并将其放入您当前的模型中。

如果您在编写数据迁移时需要帮助,您必须发布一两个模型。

由于您需要“直接”替代User,因此您还需要两个步骤: 首先,我们需要创建一个自定义身份验证后端,以确保任何身份验证请求都发送到您的新模型,并且request.user 返回BigUser 而不是User。只需将此 sn-p 剪切并粘贴到与 settings.py 位于同一目录中的名为 auth_backend.py 的文件中:

from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_model

class CustomUserModelBackend(ModelBackend):
    def authenticate(self, username=None, password=None):
        try:
            user = self.user_class.objects.get(username=username)
            if user.check_password(password):
                return user
        except self.user_class.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return self.user_class.objects.get(pk=user_id)
        except self.user_class.DoesNotExist:
            return None

    @property
    def user_class(self):
        if not hasattr(self, '_user_class'):
            self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.', 2))
            if not self._user_class:
                raise ImproperlyConfigured('Could not get custom user model')
        return self._user_class

然后在您的 settings.py 文件中,您需要添加此后端并设置自定义用户模型设置...像这样:

AUTHENTICATION_BACKENDS = (
    'auth_backends.CustomUserModelBackend',
)
...

CUSTOM_USER_MODEL = 'your-app-name.BigUser'

最后一段代码来自另一个website,描述了用户模型的子类化。

现在,在其余代码中“插入”所需要做的就是将所有 from django.contrib.auth.models import User 替换为 from your-app-name import BigUser as User。通过这样做,您不必用BigUser 更新任何User 的引用

【讨论】:

  • 这很清楚,但这会透明地工作吗?我的意思是身份验证、登录、注销、组等都可以按预期工作吗?我需要做什么才能继续无缝使用 django.contrib.auth?
  • @gbsmith 我更新了答案以允许更好的直接替换,希望对您有所帮助。
  • @JudoWill 阅读您的代码,连同您提供的网站链接以及 Django 文档,我不得不说这看起来不错。在我在我的应用程序中尝试之前,我不会将此标记为正确答案,我想尝试一下 contrib.auth.group 的行为方式
  • 这似乎对 contrib.admin 有影响
【解决方案2】:

我正在权衡更改 django.contrib.auth.models.user 的代码以包含一个 id 字段作为 BigIntegerField 主键的选项。

在我看来是最好的方法。

(我准备通过sql手动迁移数据)

【讨论】:

  • 不像我想象的那么容易。 Django 的 AutoField 是 IntegerField 而不是 BigIntegerField。指定 primary=True 解决了一个问题,而不是两个。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
  • 2018-04-06
  • 2013-10-27
  • 2015-08-07
  • 2016-05-04
  • 2011-10-02
相关资源
最近更新 更多