251

When I try to test any app with command (I noticed it when I tried to deploy myproject using fabric, which uses this command):

python manage.py test appname

I get this error:

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 command seems to work. My database settings in 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.
    }
}
3cheesewheel
  • 9,133
  • 9
  • 39
  • 59
Andrius
  • 19,658
  • 37
  • 143
  • 243

15 Answers15

496

When Django runs the test suite, it creates a new database, in your case test_finance. The postgres user with username django does not have permission to create a database, hence the error message.

When you run migrate or syncdb, Django does not try to create the finance database, so you don't get any errors.

You can add the createdb permission to the django user by running the following command in the postgres shell as a superuser (hat tip to this stack overflow answer).

=> ALTER USER django CREATEDB;

Note: The username used in the ALTER USER <username> CREATEDB; command needs to match the database user in your Django settings files. In this case, the original poster, had the user as django the above answer.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • 3
    Though the OP used postgresql, if you are using mysql you will have the same error. You can fix it for mysql with: => GRANT ALL ON \*.\* TO django@localhost; I originally tried to only GRANT CREATE... but then could not SELECT or DROP the created database. This essentially makes your user a superuser, so be careful. – mightypile Dec 31 '15 at 16:28
  • 1
    I experimented a little and found the minimum global priviledges are - Data: SELECT, INSERT, UPDATE, DELETE, Structure: CREATE, ALTER, INDEX, DROP, Admin: REFERENCES. Not a super-user, but still pretty powerful, so use caution. – Scott Jan 06 '16 at 17:52
  • 1
    for my case I grant all priviliges to te test database, something like this: `GRANT ALL PRIVILEGES ON test_my_db.* TO 'my_user'@'localhost';` – Yacine Rouizi Apr 10 '20 at 22:08
26

I have found interesting solution to your problem.
In fact for MySQL you can grant privileges for non-existing database.
So you can add name 'test_finance' for your test database in your settings:

    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',
        },
    }
}

start MySQL shell as the root user:

mysql -u root -p

and now grant all privileges to this non-existing database in MySQL:

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

Now Django will start tests without any problems.

Yurii Halapup
  • 1,282
  • 19
  • 19
10

If the database is MySQL then these two changes will get things done.

1.Open mysite/mysite/settings.py

Your database settings should have an additional 'TEST' block as shown with projectname_test.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'myproject',
        'USER': 'chandan',
        'PASSWORD': 'root',
        'HOST': 'localhost',
        'PORT': '3306',
        'TEST': {
            'NAME': 'myproject_test',
        },
    }
}

2.Type the below command using mysql command prompt or mysql workbench to give all privilages to the user specified in settings.py

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

Now you can run the below command:

python manage.py test polls
Javad
  • 2,033
  • 3
  • 13
  • 23
Chandan
  • 704
  • 7
  • 20
  • The question obviously uses Postgres as DBMS. What would *projectname_test* relate to? – code-kobold Jul 30 '17 at 08:32
  • @code-kobold 7,Yes,but i can see the same error in mysql as well.The value projectname_test is refer to name of project ex.in my answer it is myproject. – Chandan Jul 30 '17 at 15:49
  • For MySQL use: grant all on myproject_test.* to 'chandan'@'%'; – borko Mar 29 '23 at 20:36
10

In the case of Postgres, the user must have createdb permission.

ALTER ROLE miriam CREATEDB;

See this documentation: https://docs.djangoproject.com/en/2.0/topics/testing/overview/#the-test-database

Robert Columbia
  • 6,313
  • 15
  • 32
  • 40
Noufal Valapra
  • 510
  • 6
  • 12
7

In my case, I don't know why GRANT PRIVILEGES solutions don't work with Python 3.7.2, Django 2.1.7, and MySQL 5.6.23. So I decided to use SQLite as a TEST database:

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'),
        },
    }
}

After that, the tests can run without trouble:

$ 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
Javad
  • 2,033
  • 3
  • 13
  • 23
JavierFuentes
  • 1,840
  • 18
  • 13
  • At first, this appeared to be a great idea. But I tried it and it doesn't seem to work. I now see in the docs that specifying `ENGINE` in `TEST` [is not an option](https://docs.djangoproject.com/en/3.1/ref/settings/#test). Also, I noticed you commented out the MySQL back end and added the connector. What's that? – nicorellius Oct 20 '20 at 01:48
  • 1
    You seem to have used different databases for the production and test environment. That may not be a good idea, and can cause database specific bugs. – Joel G Mathew Dec 15 '21 at 06:01
