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
相关产品推荐
相关产品推荐

