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

Django测试时users表未自动创建的报错问题及解决思路

问题描述

我正在用Selenium为Django Web应用编写测试用例,Django本应自动生成包含所有数据表的测试数据库,但自定义Users模型后,运行python3.9 manage.py test -v3时触发报错:

pymysql.err.ProgrammingError: (1146, "Table 'test_civiledb.users' doesn't exist")

我的Users模型代码如下:

from django.db import models
from django.db import connection
import pymysql

class Users(models.Model):

    firstname=models.CharField(max_length=100)
    lastname=models.CharField(max_length=100) 
    username=models.CharField(max_length=50)
    password=models.CharField(max_length=255)
    admin=models.IntegerField()
    createdAt=models.DateTimeField(db_column="created_at")

    def __init__(self,*args, **kwargs):
        super().__init__(*args, **kwargs)
        print("nel costruttore model Users")

    def getAdmin(self):
        return self.admin

    class Meta:
        db_table = 'users'

    def getUser(self,username):
        cursor = connection.cursor()
        cursor.execute('''SELECT id, 
                            username, 
                            password,
                            admin,
                            firstname,
                            lastname,
                            created_at 
                            FROM users 
                            WHERE username = %s''',[username])

        result = cursor.fetchone()
                 
        return result

    def setPassword(self,userId,password):
        cursor = connection.cursor()
        
        try:
            cursor.execute('''UPDATE users  
                            SET password = %s 
                            WHERE id = %s''',[password,userId])
            connection.commit()
        except Exception as e:
            print(e)
            connection.rollback()
            return False
        finally:
            connection.close()
        
        return True

我目前想到的方案是在测试用例的setUp方法中执行CREATE TABLE语句创建表,在tearDown方法中删除该表,但想知道有没有更规范的解决方式。

解决方案

1. 确认模型所在应用已注册到INSTALLED_APPS

Django只会为INSTALLED_APPS列表里的应用生成数据库表。打开settings.py,检查是否包含Users模型所在的应用:

INSTALLED_APPS = [
    # 其他已注册应用
    '你的应用名称',  # 替换为Users模型所在的应用名
]

2. 改用Django ORM替代原生SQL操作

你自定义的getUser和setPassword方法直接用原生SQL,还手动关闭了数据库连接,这会干扰Django的测试数据库管理。换成ORM不仅更规范,还能让测试自动处理表结构:

# 修改后的Users模型
from django.db import models

class Users(models.Model):
    firstname = models.CharField(max_length=100)
    lastname = models.CharField(max_length=100) 
    username = models.CharField(max_length=50, unique=True)  # 建议添加唯一约束
    password = models.CharField(max_length=255)
    admin = models.IntegerField()
    createdAt = models.DateTimeField(db_column="created_at")

    def __init__(self,*args, **kwargs):
        super().__init__(*args, **kwargs)
        print("nel costruttore model Users")

    def getAdmin(self):
        return self.admin

    class Meta:
        db_table = 'users'

    # 用ORM替代原生SQL查询
    def getUser(self, username):
        try:
            user = Users.objects.get(username=username)
            return (user.id, user.username, user.password, user.admin, user.firstname, user.lastname, user.createdAt)
        except Users.DoesNotExist:
            return None

    # 用ORM替代原生SQL更新
    def setPassword(self, userId, password):
        try:
            user = Users.objects.get(id=userId)
            user.password = password
            user.save()
            return True
        except Users.DoesNotExist:
            return False

3. 生成并应用迁移文件

就算模型存在,没生成迁移文件的话,Django测试时也不会自动建表。执行以下命令生成并应用迁移:

python3.9 manage.py makemigrations
python3.9 manage.py migrate

测试时Django会自动把迁移应用到测试数据库,不需要手动创建表。

4. 若必须保留原生SQL(不推荐)

如果一定要用原生SQL,别手动关闭connection,Django会自动管理连接生命周期。修改setPassword方法:

def setPassword(self,userId,password):
    cursor = connection.cursor()
    try:
        cursor.execute('''UPDATE users  
                        SET password = %s 
                        WHERE id = %s''',[password,userId])
        connection.commit()
    except Exception as e:
        print(e)
        connection.rollback()
        return False
    # 移除finally里的connection.close()
    return True

5. 临时方案:手动在测试中管理表(不推荐)

如果以上方法都没解决,你提到的setUp/tearDown手动建表可以作为临时方案,但要保证SQL语句和模型字段完全匹配:

from django.test import TestCase

class YourTestCase(TestCase):
    def setUp(self):
        with connection.cursor() as cursor:
            cursor.execute('''
                CREATE TABLE users (
                    id INT AUTO_INCREMENT PRIMARY KEY,
                    firstname VARCHAR(100) NOT NULL,
                    lastname VARCHAR(100) NOT NULL,
                    username VARCHAR(50) NOT NULL UNIQUE,
                    password VARCHAR(255) NOT NULL,
                    admin INT NOT NULL,
                    created_at DATETIME NOT NULL
                )
            ''')

    def tearDown(self):
        with connection.cursor() as cursor:
            cursor.execute('DROP TABLE users')

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 09:09:21