首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

如何切换到一个自定义Django用户模型Mid-Project

Django文档建议开发者始终使用一个自定义的用户模型来启动项目(即使它与Django的用户模型一开始是相同的),以便在以后需要时更容易地进行自定义。但是,如果你在启动一个项目时没有看到这一点,或者继承了一个没有自定义用户模型的项目,需要添加一个用户模型,那么你应该怎么做呢?

在Caktus,当Django第一次添加对自定义用户模型的支持时,我们仍然使用South进行迁移。难以置信!大约六年前,我写了一篇关于迁移到自定义用户模型的文章,当然,由于Django内置了对数据库迁移的支持,这个模型在很大程度上已经过时了。因此,我觉得为那些需要在Django 2.0+上的现有项目添加自定义用户模型的任何人编写一篇新文章是有帮助的。

背景

在本文发布时,Django票数跟踪器中针对这个问题添加进一步文档的Ticket#25313是开放的。这个Ticket中包含了一些在切换到自定义用户模型时需要遵循的高级步骤,我建议你首先熟悉这些步骤。正如文档中“切换到一个自定义用户模型mid-project”下面所指出的, “在创建数据库表之后更改AUTH_USER_MODEL要困难得多,比如,它会影响外部键和多对多关系。”

我放在下面的指南在一定程度上与Ticket #25313中的高级指南有一些不同,我认为(希望)它们是积极的和破坏性较小的方式。尽管如此,这个Ticket已经开放了四年多,这是有原因的,因为它很难。因此,正如这个Ticket中提到的:

在更改生产数据库之前,请谨慎进行,并确保你有一个数据库备份(以及一个恢复它的工作流程)。

概述

下面的步骤1和步骤2与2013年(大约是Django 1.5)的步骤1和步骤2相同,之后的情况会有所不同,因为我们现在使用的是Django的内置迁移(而不是South)。在高级层面上,我们的策略是在我们自己的应用程序中创建一个模型,它具有与auth.User相同的所有字段,并使用相同的底层数据库表。然后,我们为自定义用户模型伪造初始迁移,并彻底测试更改,并将所有内容部署到生产环境中。一旦完成之后,你的项目中就会有一个自定义的用户模型,正如Django文档中建议的那样,你可以继续根据自己的喜好对它进行调整。

与其他一些方法(包括我2013年的文章)相反,这次我选择更新现有的auth_user表,以帮助确保现有的外键引用保持完整。这样做的缺点是,目前需要对数据库进行一些手工操作。不过,如果你正在使用具有引用完整性检查(你应该这样做)的数据库,那么你在晚上就会睡得更安稳,因为你知道你没有搞砸一个影响数据库中所有用户的数据迁移。

如果你(以及其他一些人)能够确认以下内容对你有效,那么这个过程的某些迭代可能会在某个时候被加入到Django文档中。

迁移过程

下面是我切换到一个自定义用户模型mid-project的方法:

0. 假设:

你有一个没有自定义用户模型的现有项目。

你正在使用Django的迁移,所有迁移都是最新的(并且已经应用到生产数据库中)。

你需要保留一组现有的用户,以及指向Django内置User模型的任意数量的模型。

首先,评估任何第三方应用程序,确保它们没有任何对Django的User模型的引用,或者即使引用了,也要使用Django的通用方法来引用用户模型。

接下来,对你自己的项目执行相同的操作。遍历代码,寻找可能对User模型的任何引用,并用相同的泛型引用替换它们。简而言之,你可以使用get_user_model()方法直接获取模型,或者如果你需要为用户模型创建一个外键或其他数据库关系,则可以使用settings.AUTH_USER_MODEL (它只是一个与指向该用户模型的appname.ModelName路径相对应的简单字符串。)

注意,get_user_model()不能在任何models .py文件中以模块级别被调用(扩展为models.py导入的任何文件),因为你最终将得 到一个循环导入。通常,在可能的情况下,将get_user_model()的调用保存在一个方法中(因此它是在运行时被调用的,而不是 在加载被时调用的),并在所有其他情况中使用settings.AUTH_USER_MODEL,会变得更容易一些。这并不总是可行的(例如, 在创建ModelForm时),但是你在模块级别上使用它的次数越少,就越可能避免循环导入。

启动一个新的users应用程序(或者给它另一个你选择的名字,比如accounts)。如果你喜欢,你可以使用一个现有的应用程序,但它必须是一个没有任何预先存在的迁移历史的应用程序,因为正如Django文档中所提到的,“由于受到可交换模型的Django动态依赖特性的局限,由AUTH_USER_MODEL引用的模型必须在它的应用程序的第一次迁移中被创建 (通常称为0001 _initial);不然的化,你就会遇到依赖问题。”

