Błąd aplikacji testowej django - wystąpił błąd podczas tworzenia testowej bazy danych: odmowa uprawnień do tworzenia bazy danych

181

Kiedy próbuję przetestować dowolną aplikację za pomocą polecenia (zauważyłem to, gdy próbowałem wdrożyć mój projekt za pomocą tkaniny, która używa tego polecenia):

python manage.py test appname

Otrzymuję ten błąd:

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

syncdbpolecenie wydaje się działać. Moje ustawienia bazy danych w 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.
    }
}
Andrius
źródło

Odpowiedzi:

373

Kiedy Django uruchamia zestaw testów, w twoim przypadku tworzy nową bazę danych test_finance. Użytkownik postgres z nazwą użytkownika djangonie ma uprawnień do tworzenia bazy danych, stąd komunikat o błędzie.

Po uruchomieniu migratelub syncdbDjango nie próbuje utworzyć financebazy danych, więc nie pojawiają się żadne błędy.

Możesz dodać uprawnienie createdb do użytkownika django, uruchamiając następującą komendę w powłoce postgres jako superużytkownik (wskazówka w odpowiedzi na przepełnienie stosu ).

=> ALTER USER django CREATEDB;

Uwaga: nazwa użytkownika używana w ALTER USER <username> CREATEDB;poleceniu musi być zgodna z nazwą użytkownika bazy danych w plikach ustawień Django. W tym przypadku oryginalny plakat miał użytkownika jako djangopowyższą odpowiedź.

Alasdair
źródło
2
Chociaż OP używał postgresql, jeśli używasz mysql, będziesz miał ten sam błąd. Możesz to naprawić dla mysql za pomocą: => GRANT ALL ON *. * TO django @ localhost; Początkowo próbowałem tylko GRANT CREATE ... ale potem nie mogłem WYBRAĆ lub DROP utworzonej bazy danych. To zasadniczo sprawia, że ​​twój użytkownik jest superużytkownikiem, więc bądź ostrożny.
mightypile
1
Trochę poeksperymentowałem i stwierdziłem, że minimalne uprawnienia globalne to - Dane: SELECT, INSERT, UPDATE, DELETE, Structure: CREATE, ALTER, INDEX, DROP, Admin: REFERENCES. Nie jest superużytkownikiem, ale wciąż jest dość potężny, więc zachowaj ostrożność.
Scott,
w moim przypadku przyznaję wszystkie uprawnienia do testowej bazy danych, coś takiego:GRANT ALL PRIVILEGES ON test_my_db.* TO 'my_user'@'localhost';
Yacine Rouizi
17

Znalazłem interesujące rozwiązanie twojego problemu.
W rzeczywistości dla MySQL możesz nadać uprawnienia do nieistniejącej bazy danych.
Możesz więc dodać nazwę „test_finance” do swojej testowej bazy danych w ustawieniach:

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

uruchom powłokę MySQL jako użytkownik root:

mysql -u root -p

a teraz przyznaj wszystkie uprawnienia do tej nieistniejącej bazy danych w MySQL:

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

Teraz Django rozpocznie testy bez żadnych problemów.

Yurii Halapup
źródło
4

Jeśli bazą danych jest mysql, te dwie zmiany załatwią sprawę.

1. Otwórz mysite / mysite / settings.py

Twoje ustawienia bazy danych powinny mieć dodatkowy blok TEST, jak pokazano w projekcie nazwa_testu .

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

2.Wpisz poniższe polecenie za pomocą wiersza poleceń mysql lub środowiska roboczego mysql, aby nadać wszystkie uprawnienia użytkownikowi określonym w settings.py

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

Teraz możesz biec python manage.py test polls.

Chandan
źródło
Pytanie oczywiście używa Postgres jako DBMS. Do czego odnosiłby się projectname_test ?
code-kobold
@ code-kobold 7, Tak, ale widzę ten sam błąd również w mysql. Wartość nazwa_projektu_test odnosi się do nazwy projektu np. w mojej odpowiedzi jest to mój projekt.
Chandan
2

W moim przypadku rozwiązania GRANT PRIVILEGES nie działały z Pythonem 3.7.2 , Django 2.1.7 i MySQL 5.6.23 ... Nie wiem dlaczego.

Postanowiłem więc użyć SQLite jako bazy danych 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'),
        },
    }
}

Po tym samochód TESTY działa bez problemów:

$ 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
JavierFuentes
źródło
1

Jeśli używasz docker-composetego, co zadziałało dla mnie, było następujące:

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

lub

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

Moje ustawienia wyglądają tak:

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

a mój docker-compose.ymlwygląd wygląda następująco:

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
źródło
0

Wow, więc połączenie wszystkich odpowiedzi tutaj z drobnymi poprawkami w końcu doprowadziło mnie do działającego rozwiązania dla docker-compose, django i postgres ...

Najpierw polecenie postgres podane przez noufal valapra jest niepoprawne (lub może po prostu nieaktualne), powinno być:

ALTER USER docker WITH CREATEDB;

W przypadku konfiguracji docker-compose, zostanie to umieszczone w pliku init.sql, tak wygląda moja:

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

Następnie plik Dockerfile dla postgres wygląda następująco:

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

Następnie Django settings.py zawiera ten wpis:

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

a docker-compose wygląda następująco:

wersja: '3.6'

usługi:

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
źródło
0

Może umieścisz swój test w trybie zawieszonym lub jako praca w tle. Spróbuj za pomocą fgpolecenia w powłoce bash.

eEmanuel Oviedo
źródło