Django测试应用程序错误 - 创建测试数据库时出错:没有权限创建数据库。

256

当我尝试使用命令行测试任何应用程序时(我注意到这一点是在尝试使用使用此命令的Fabric部署我的项目时),会出现以下情况:

python manage.py test appname

我遇到了这个错误:

Creating test database for alias 'default'...
Got an error creating the test database: permission denied to create database

Type 'yes' if you would like to try deleting the test database 'test_finance', or 'no' to cancel

syncdb 命令似乎有效。我的 settings.py 文件中的数据库设置为:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'finance',                      # Or path to database file if using sqlite3.
        'USER': 'django',                      # Not used with sqlite3.
        'PASSWORD': 'mydb123',                  # Not used with sqlite3.
        'HOST': '127.0.0.1',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
    }
}
15个回答

503

当Django运行测试套件时,它会创建一个新的数据库,此处为test_finance。由于postgres用户的用户名是django,没有权限创建数据库,因此会出现错误信息。

当您运行migratesyncdb时,Django不会尝试创建finance数据库,所以您不会收到任何错误消息。

您可以在作为超级用户的postgres shell中运行以下命令,将createdb权限添加给django用户(感谢此stack overflow答案)。

=> ALTER USER django CREATEDB;

注意:ALTER USER <username> CREATEDB;命令中使用的用户名需要与您 Django 设置文件中的数据库用户匹配。在这种情况下,原帖作者将用户设置为 django ,如上所述回答。


3
尽管原帖使用了postgresql,但如果你使用的是mysql,你也会遇到相同的错误。你可以通过执行以下命令来解决mysql的问题:=> GRANT ALL ON . TO django@localhost; 我最初尝试授予CREATE权限...但随后无法SELECT或DROP已创建的数据库。这实际上使得你的用户成为超级用户,所以请小心操作。 - mightypile
1
我进行了一些实验,并发现最小的全局权限为 - 数据:SELECT、INSERT、UPDATE、DELETE,结构:CREATE、ALTER、INDEX、DROP,管理员:REFERENCES。虽然不是超级用户,但仍然非常强大,因此请谨慎使用。 - Scott
2
对于我的情况,我授予测试数据库所有权限,类似这样:GRANT ALL PRIVILEGES ON test_my_db.* TO 'my_user'@'localhost'; - Yacine Rouizi

26

我已经找到了一个有趣的解决方案来解决您的问题。
实际上,对于MySQL,您可以授予不存在的数据库的权限。
因此,您可以在设置中为测试数据库添加名称“test_finance”:

    DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
        'NAME': 'finance',                      # Or path to database file if using sqlite3.
        'USER': 'django',                      # Not used with sqlite3.
        'PASSWORD': 'mydb123',                  # Not used with sqlite3.
        'HOST': '127.0.0.1',                      # Set to empty string for localhost. Not used with sqlite3.
        'PORT': '',                      # Set to empty string for default. Not used with sqlite3.
        'TEST': {
            'NAME': 'test_finance',
        },
    }
}

以 root 用户身份启动 MySQL shell:

mysql -u root -p

现在在MySQL中授予所有权限给这个不存在的数据库:

GRANT ALL PRIVILEGES ON test_finance.* TO 'django'@'localhost';

现在Django将会无任何问题地开始测试。


在mysql shell中,我收到了“ERROR 1410 (42000): You are not allowed to create a user with GRANT”的错误信息。请问有什么想法吗? - harryghgim
正如您所看到的,我已经以root用户身份启动了MySQL shell。 - Yurii Halapup
我喜欢这个答案。这不会让Django项目的用户成为数据库超级用户。 - AcaNg

10

10
如果数据库是MySQL,那么这两个更改将完成任务。
1.打开mysite/mysite/settings.py 你的数据库设置应该有一个额外的'TEST'块,如所示,其中包括projectname_test
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': 'chandan',
        'PASSWORD': 'root',
        'HOST': 'localhost',
        'PORT': '3306',
        'TEST': {
            'NAME': 'myproject_test',
        },
    }
}

2. 使用mysql命令提示符mysql workbench输入以下命令,为在settings.py中指定的用户授予所有权限:

GRANT ALL PRIVILEGES ON myproject_test.* TO 'chandan'@'localhost';

现在你可以运行以下命令:

python manage.py test polls

这个问题显然使用Postgres作为DBMS。projectname_test是什么相关的? - code-kobold
@code-kobold 7,是的,但我在MySQL中也看到了相同的错误。projectname_test的值是指项目名称,例如,在我的答案中它是myproject。 - Chandan
对于MySQL使用:授予'chandan'@'%'所有权限于myproject_test数据库。 - borko
对于MySQL使用:grant all on myproject_test.* to 'chandan'@'%'; - borko

7

在我的情况下,我不知道为什么 GRANT PRIVILEGES 解决方案无法与 Python 3.7.2Django 2.1.7MySQL 5.6.23 兼容。

所以我决定使用 SQLite 作为 TEST 数据库:

DATABASES = {
    'default': {
        'NAME': 'productiondb',
        'ENGINE': 'mysql.connector.django',   # 'django.db.backends.mysql'
        'USER': '<user>',
        'PASSWORD': '<pass>',
        'HOST': 'localhost',
        'PORT': 3306,
        'OPTIONS': {
            'autocommit': True,
        },
        'TEST': {
            'ENGINE': 'django.db.backends.sqlite3',
            'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
        },
    }
}

