Django REST Framework APITestCase无法创建ElephantSQL测试数据库
Django REST Framework测试数据库权限问题排查
我正在学习Python/Django REST Framework的测试方法,已经成功连接ElephantSQL免费版(tiny turtle)数据库并创建数据表,但使用APITestCase测试注册视图时遇到权限问题。
测试代码
import json from django.contrib.auth.models import User from django.urls import reverse from rest_framework.authtoken.models import Token from rest_framework.test import APITestCase from rest_framework import status from users.serializers.common import RegistrationSerializer, UserSerializer class RegistrationTestCase(APITestCase): def test_registration(self): data = {'username': 'testuser', 'email': 'test@email.com', 'password': 'super_unique_password', 'password_confirmation': 'super_unique_password'} # Add a test user to database response = self.client.post('/api/auth/register/', data) # Test that 201 status is receieved self.assertEqual(response.status_code, status.HTTP_201_CREATED)
settings.py数据库配置
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': env('DATABASE_NAME'), 'HOST': env('DATABASE_HOST'), 'PORT': 5432, 'USER': env('DATABASE_USER'), 'PASSWORD': env('DATABASE_PASS'), }, 'test': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': env('DATABASE_NAME'), 'HOST': env('DATABASE_HOST'), 'PORT': 5432, 'USER': env('DATABASE_USER'), 'PASSWORD': env('DATABASE_PASS'), } }
测试执行错误信息
执行命令 python manage.py test --verbosity=2 后报错:
Found 1 test(s). Skipping setup of unused database(s): test. Creating test database for alias 'default' ('test_<database_name_here>')... /home/ben_kelly/.local/share/virtualenvs/Siege_of_the_Citadel_Companion-eBaHHEGM/lib/python3.10/site-packages/django/db/backends/postgresql/base.py:407: RuntimeWarning: Normally Django will use a connection to the 'postgres' database to avoid running initialization queries against the production database when it's not needed (for example, when running tests). Django was unable to create a connection to the 'postgres' database and will use the first PostgreSQL database instead. warnings.warn( Got an error creating the test database: permission denied to create database
疑问
- 如何排查是哪个用户触发了权限不足的问题?是settings.py中配置的数据库用户,还是psql登录用户?已确认psql用户为超级用户且拥有CREATEDB权限。
- 移除settings中的test数据库配置后仍报错,且自定义的test数据库未被使用,如何强制APITestCase使用test数据库?
- 添加的测试数据库别名打印代码未执行,请求相关帮助。
问题分析与解决步骤
1. 权限问题的触发用户排查
Django执行测试时,使用的是settings.py中配置的DATABASE_USER对应的远程数据库用户,和本地psql登录用户无关。ElephantSQL免费版(tiny turtle)默认不提供创建数据库的权限,即便本地用户是超级用户,远程用户的权限限制才是报错核心。
验证方式:直接用ElephantSQL提供的用户登录远程数据库,执行 CREATE DATABASE test_db;,会直接返回permission denied to create database,确认权限限制。
2. 强制使用自定义test数据库的方法
Django默认会自动创建test_<原数据库名>的测试库,但ElephantSQL不支持创建新库,需要修改配置让测试复用现有数据库(注意:测试会清空数据,建议提前备份):
修改settings.py:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': env('DATABASE_NAME'), 'HOST': env('DATABASE_HOST'), 'PORT': 5432, 'USER': env('DATABASE_USER'), 'PASSWORD': env('DATABASE_PASS'), } } # 测试环境配置,复用现有数据库 import sys if 'test' in sys.argv: DATABASES['default']['TEST'] = { 'NAME': env('DATABASE_NAME'), 'MIGRATE': True, }
如果要强制使用之前配置的test数据库别名,需要在测试类中指定:
class RegistrationTestCase(APITestCase): databases = ['test'] # 指定使用test别名的数据库 def test_registration(self): # 测试代码...
但注意:ElephantSQL免费版无法创建新库,test别名指向的是和默认库同名的远程库,本质还是同一个数据库,不如直接复用默认库更简单。
3. 测试数据库别名打印代码未执行的解决
如果打印代码没执行,排查两点:
- 代码位置错误:要把打印代码放在测试类的
setUp方法或测试方法中,比如:
class RegistrationTestCase(APITestCase): def setUp(self): from django.db import connections print("当前使用的数据库别名:", connections.databases)
- 测试文件命名不符合规范:Django只会自动发现以
test_开头的测试文件(比如test_registration.py),如果文件名不对,测试不会被执行。
额外建议
ElephantSQL免费版限制较多,不适合作为测试环境,建议:
- 本地安装PostgreSQL作为测试数据库
- 或在测试环境切换为SQLite,避免远程权限限制:
import sys if 'test' in sys.argv: DATABASES['default'] = { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': 'test_db.sqlite3', }
内容的提问来源于stack exchange,提问作者Phaliaetus
相关产品推荐
相关产品推荐

