【问题标题】:merge django's auth_user with existing user table将 django 的 auth_user 与现有的用户表合并
【发布时间】:2018-02-17 00:47:38
【问题描述】:

目前我有一个旧版应用程序,它引用了一个包含所有自定义字段的 user 表。由于有大量遗留代码引用该表,我不能简单地将表重命名为auth_user。所以我想做的事情是以某种方式合并(我不知道这是正确的术语)auth_useruser

下面是user 表:

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| user_id           | int(10)      | NO   | PRI | NULL    | auto_increment |
| name              | varchar(100) | NO   |     | NULL    |                |
| address           | varchar(100) | NO   |     | NULL    |                |
| phone_no          | varchar(15)  | NO   |     | NULL    |                |
| city              | varchar(100) | NO   |     | NULL    |                |
| state             | varchar(100) | NO   |     | NULL    |                |
| pin_no            | int(10)      | NO   |     | NULL    |                |
| type              | varchar(100) | NO   |     | NULL    |                |
| email             | varchar(100) | NO   |     | NULL    |                |
| password          | varchar(100) | NO   |     | NULL    |                |
| is_active         | tinyint(1)   | NO   |     | NULL    |                |
| role              | varchar(40)  | NO   |     | NULL    |                |
| creation_date     | int(100)     | NO   |     | NULL    |                |
| edit_date         | int(100)     | NO   |     | NULL    |                |
| country           | varchar(255) | NO   |     | NULL    |                |
| district          | varchar(255) | NO   |     | NULL    |                |
| ip                | varchar(255) | NO   |     | NULL    |                |
| added_by          | int(11)      | NO   |     | NULL    |                |
| is_phone_verified | binary(1)    | NO   |     | 0       |                |
| remember_token    | varchar(100) | YES  |     | NULL    |                |
| disclaimer_agreed | int(11)      | YES  |     | 0       |                |
| mobile_login      | tinyint(4)   | NO   |     | 0       |                |
+-------------------+--------------+------+-----+---------+----------------+

和 django 的 auth_user 表:

+--------------+--------------+------+-----+---------+----------------+
| Field        | Type         | Null | Key | Default | Extra          |
+--------------+--------------+------+-----+---------+----------------+
| id           | int(11)      | NO   | PRI | NULL    | auto_increment |
| password     | varchar(128) | NO   |     | NULL    |                |
| last_login   | datetime(6)  | YES  |     | NULL    |                |
| is_superuser | tinyint(1)   | NO   |     | NULL    |                |
| username     | varchar(150) | NO   | UNI | NULL    |                |
| first_name   | varchar(30)  | NO   |     | NULL    |                |
| last_name    | varchar(30)  | NO   |     | NULL    |                |
| email        | varchar(254) | NO   |     | NULL    |                |
| is_staff     | tinyint(1)   | NO   |     | NULL    |                |
| is_active    | tinyint(1)   | NO   |     | NULL    |                |
| date_joined  | datetime(6)  | NO   |     | NULL    |                |
+--------------+--------------+------+-----+---------+----------------+

我想要的是一个单一的表,django 将在使用contrib.auth 相关的东西时引用它,同时也不会弃用我的旧代码。也许是这样的:

+-------------------+--------------+------+-----+---------+----------------+
| Field             | Type         | Null | Key | Default | Extra          |
+-------------------+--------------+------+-----+---------+----------------+
| user_id           | int(10)      | NO   | PRI | NULL    | auto_increment |
| name              | varchar(100) | NO   |     | NULL    |                |
| address           | varchar(100) | NO   |     | NULL    |                |
| phone_no          | varchar(15)  | NO   |     | NULL    |                |
| city              | varchar(100) | NO   |     | NULL    |                |
| state             | varchar(100) | NO   |     | NULL    |                |
| pin_no            | int(10)      | NO   |     | NULL    |                |
| type              | varchar(100) | NO   |     | NULL    |                |
| email             | varchar(100) | NO   |     | NULL    |                |
| password          | varchar(100) | NO   |     | NULL    |                |
| is_active         | tinyint(1)   | NO   |     | NULL    |                |
| role              | varchar(40)  | NO   |     | NULL    |                |
| creation_date     | int(100)     | NO   |     | NULL    |                |
| edit_date         | int(100)     | NO   |     | NULL    |                |
| country           | varchar(255) | NO   |     | NULL    |                |
| district          | varchar(255) | NO   |     | NULL    |                |
| ip                | varchar(255) | NO   |     | NULL    |                |
| added_by          | int(11)      | NO   |     | NULL    |                |
| is_phone_verified | binary(1)    | NO   |     | 0       |                |
| remember_token    | varchar(100) | YES  |     | NULL    |                |
| disclaimer_agreed | int(11)      | YES  |     | 0       |                |
| mobile_login      | tinyint(4)   | NO   |     | 0       |                |
| last_login        | datetime(6)  | YES  |     | NULL    |                |
| is_superuser      | tinyint(1)   | NO   |     | NULL    |                |
| username          | varchar(150) | NO   | UNI | NULL    |                |
| first_name        | varchar(30)  | NO   |     | NULL    |                |
| last_name         | varchar(30)  | NO   |     | NULL    |                |
| is_staff          | tinyint(1)   | NO   |     | NULL    |                |
| is_active         | tinyint(1)   | NO   |     | NULL    |                |
| date_joined       | datetime(6)  | NO   |     | NULL    |                |
+-------------------+--------------+------+-----+---------+----------------+