之后,测试可以无障碍运行:

$ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (0 silenced).

Destroying test database for alias 'default'...
----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

Process finished with exit code 0

起初,这似乎是个好主意。但我尝试了一下,它似乎不起作用。现在我在文档中看到,在TEST中指定ENGINE不是一个选项。此外,我注意到你注释掉了MySQL后端并添加了连接器。那是什么? - nicorellius
1
您似乎在生产和测试环境中使用了不同的数据库。这可能不是一个好主意,会导致特定于数据库的错误。 - Joel G Mathew

5

通过键入以下命令,切换到您服务器上的Postgres账户:

sudo -i -u postgres

现在,您可以通过键入以下内容立即访问Postgres提示符:

psql

现在输入

ALTER USER username CREATEDB;

5

哇,结合这里所有的答案,并稍作调整,最终使我找到了一种针对docker-compose、django和postgres的工作解决方案...

首先,noufal valapra提供的postgres命令不正确(或者可能只是不够最新),应该是:

ALTER USER docker WITH CREATEDB;

在docker-compose设置中,这将放在init.sql文件中,这是我的样式:
CREATE USER docker;
ALTER USER docker WITH CREATEDB;
CREATE DATABASE djangodb;
GRANT ALL PRIVILEGES ON DATABASE djangodb TO docker;

那么,针对postgres的Dockerfile如下所示:

FROM postgres:10.1-alpine
COPY init.sql /docker-entrypoint-initdb.d/

然后,Django的settings.py文件中有这个条目:

if 'RDS_DB_NAME' in os.environ:
    INTERNAL_DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': os.environ['RDS_DB_NAME'],
            'USER': os.environ['RDS_USERNAME'],
            'PASSWORD': os.environ['RDS_PASSWORD'],
            'HOST': os.environ['RDS_HOSTNAME'],
            'PORT': os.environ['RDS_PORT'],
        }
    }

以下是Docker Compose文件的示例:

版本: '3.6'

服务:

postgresdb:
  build:
    context: ./
    dockerfile: ./Dockerfile-postgresdb
  volumes:
    - postgresdata:/var/lib/postgresql/data/

django:
  build:
    context: ../
    dockerfile: ./docker/Dockerfile
  environment:
    - RDS_DB_NAME=djangodb
    - RDS_USERNAME=docker
    - RDS_PASSWORD=docker
    - RDS_HOSTNAME=postgresdb
    - RDS_PORT=5432

  stdin_open: true
  tty: true
  depends_on:
    - postgresdb

volumes:
    postgresdata:

4
如果你正在使用docker-compose,以下内容适用于我:

如果您正在使用docker-compose,对我有用的是以下内容:

ALTER ROLE username CREATEDB;
GRANT ALL PRIVILEGES ON test_database_name.* TO 'username';

或者

ALTER ROLE username CREATEDB;
GRANT ALL PRIVILEGES ON *.* TO 'username'@'%';

我的设置如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'database_name',
        'USER': 'username',
        'PASSWORD': 'password',
        'HOST': 'db',
        'PORT': '3306',
    }
}

我的 docker-compose.yml 文件如下:

version: '3'
services:
  web:
      build: .
      command: './wait_for_db_and_start_server.sh'
      env_file: env_web
      working_dir: /project_name
      links:
        - db
      volumes:
        - .:/volume_name
      ports:
        - "8000:8000"
      depends_on:
        - db
  db:
    image: mysql:5.7
    restart: always
    env_file: env_db
    working_dir: /db
    volumes:
      - ./Dump.sql:/db/Dump.sql
    ports:
      - "3306:3306"

2

我之前遇到了同样的问题。

以下是我在Django 3.10.6上解决它的方法:

首先,通过终端进入您的dbshell,使用以下命令:

python3 manage.py dbshell

这将带您进入您的项目数据库,即如果您已经创建了一个。

到达数据库的另一种方法是:

sudo su postgres

然后:

psql

这将带您进入默认数据库。然后通过以下方式连接到您的项目数据库:

\c projectdb

在这个时候,使用以下命令来修复您的错误:

ALTER USER you CREATEDB;

使用 '\q' 命令退出数据库,使用 'exit' 命令退出 PostgreSQL,然后运行以下命令:

python3 manage.py test app

错误将被修复,您的测试将通过。
Found 1 test(s).
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
.
----------------------------------------------------------------------
Ran 1 test in 0.003s

OK
Destroying test database for alias 'default'...

1

在运行时检查操作并切换数据库

import sys
TESTING = sys.argv[1:2] == ['test']
if TESTING==False:
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            'NAME': config('DB_NAME'),
            'USER': config('DB_USER'),
            'PASSWORD': config('DB_PASSWORD'),
            'HOST': config('DB_HOST'),
            'PORT': ''
             }       
           }
else:
    DATABASES = {    
        'default': {
        "ENGINE": "django.db.backends.sqlite3",
        "TEST": {
            "NAME": os.path.join(BASE_DIR, "test_db.sqlite3"),
        }
    }}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接