5

Wow so combining all of the answers here with a little tweaking finally got me to a working solution for docker-compose, django, and postgres...

First the postgres command given by noufal valapra is not correct (or maybe just not current), it should be:

ALTER USER docker WITH CREATEDB;

In the case of a docker-compose setup, this will go in the init.sql file, this is what mine looks like:

CREATE USER docker;
ALTER USER docker WITH CREATEDB;
CREATE DATABASE djangodb;
GRANT ALL PRIVILEGES ON DATABASE djangodb TO docker;

Then the Dockerfile for postgres looks like this:

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

Then the Django settings.py has this entry:

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'],
        }
    }

and the docker-compose looks like this:

version: '3.6'

services:

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:
Paul Jacobs
  • 430
  • 5
  • 11
5

Switch over to the postgres account on your server by typing:

sudo -i -u postgres

You can now access a Postgres prompt immediately by typing:

psql

Now type

ALTER USER username CREATEDB;
4

If you are using docker-compose what worked for me was the following:

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

or

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

My settings looks like this:

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

and my docker-compose.yml looks as follows:

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"
lmiguelvargasf
  • 63,191
  • 45
  • 217
  • 228
2

I ran into the same problem a while ago. This is how I was able to solve it on django 3.10.6

First get into your dbshell via terminal by using this command

python3 manage.py dbshell

This will take you to your projects db ie if you have created one. The other way to get to your db is:

sudo su postgres

then:

psql

This will take you to the default database. Then connect to your projects db by:

\c projectdb

At this point use this command to fix your error:

ALTER USER you CREATEDB;

Quit your db with '\q'; exit postgres with 'exit' then run:

python3 manage.py test app

The error will be fixed and your test will pass

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

A superuser account is the easiest way to guarantee smooth testing. so a simpler way of making the django user su is to do ALTER django WITH SUPERUSER .

for more information https://www.postgresql.org/docs/current/sql-alteruser.html

  • 2
    `ALTER USER django WITH SUPERUSER`, you forgot the `USER` keyword. I tried to edit your post, but the edit que is full and won't free up. – run_the_race Sep 16 '20 at 06:59
1

Check the the actions in runtime and switch your database

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"),
        }
    }}
7guyo
  • 3,047
  • 1
  • 30
  • 31
0

Maybe you put your test in suspended mode or as a backgrounded job. Try with fg command in bash shell.

0

You can also just create a test database manually but putting the TEST key in your settings.py

Then fill pass the MIRROR key with value 'default' so you can test off of an exact replica of your default db, or whichever db you like.

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'finance',
        'USER': 'django',
        'TEST': {
             'MIRROR': 'default',
        },
        'PASSWORD': 'mydb123',
        'HOST': '127.0.0.1',
        'PORT': '',
    }
}

You can also check the advanced django postgres docs

Travis
  • 29
  • 1
  • 3
  • 1
    It is a wrong approach because will use the real database to write persistent data into the database. Not being able to delete after. – Elias Prado Dec 13 '21 at 13:54
0

I am facing the same issue for

pytest

I altered the django user permission so that it can create a test database while running python test cases.

ALTER USER USERNAME CREATEDB;

bansi923
  • 839
  • 8
  • 8
0

As the error suggests the user does not have sufficient permissions to create a database. Django creates a separate database during tests so that our original development database is not affected.

We might need to give the permissions via Postgres shell.

DATABASES = {
'default': {
    'ENGINE': 'django.db.backends.postgresql_psycopg2',
    'NAME': config('DB_NAME'),
    'USER': "myuser",
    'PASSWORD': config('DB_PASSWORD'),
    'HOST': config('DB_HOST'),
    'PORT': config('DB_PORT'),

    'TEST': {
        'NAME': 'test_nofoobar',
    },
}

}

As the settings suggest, the name of the database user is myuser in this case. So, let's start the Postgres shell and give database creation permission.

sudo -u postgres psql


psql (14.5 (Ubuntu 14.5-1.pgdg22.04+1))

postgres=# ALTER ROLE myuser CREATEDB;
Output: ALTER ROLE
nofoobar
  • 2,826
  • 20
  • 24