You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django3.2迁移报错UndefinedTable: relation "user" does not exist

Django 部署执行migrate报错:relation "user" does not exist

已尝试的排查操作

  • 删除所有应用下的迁移文件
  • 新建数据库并重新生成迁移文件,仍然出现相同报错

异常现象

  • 部署完成后在服务器本地运行Django应用,使用curl在服务器本地调用API(例如用户注册接口)可正常执行,但查看数据库时对应表为空,user表甚至无字段展示,其余表可正常查看字段。
    数据库表异常截图
  • 通过服务器对外端点调用API时返回500错误,异常信息如下:

    relation "user" does not exist
    LINE 1: SELECT (1) AS "a" FROM "user" WHERE "user"."email" = '

  • 执行migrate后可正常创建超级用户,但尝试登录时返回500错误,同样提示UndefinedTable: relation "user" does not exist
    登录报错截图

基础环境与配置

  • 运行环境:Python 3.10、Django 3.2
  • 核心配置项:
AUTH_USER_MODEL = 'registration.User'

相关代码

models.py

from django.db import models
import uuid
from django.db import models
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils import timezone
from .managers import CustomUserManager
from rest_framework_simplejwt.tokens import RefreshToken

AUTH_PROVIDERS = {'facebook': 'facebook', 'google': 'google',
                  'twitter': 'twitter', 'email': 'email'}

class User(AbstractBaseUser, PermissionsMixin):
    A = 1
    I = 2
    C = 3

    USER_ROLE = (
        (A, 'A'),
        (I, 'I'),
        (C, 'C')
    )

    uuid = models.UUIDField(unique=True, editable=False, default=uuid.uuid4)
    username = models.CharField(max_length=255, unique=True, db_index=True)
    email = models.EmailField(unique=True)
    first_name = models.CharField(max_length=50, blank=True)
    last_name = models.CharField(max_length=50, blank=True)
    role = models.PositiveSmallIntegerField(choices=USER_ROLE, blank=True, null=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    is_verified = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    is_deleted = models.BooleanField(default=False)
    created_date = models.DateTimeField(default=timezone.now)
    modified_date = models.DateTimeField(default=timezone.now)
    auth_provider = models.CharField(
        max_length=255, blank=False,
        null=False, default=AUTH_PROVIDERS.get('email'))
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username', 'role']

    objects = CustomUserManager()

    class Meta:
        db_table = 'user'
        verbose_name = 'user'
        verbose_name_plural = 'users'

    def __str__(self):
        return self.email

    def save(self, *args, **kwargs):
        self.is_staff = True if self.role == self.ADMIN else False
        self.is_superuser = True if self.role == self.ADMIN else False
        super(User, self).save(*args, **kwargs)

    def tokens(self):
        refresh = RefreshToken.for_user(self)
        return {
            'refresh': str(refresh),
            'access': str(refresh.access_token)
        }

managers.py(CustomUserManager)

from django.contrib.auth.base_user import BaseUserManager
from django.utils.translation import ugettext_lazy as _


class CustomUserManager(BaseUserManager):
    """
    自定义用户管理器,以邮箱作为唯一认证标识
    """

    def create_user(self, username, email, role, password=None):
        if username is None:
            raise TypeError('Users should have a username')
        if email is None:
            raise TypeError('Users should have a Email')

        user = self.model(username=username, role=role, email=self.normalize_email(email))
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, username, role, email, password=None):
        if password is None:
            raise TypeError('Password should not be none')
        user = self.create_user(
            username,
            email,
            role,
            password=password,
        )
        user.is_staff = True
        user.is_superuser = True
        user.save(using=self._db)
        return user

views.py

renderer_classes = (UserRenderer,)
permission_classes = [AllowAny]

def post(self, request):
    user = request.data
    serializer = self.serializer_class(data=user)
    serializer.is_valid(raise_exception=True)
    serializer.save()
    user_data = serializer.data
    user = User.objects.get(email=user_data['email'])
    token = RefreshToken.for_user(user).access_token
    current_site = get_current_site(request).domain
    relativeLink = reverse('email-verify')
    absurl = 'http://' + current_site + relativeLink + "?token=" + str(token)
    email_body = 'Hi ' + user.username + \
                    ' Use the link below to verify your email \n' + absurl
    data = {'email_body': email_body, 'to_email': user.email,
            'email_subject': 'Verify your email'}

    mail.send(
                [user.email],
                "abc@gmail.com",
                subject='Account Verification',
                message=email_body,
                priority='now',
            )
    return Response(user_data, status=status.HTTP_201_CREATED)

serializer.py

class RegisterSerializer(serializers.ModelSerializer):

    password = serializers.CharField(
        max_length=68, min_length=6, write_only=True)
    role = serializers.IntegerField(write_only=True)

    default_error_messages = {
        'username': 'The username should only contain alphanumeric characters'}

    class Meta:
        model = User
        fields = ['email', 'username', 'password', 'role']

    def validate(self, attrs):
        email = attrs.get('email', '')
        username = attrs.get('username', '')
        role = attrs.get('role', '')

        if not username.isalnum():
            raise serializers.ValidationError(
                self.default_error_messages)
        return attrs

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

修复步骤

  1. 优先排查服务多实例数据库连接不一致问题:本地curl调用正常、外部访问报错,是典型的多进程加载不同配置的表现——对外提供服务的Gunicorn/Uwsgi进程没有重启,仍在连接旧的空数据库/其他数据库实例,本地手动执行的runserver连接的是新建的数据库。先全量重启所有Django相关服务进程,确认所有进程加载同一份配置文件、连接同一个数据库地址。
  2. 修复代码硬bug:
    • User模型的save方法中引用了未定义的self.ADMIN常量,模型内仅定义了A/I/C三个角色常量,执行用户保存操作时会抛出属性错误,中断表创建/数据写入流程,将判断逻辑修改为对应常量:
      def save(self, *args, **kwargs):
          self.is_staff = True if self.role == self.A else False
          self.is_superuser = True if self.role == self.A else False
          super(User, self).save(*args, **kwargs)
      
    • managers.py中导入的ugettext_lazy在Django 3.2版本已标记为废弃,替换为正式导入from django.utils.translation import gettext_lazy as _,避免导入异常。
  3. 重新执行迁移:
    • 清空目标数据库所有表
    • 删除所有app下migrations目录内除__init__.py外的所有文件
    • 依次执行python manage.py makemigrations、python manage.py migrate
    • 重启所有服务进程,验证表结构与接口逻辑

内容的提问来源于stack exchange,提问作者wizard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 08:54:19