通过一个 db_table向users/models.py添加一个新的User模型,db_table将使该User模型使用与现有的 auth.User模型相同的数据库表。为了在以后更新内容类型时变得简单一点(并且如果你希望底层数据库模式中的多对多表命名与你的用户模型的名称匹配的话),你应该像我在这里所做的那样称它为User。如果你愿意,稍后可以对它重命名。

为了方便起见,如果你希望在运行时通过admin来检查这个用户模型,请在users/admin.py中为此添加一个入口:

在 settings.py中,将 users 添加到 INSTALLED_APPS 中,并设置 AUTH_USER_MODEL = 'users.User':

为你的新User模型创建一个初始迁移:

你应该会得到一个新的迁移文件users/migration /0001_initial.py。

因为auth_user表已经存在,所以在这种情况下,我们通常会使用python manage.py migrate users --fake-initial命令来伪造本次迁移。但是,如果你现在尝试运行它,你将得到一个InconsistentMigrationHistory错误,因为Django会在伪造这个迁移之前进行一次完整性检查,该检查会阻止这个伪造迁移的应用。特别是,它不允许伪造此迁移,因为其他会依赖于它,也就是说,包含对settings.AUTH_USER_MODEL的引用的任何迁移都已经运行了。我并不完全确定Django为什么对伪造迁移设置这种限制,因为所有的重点就是告诉它迁移实际上已经被应用了(如果你知道为什么,请在下面评论)。相反,你也可以通过手动将你的新users应用程序的初始迁移添加到迁移历史中来实现相同的结果:

如果你使用的是users以外的应用程序名称,请使用包含你的用户模型的Django应用程序的名称替换上面一行中的users。

同时,让我们用用户模型的新app_label来更新django_content_types表,这样对该内容类型的现有引用将保持不变。与之前的数据库更改一样,必须在运行migrate之前进行此更改。这样做的原因是,migrate将创建任何不存在的内容类型,这将阻止你使用新的应用程序标签去更新旧的内容类型(会返回一个“重复键值违反唯一约束”错误)。

同样,如果你将应用程序命名为users以外的名称,请确保使用你选择的应用程序名称更新上面的SET app_label = 'users'。

注意,此SQL只用于Postgres,对于其他数据库后端可能会有所不同。

此时,你应该停止并将所有内容部署到模拟环境中,因为在手动调整迁移历史之前尝试运行迁移将会失败。如果你的自动化部署过程运行了migrate(它可能会这样做),那你需要在migrate之前运行这两个SQL语句去更新这个过程 (尤其是因为migrate会为你创建任何不存在的内容类型,从而防止你在没有进一步调整的情况下更新数据库中的现有内容类型)。在模拟环境中彻底测试这个过程(甚至可能会多次),以确保你正确地自动化了所有内容。

在测试和修复任何错误之后,并在确保你有良好的备份和在出现问题时恢复它的流程之后,你就应该将目前为止的所有内容部署到生产环境中(和/或你需要保存现有用户数据库的任何其他环境)。

现在,你应该能够对你的users.User模型进行更改,并根据需要运行 makemigrations / migrate。例如,作为第一步,你可能希望将auth_user表重命名为你的users应用程序名称空间中的某个名称。你可以通过从你的User模型中删除db_table来实现这一点,所以它看起来是这样的:

你还需要创建和运行一个新的迁移,使这个更改在数据库中生效:

成功了吗?

应该是这样。现在,你应该可以对你自定义的User模型进行其他更改了(并为这些更改创建迁移)。你可以进行哪种类型的更改以及如何进行这些更改超出了本文的范围,所以我建议你仔细阅读Django文档中关于如何替换自定义User模型的内容。如果你选择从AbstractUser切换到AbstractBaseUser,请确保在从数据库中删除这些列之前,为你想保留的AbstractUser提供的任何字段创建数据迁移。想了解更多关于这个话题的信息,请查看我们关于2017年度Django大会的文章,其中我们链接到了Julia M Looney的一篇题为“充分利用Django的用户模型”的演讲。我的同事Dmitriy也有一个很棒的帖子,里面有一些其他的建议,可以帮助你挑选旧的项目。

再次强调一下,在生产环境中进行测试之前,请在模拟环境中仔细测试,并确保你有一个工作数据库备份。祝你好运,请在下面评论任何成功或失败的故事,或者关于如何改进这个过程的想法!

英文原文:https://www.caktusgroup.com/blog/2019/04/26/how-switch-custom-django-user-model-mid-project/

译者:一瞬

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190626A05UK100?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券