这里的动机是利用 Django 的内置 authenticationpermission 系统,但不破坏遗留代码。我认为必须有一个解决方案,因为这不是第一次有人将一些遗留应用程序移植到 django。

我还想提一下这个链接How to Extend Django User Model,但我不确定哪种方法最好采用,或者我应该做一些完全不同的事情

【问题讨论】:

  • 我不明白你为什么要合并它们。为什么不在它们之间添加一对一的关系?
  • auth_user 表未填充,而user 表中有很多条目。还进行一对一的关系意味着我可能不得不在某些时候使用连接,这可能不适用于restframework 现有的序列化程序/视图集
  • 这仍然不意味着您需要合并它们,这意味着您需要使用自己的自定义模型,这是有据可查的。
  • 如果我从auth_user 继承作为代理模型会怎样,这里建议simpleisbetterthancomplex.com/tutorial/2016/07/22/… 解决了我猜的很多麻烦
  • 不,根本不需要。看我的回答。

标签: python mysql django django-rest-framework django-authentication


【解决方案1】:

Django 明确支持自定义用户模型。为现有表创建一个模型,使其从 AbstractBaseUser 继承,并将 AUTH_USER_MODEL 设置设置为指向您的新模型。请参阅comprehensive docs

【讨论】:

  • 这真的很有帮助,但它清楚地表明 - Don’t forget to point AUTH_USER_MODEL to it. Do this before creating any migrations or running manage.py migrate for the first time - 我已经超出了这一步。如果我现在改变这个,它会有什么影响?我是否应该删除在上述步骤中创建的那些表,然后将 AUTH_USER_MODEL 指向它,然后重新运行新的迁移?
  • 是的,如果您仍在开发中,最好的办法是删除数据库,删除迁移,然后重新创建它们。
  • 如果我不能删除现有的用户表并重新运行迁移怎么办?
  • 自从我最初写这篇文章以来,指南已经改变,请参阅changing to a custom user model mid-project 上的更新文档。
【解决方案2】:

我们可以从Django ticket 中详细了解如何从内置用户模型迁移到自定义用户模型。

引用Carsten Fuchs

假设

  • 您的项目还没有自定义用户模型。
  • 必须保留所有现有用户。
  • 没有挂起的迁移,所有现有的迁移都已应用。
  • 即使您使用版本控制签出旧版本,所有以前的迁移都丢失并且不能再取消应用是可以接受的 仍然具有迁移文件的提交。这是相关的 这种方法的缺点。

准备工作

  • 确保任何引用 Django User 模型的第三方应用程序仅使用generic referencing methods
  • 确保您自己的可重用应用(打算供他人使用的应用)使用通用引用方法。
  • 我建议不要对您的项目应用程序执行相同的操作:切换到自定义用户模型在每个项目中只执行一次,以后不再执行。它 更容易(在我看来也更清楚)将from django.contrib.auth.models import User 更改为其他内容(详细 下面)而不是用不需要的通用引用替换它 在项目代码中。
  • 确保您有代码和数据库的备份!

更新代码

  • 您可以在任何现有应用或新创建的应用中创建新用户模型。我的偏好是创建一个新应用:

    ./manage.py startapp Accounts
    

我选择了“Accounts”这个名称,但任何其他名称也可以。

  • Aymeric:“创建与auth.User 相同的自定义用户模型,将其命名为User(因此多对多表保持相同名称)并设置 db_table='auth_user'(所以它使用同一张表)。“在 Accounts/models.py:

    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    
    class User(AbstractUser):
    class Meta:
            db_table = 'auth_user'
    
  • settings.py 中,将应用添加到INSTALLED_APPS 并更新AUTH_USER_MODEL 设置:

    INSTALLED_APPS = (
        # ...
        'Accounts',
    )
    
    AUTH_USER_MODEL = 'Accounts.User'
    
  • 在您的项目代码中,替换 Django 用户模型的所有导入:

    from django.contrib.auth.models import User with the new, custom one:
    

    从 Accounts.models 导入用户

  • 删除所有旧迁移。 (事先看comment 14是否与你相关!)例如在项目根目录中:

    find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
    find . -path "*/migrations/*.pyc" -delete
    
  • 从头开始创建新的迁移:

    ./manage.py makemigrations
    
  • 根据需要对 admin.py 文件进行任何更改。 (我不能在这里提供任何可靠的信息,但这对结果并不重要,并且 所以细节仍然可以稍后查看。)

  • 确保您的测试套件成功完成! (必须使用新的测试数据库,它不能保留以前的运行。)
  • 至此,对代码的更改就完成了。这是提交的好时机。

请注意,我们已经完成了 - 除了新的迁移文件不匹配 django_migrations 表的内容。

(此时甚至可以为您的项目提供服务:它是 在实际更改数据库之前很容易退出。 做 如果您了解您甚至无法触摸迁移,则可以这样做 系统只要以下步骤没有完成!)

更新数据库

  • 截断 django_migrations 表。 MySQL 8 示例:

      TRUNCATE TABLE django_migrations;
    

这可能与其他数据库或 MySQL 版本不同

  • 假应用新的迁移集 ./manage.py 迁移 --fake

  • 检查 comment 12 中所述的 ContentTypes

结论

  • 到自定义用户模型的升级现已完成。您可以更改此模型并为其生成和应用迁移,就像使用 任何其他型号。
  • 作为第一步,您可能希望取消设置 db_table 并生成并应用生成的迁移。
  • 在我看来,startproject 管理命令应该可以预见到自定义用户模型的引入。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-30
    • 1970-01-01
    • 2019-03-25
    • 2014-07-27
    相关资源
    最近更新 更多