Django & Vue 项目踩坑记:no such table: accounts_user ; django.db.migrations.exceptions.InconsistentMigrat

功能期望

  1. 基于Django提供的AbstractUser类重写User模型,在其中根据业务需求增加信息,并将新的用户模型设为系统默认用户模型。
  2. 使用新的自定义User模型创建超级用户和普通用户。
    其中,自定义用户模型的部分参考了如下链接中的代码:

[1] Django自定义User模型以及用户系统(用户、权限、组)的使用

部分代码如下所示:

from django.contrib.auth.models import BaseUserManager,AbstractUser
from shortuuidfield import ShortUUIDField # 使用shortuuid作为User表的主键,使数据更加的安全

class UserManager(BaseUserManager): #自定义Manager管理器
    def _create_user(self,username,password,email,**kwargs):
        if not username:
            raise ValueError("请传入用户名!")
        if not password:
            raise ValueError("请传入密码!")
        if not email:
            raise ValueError("请传入邮箱地址!")
        user = self.model(username=username,email=email,**kwargs)
        user.set_password(password)
        user.save()
        return user

    def create_user(self,username,password,email,**kwargs): # 创建普通用户
        kwargs['is_superuser'] = False
        return self._create_user(username,password,email,**kwargs)

    def create_superuser(self,username,password,email,**kwargs): # 创建超级用户
        kwargs['is_superuser'] = True
        kwargs['is_staff'] = True
        return self._create_user(username,password,email,**kwargs)

class User(AbstractUser): # 自定义User
    GENDER_TYPE = (
        ("1","男"),
        ("2","女")
    )
    uid = ShortUUIDField(primary_key=True)
    username = models.CharField(max_length=15,verbose_name="用户名",unique=True)
    nickname = models.CharField(max_length=13,verbose_name="昵称",null=True,blank=True)
    age = models.IntegerField(verbose_name="年龄",null=True,blank=True)
    gender = models.CharField(max_length=2,choices=GENDER_TYPE,verbose_name="性别",null=True,blank=True)
    phone = models.CharField(max_length=11,null=True,blank=True,verbose_name="手机号码")
    email = models.EmailField(verbose_name="邮箱")
    picture = models.ImageField(upload_to="Store/user_picture",verbose_name="用户头像",null=True,blank=True)
    home_address = models.CharField(max_length=100,null=True,blank=True,verbose_name="地址")
    card_id = models.CharField(max_length=30,verbose_name="身份证",null=True,blank=True)
    is_active = models.BooleanField(default=True,verbose_name="激活状态")
    is_staff = models.BooleanField(default=True,verbose_name="是否是员工")
    date_joined = models.DateTimeField(auto_now_add=True)

    USERNAME_FIELD = 'username' # 使用authenticate验证时使用的验证字段,可以换成其他字段,但验证字段必须是唯一的,即设置了unique=True
    REQUIRED_FIELDS = ['email'] # 创建用户时必须填写的字段,除了该列表里的字段还包括password字段以及USERNAME_FIELD中的字段
    EMAIL_FIELD = 'email' # 发送邮件时使用的字段

    objects = UserManager()

    def get_full_name(self):
        return self.username

    def get_short_name(self):
        return self.username

    class Meta:
        verbose_name = "用户"
        verbose_name_plural = verbose_name

问题描述

  1. 我在上一篇帖子中已经描述了遇到的一个坑,但是按照上一篇文章完成了数据库的migrate后,我发现在前端调用自己编写的函数去访问User模型内的所有对象时,出现了 no such table: accounts_user 的报错。
  2. 根据上述问题,我尝试了一些解决方案,其中包括重新makemigrations 和 migrate,但是都没有用!!!makemigrations提示我没有需要修改的地方,migrate同样提示我没有需要修改的地方!! 我尝试直接使用 pyton manage.py createsuperuser 指令创建管理员,但是在我输入用户名后,Django直接返回报错:django.db.utils.OperationalError: no such table: accounts_user
    完整报错如下所示:
Traceback (most recent call last):
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\sqlite3\base.py", line 383, in execute
    return Database.Cursor.execute(self, query, params)
