Выберите тестовую базу данных?
Я пытаюсь запустить
./manage.py test
Но это говорит мне
Появилась ошибка при создании тестовой базы данных: разрешено запретить создание базы данных
Очевидно, что у него нет разрешения на создание базы данных, но я нахожусь на общем сервере, поэтому я не могу с этим поделать. Я могу создать новую базу данных через панель управления, но я не думаю, что я могу позволить Django сделать это автоматически.
Итак, не могу ли я создать тестовую базу данных вручную и вместо этого скажу, что Django каждый раз очищает ее, а не воссоздает все это?
Ответы
Ответ 1
У меня была аналогичная проблема. Но я хотел, чтобы Django просто обошел создание тестовой базы данных для одного из моих экземпляров (это не круто зеркало). Следуя предложению Марка, я создал собственный тестовый бегун, как показано ниже.
from django.test.simple import DjangoTestSuiteRunner
class ByPassableDBDjangoTestSuiteRunner(DjangoTestSuiteRunner):
def setup_databases(self, **kwargs):
from django.db import connections
old_names = []
mirrors = []
for alias in connections:
connection = connections[alias]
# If the database is a test mirror, redirect its connection
# instead of creating a test database.
if connection.settings_dict['TEST_MIRROR']:
mirrors.append((alias, connection))
mirror_alias = connection.settings_dict['TEST_MIRROR']
connections._connections[alias] = connections[mirror_alias]
elif connection.settings_dict.get('BYPASS_CREATION','no') == 'no':
old_names.append((connection, connection.settings_dict['NAME']))
connection.creation.create_test_db(self.verbosity, autoclobber=not self.interactive)
return old_names, mirrors
Затем я создал дополнительную запись dict в одной из записей моих баз данных внутри settings.py, 'BYPASS_CREATION':'yes',
Наконец, я настроил новый TestRunner с
TEST_RUNNER = 'auth.data.runner.ByPassableDBDjangoTestSuiteRunner'
Ответ 2
Я бы предложил использовать sqlite3 для тестирования, продолжая использовать mysql/postgres/etc для производства.
Это можно сделать, разместив это в своем файле настроек:
if 'test' in sys.argv:
DATABASES['default'] = {'ENGINE': 'django.db.backends.sqlite3'}
см. Запуск тестов django с использованием sqlite
временный файл базы данных sqlite будет создан в вашем доме проекта django, к которому вы будете иметь доступ на запись. Другим преимуществом является то, что sqlite3 намного быстрее для тестирования. Тем не менее, вы можете столкнуться с проблемами, если используете какой-либо сырой sql файл mysql/postgres (который вы все равно должны избегать).
Ответ 3
Я думаю, что лучшим решением может быть определить свой собственный тестовый бегун.
Ответ 4
Я добавил это к комментариям выше, но он получил вид потерянных - последние изменения в webfaction делают это намного проще. Теперь вы можете создать новые экземпляры частной базы данных.
Следуйте инструкциям, и при создании нового пользователя обязательно дайте им разрешение на ALTER USER new_username CREATEDB;
.
Вероятно, вы также должны изменить настройки по умолчанию cron, чтобы они не пытались проверить, что эта база данных работает и работает так часто.
Ответ 5
Вы можете использовать django-nose как ваш TEST_RUNNER. После установки, если вы передадите следующую переменную среды, она не удалит и не заново создаст базу данных (сначала создайте ее самостоятельно).
REUSE_DB=1 ./manage.py test
Вы также можете добавить следующее в settings.py, чтобы вам не приходилось писать REUSE_DB = 1 каждый раз, когда вы хотите запускать тесты:
os.environ['REUSE_DB'] = "1"
Примечание. это также оставит все ваши таблицы в базах данных, что означает, что установка теста будет немного быстрее, но вам придется вручную обновлять таблицы (или удалять и воссоздавать базу данных самостоятельно), когда вы меняете свои модели.
Ответ 6
мой вариант повторного использования базы данных:
from django.test.simple import DjangoTestSuiteRunner
from django.core.management import call_command
class TestRunner(DjangoTestSuiteRunner):
def setup_databases(self, **kwargs):
from django.db import connections
settings = connections['default'].settings_dict
settings['NAME'] = settings['TEST_NAME']
settings['USER'] = settings['TEST_USER']
settings['PASSWORD'] = settings['TEST_PASSWD']
call_command('syncdb', verbosity=1, interactive=False, load_initial_data=False)
def teardown_databases(self, old_config, **kwargs):
from django.db import connection
cursor = connection.cursor()
cursor.execute('show tables;')
parts = ('DROP TABLE IF EXISTS %s;' % table for (table,) in cursor.fetchall())
sql = 'SET FOREIGN_KEY_CHECKS = 0;\n' + '\n'.join(parts) + 'SET FOREIGN_KEY_CHECKS = 1;\n'
connection.cursor().execute(sql)
Ответ 7
Ниже приведен пример бегуна набора тестов django для создания базы данных с использованием API XML-RPC Webfaction. Обратите внимание: настройка базы данных с использованием API может занять до минуты, а script может застрять на мгновение, просто подождите немного.
ПРИМЕЧАНИЕ. Существует риск безопасности наличия пароля панели управления на сервере webfaction, поскольку кто-то, нарушив свой SSH-сервер, может взять вашу учетную запись Webfaction. Если это вызывает беспокойство, установите USE_SESSKEY в значение Истина и используйте ткань script ниже этого script, чтобы передать идентификатор сеанса на сервер. Ключ сеанса истекает через 1 час из последнего вызова API.
Файл test_runner.py: на сервере вам нужно настроить тест. /manage.py для использования WebfactionTestRunner
"""
This test runner uses Webfaction XML-RPC API to create and destroy database
"""
# you can put your control panel username and password here.
# NOTE: there is a security risk of having control panel password in
# the webfaction server, because someone breaching into your web server
# SSH could take over your Webfaction account. If that is a concern,
# set USE_SESSKEY to True and use the fabric script below this script to
# generate a session.
USE_SESSKEY = True
# CP_USERNAME = 'webfactionusername' # required if and only if USE_SESSKEY is False
# CP_PASSWORD = 'webfactionpassword' # required if and only if USE_SESSKEY is False
import sys
import os
from django.test.simple import DjangoTestSuiteRunner
from django import db
from webfaction import Webfaction
def get_sesskey():
f = os.path.expanduser("~/sesskey")
sesskey = open(f).read().strip()
os.remove(f)
return sesskey
if USE_SESSKEY:
wf = Webfaction(get_sesskey())
else:
wf = Webfaction()
wf.login(CP_USERNAME, CP_PASSWORD)
def get_db_user_and_type(connection):
db_types = {
'django.db.backends.postgresql_psycopg2': 'postgresql',
'django.db.backends.mysql': 'mysql',
}
return (
connection.settings_dict['USER'],
db_types[connection.settings_dict['ENGINE']],
)
def _create_test_db(self, verbosity, autoclobber):
"""
Internal implementation - creates the test db tables.
"""
test_database_name = self._get_test_db_name()
db_user, db_type = get_db_user_and_type(self.connection)
try:
wf.create_db(db_user, test_database_name, db_type)
except Exception as e:
sys.stderr.write(
"Got an error creating the test database: %s\n" % e)
if not autoclobber:
confirm = raw_input(
"Type 'yes' if you would like to try deleting the test "
"database '%s', or 'no' to cancel: " % test_database_name)
if autoclobber or confirm == 'yes':
try:
if verbosity >= 1:
print("Destroying old test database '%s'..."
% self.connection.alias)
wf.delete_db(test_database_name, db_type)
wf.create_db(db_user, test_database_name, db_type)
except Exception as e:
sys.stderr.write(
"Got an error recreating the test database: %s\n" % e)
sys.exit(2)
else:
print("Tests cancelled.")
sys.exit(1)
db.close_connection()
return test_database_name
def _destroy_test_db(self, test_database_name, verbosity):
"""
Internal implementation - remove the test db tables.
"""
db_user, db_type = get_db_user_and_type(self.connection)
wf.delete_db(test_database_name, db_type)
self.connection.close()
class WebfactionTestRunner(DjangoTestSuiteRunner):
def __init__(self, *args, **kwargs):
# Monkey patch BaseDatabaseCreation with our own version
from django.db.backends.creation import BaseDatabaseCreation
BaseDatabaseCreation._create_test_db = _create_test_db
BaseDatabaseCreation._destroy_test_db = _destroy_test_db
return super(WebfactionTestRunner, self).__init__(*args, **kwargs)
Файл webfaction.py: это тонкая оболочка для API Webfaction, она должна быть импортируемой как test_runner.py(на удаленном сервере), так и fabfile.py(на локальном компьютере)
import xmlrpclib
class Webfaction(object):
def __init__(self, sesskey=None):
self.connection = xmlrpclib.ServerProxy("https://api.webfaction.com/")
self.sesskey = sesskey
def login(self, username, password):
self.sesskey, _ = self.connection.login(username, password)
def create_db(self, db_user, db_name, db_type):
""" Create a database owned by db_user """
self.connection.create_db(self.sesskey, db_name, db_type, 'unused')
# deletes the default user created by Webfaction API
self.connection.make_user_owner_of_db(self.sesskey, db_user, db_name, db_type)
self.connection.delete_db_user(self.sesskey, db_name, db_type)
def delete_db(self, db_name, db_type):
try:
self.connection.delete_db_user(self.sesskey, db_name, db_type)
except xmlrpclib.Fault as e:
print 'ignored error:', e
try:
self.connection.delete_db(self.sesskey, db_name, db_type)
except xmlrpclib.Fault as e:
print 'ignored error:', e
Файл fabfile.py: образец шаблона script для генерации ключа сеанса, необходимый только в том случае, если USE_SESSKEY = True
from fabric.api import *
from fabric.operations import run, put
from webfaction import Webfaction
import io
env.hosts = ["[email protected]"]
env.password = "webfactionpassword"
def run_test():
wf = Webfaction()
wf.login(env.hosts[0].split('@')[0], env.password)
sesskey_file = '~/sesskey'
sesskey = wf.sesskey
try:
put(io.StringIO(unicode(sesskey)), sesskey_file, mode='0600')
# put your test code here
# e.g. run('DJANGO_SETTINGS_MODULE=settings /path/to/virtualenv/python /path/to/manage.py test --testrunner=test_runner.WebfactionTestRunner')
raise Exception('write your test here')
finally:
run("rm -f %s" % sesskey_file)
Ответ 8
Принятый ответ не помог мне. Это так устарело, что он не запускался на моей старой кодовой базе с помощью jjano 1.5.
Я написал blogpost, полностью описывающий, как я решил эту проблему, создав альтернативный тестовый бегун и изменив настройки django, чтобы предоставить все необходимые конфигурации и для использования нового тестового бегуна.
Ответ 9
Измените следующие методы в django/db/backends/creation.py
:
def _destroy_test_db(self, test_database_name, verbosity):
"Internal implementation - remove the test db tables."
# Remove the test database to clean up after
# ourselves. Connect to the previous database (not the test database)
# to do so, because it not allowed to delete a database while being
# connected to it.
self._set_test_dict()
cursor = self.connection.cursor()
self.set_autocommit()
time.sleep(1) # To avoid "database is being accessed by other users" errors.
cursor.execute("""SELECT table_name FROM information_schema.tables WHERE table_schema='public'""")
rows = cursor.fetchall()
for row in rows:
try:
print "Dropping table '%s'" % row[0]
cursor.execute('drop table %s cascade ' % row[0])
except:
print "Couldn't drop '%s'" % row[0]
#cursor.execute("DROP DATABASE %s" % self.connection.ops.quote_name(test_database_name))
self.connection.close()
def _create_test_db(self, verbosity, autoclobber):
"Internal implementation - creates the test db tables."
suffix = self.sql_table_creation_suffix()
if self.connection.settings_dict['TEST_NAME']:
test_database_name = self.connection.settings_dict['TEST_NAME']
else:
test_database_name = TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME']
qn = self.connection.ops.quote_name
# Create the test database and connect to it. We need to autocommit
# if the database supports it because PostgreSQL doesn't allow
# CREATE/DROP DATABASE statements within transactions.
self._set_test_dict()
cursor = self.connection.cursor()
self.set_autocommit()
return test_database_name
def _set_test_dict(self):
if "TEST_NAME" in self.connection.settings_dict:
self.connection.settings_dict["NAME"] = self.connection.settings_dict["TEST_NAME"]
if "TEST_USER" in self.connection.settings_dict:
self.connection.settings_dict['USER'] = self.connection.settings_dict["TEST_USER"]
if "TEST_PASSWORD" in self.connection.settings_dict:
self.connection.settings_dict['PASSWORD'] = self.connection.settings_dict["TEST_PASSWORD"]
Кажется, нужно работать... просто добавьте дополнительные настройки к вашему settings.py
, если вам нужно.
Ответ 10
Простой обходной путь: измените TEST_DATABASE_PREFIX
на django/db/backends/base/creation.py
по своему усмотрению.