sqlite3.OperationalError: no such table: accounts_user

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "manage.py", line 21, in <module>
    main()
  File "manage.py", line 17, in main
    execute_from_command_line(sys.argv)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\core\management\__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\core\management\__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\core\management\base.py", line 323, in run_from_argv
    self.execute(*args, **cmd_options)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 61, in execute
    return super().execute(*args, **options)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\core\management\base.py", line 364, in execute
    output = self.handle(*args, **options)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 95, in handle
    error_msg = self._validate_username(username, verbose_field_name, database)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\contrib\auth\management\commands\createsuperuser.py", line 201, in _validate_username
    self.UserModel._default_manager.db_manager(database).get_by_natural_key(username)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\contrib\auth\base_user.py", line 44, in get_by_natural_key
    return self.get(**{self.model.USERNAME_FIELD: username})
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\models\manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\models\query.py", line 402, in get
    num = len(clone)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\models\query.py", line 256, in __len__
    self._fetch_all()
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\models\query.py", line 1242, in _fetch_all
    self._result_cache = list(self._iterable_class(self))
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\models\query.py", line 55, in __iter__
    results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\models\sql\compiler.py", line 1100, in execute_sql
    cursor.execute(sql, params)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\utils.py", line 99, in execute
    return super().execute(sql, params)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\utils.py", line 67, in execute
    return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\utils.py", line 76, in _execute_with_wrappers
    return executor(sql, params, many, context)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\utils.py", line 89, in __exit__
    raise dj_exc_value.with_traceback(traceback) from exc_value
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\utils.py", line 84, in _execute
    return self.cursor.execute(sql, params)
  File "D:\ProgramData\Anaconda3\envs\Django2\lib\site-packages\django\db\backends\sqlite3\base.py", line 383, in execute
    return Database.Cursor.execute(self, query, params)
django.db.utils.OperationalError: no such table: accounts_user
  1. 我还尝试stackoverflow上的一些方法(当然最多的还是makemigrations 和 migrate,但是我真的想吐槽,如果这么简单的方法能解决也不会有那么多人去问了啊。。。):比如让我删除项目内的所有migrations文件夹以及__pycache__文件夹,并且删除db.sqlite3数据库,之后重新运行makemigrations 和 migrate, 然后我就遇到了新的报错:django.db.migrations.exceptions.InconsistentMigrationHistory

事情到这里陷入了僵局,还有人说要把settings.py里的INSTALLED_APPS内的’django.contrib.admin’语句注释掉的。

INSTALLED_APPS = [
	...
    # 'django.contrib.admin',
    ...
    ]

试了一下直接报错: "No install app with label admin"
评论区也有很多伙计说这样不行。
在这里插入图片描述
so, 难道就这样放弃了嘛?
不存在的,新建一个全新的project,让我们来测试一下!

问题分析

  1. 首先,在上面遇到的种种错误中,基本都是和数据库相关,自定义的UserModel是没有什么问题的,所以我新建了一个project,运行了migrate指令初始化数据库,又在其中新建了一个app,将上述自定义UserModel拷贝到accounts app下的model.py文件内,并在settings.py中进行了app的注册和AUTH_USER_MODEL的声明。完成上述任务后,我又一次运行了migrate指令,结果遇到了报错:
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency accounts.0001_initial on database 'default'.
  1. 仿佛有了一点头绪,这个报错提到了很关键的一点,“Migration admin.0001_initial is applied before its dependency accounts.0001_initial”,那么问题可能出现在原始的migrations文件和我们的新定义的用户模型之间存在冲突。

那么现在应该怎么办?
一个字: “删!”

解决方案

  1. 删除项目内和app内的migrations文件夹以及__pycache__文件夹、以及数据库db.sqlite3, 数据库是一定要删的,因为数据库里存储了默认的user模型,我尝试不删除数据库,结果还是抛出错误:InconsistentMigrationHistory;
  2. 运行 python manage.py makemigrations accounts, 这里的accounts是创建的用来实现用户模型的app。一定要精确到这个app,否则直接运行makemigrations的话,Django可能会提示 no change,对,就是这么坑。
    运行过后,提示如下:
Migrations for 'accounts':
  accounts\migrations\0001_initial.py
    - Create model User
  1. 运行 python manage.py migrate accounts, 提示如下:可以看到django重新对所有model进行了配置。
Operations to perform:
  Apply all migrations: accounts
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0001_initial... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying accounts.0001_initial... OK
  1. 让我们使用 python manage.py createsuperuser 来测试一下!
    在这里插入图片描述
    成功!!!

原因分析

  1. 数据库中的django migrations table是导致不一致的原因,仅仅从本地路径删除所有的migrations是行不通的。
  2. 应该从数据库中截断(truncate)migrations,并重新makemigrations和migrate;

按照Django官方的说法:用户最好在migrate项目的数据库之前应用自己的自定义模型(哪怕仅仅是声明),否则可能会遇到不可预知的错误。

参考资料

[1] stackoverflow_django.db.migrations.exceptions.InconsistentMigrationHistory
[2] stackoverflow_django.db.utils.OperationalError: no such table: auth_user
[3] CSDN_自定义Django用户模型
[4] stackoverflow_User Registration with error: no such table: auth_user
[5] Django官方文档:Customizing authentication in Django

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值