Django and postgresql testing schema - django

I'm using PostgreSQL 9.3 and Django 1.7.4 with psycopg2 2.5.4
The DBA, asked us to create a schema for our application instead of using public.
We defined the schema, and we had to add the
'OPTIONS': {
'options': '-c search_path=custom-schema-name'
},
to the settings.
During testing, Django is creating the test database with the corresponding name, but we can't set the custom-schema name
I tried to find a way to set up the custom schema name (I've read the docs) but I can't find a way to force the creation of the schema name during testing.
The error that I obtain is
django.db.utils.ProgrammingError: no schema has been selected to create in
When I see the created database , it has the schema public created by default.
I partially solved this issue and added to the search path the schema name public
'OPTIONS': {
'options': '-c search_path=custom-schema-name,public'
},
but I'd like to create the test database with a custom schema name.
Does anybody knows how to set the testing schema name ?

I ended up with writing a custom test runner to solve this problem (using django 1.9.x):
myapp/test/runner.py
from types import MethodType
from django.test.runner import DiscoverRunner
from django.db import connections
def prepare_database(self):
self.connect()
self.connection.cursor().execute("""
CREATE SCHEMA foobar_schema AUTHORIZATION your_user;
GRANT ALL ON SCHEMA foobar_schema TO your_user;
""")
class PostgresSchemaTestRunner(DiscoverRunner):
def setup_databases(self, **kwargs):
for connection_name in connections:
connection = connections[connection_name]
connection.prepare_database = MethodType(prepare_database, connection)
return super().setup_databases(**kwargs)
settings.py
TEST_RUNNER = 'myapp.test.runner.PostgresSchemaTestRunner'

Related

Django test database requires Postgres Extension enabled

I have a Django app which requires Postgres' fuzzystrmatch extension to be enabled on the database.
Django's unittest framework creates and destroys a new database. I need this new database to have the extension turned on for testing.
I can use './manage.py test --keepdb' to keep the database and then manually turn on the extension, but this is an ineloquent solution.
Any idea how I can enable this extension programmatically?
Create an empty migration and use the CreateExtension operation:
from django.contrib.postgres.operations import CreateExtension
class Migration(migrations.Migration):
...
operations = [
CreateExtension(name='fuzzystrmatch'),
...
]
Relevant docs
Edit:
If that doesn't work, reviewing how Django actually handles those classes internally would be my next suggestion.
In case you've disabled the migrations in the test settings, the migrations will not be run, so you can't use django CreateExtension.
Example:
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": "test-database",
"USER": "username",
"PASSWORD": "password",
"HOST": "postgresql-host",
"PORT": "5432",
"TEST": {
"MIGRATE": False,
},
},
}
In this case you can manually call SQL code to create the extension.
If you use unitest, you can for example create a custom TestCase class inherited by all your tests like so:
from django.test import TestCase from django.db import connection
class PostgresExtensionTestCase(TestCase):
#classmethod
def setUpClass(cls):
with connection.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS unaccent;")
super().setUpClass()
If you use pytest, you can create a fixture in your conftest.py like so (for unaccent in the example):
from django.db import connection
#pytest.fixture(autouse=True)
def activate_postgresql_unaccent():
with connection.cursor() as cursor:
cursor.execute("CREATE EXTENSION IF NOT EXISTS unaccent;")

How to connect to my heroku database from localhost?

I'm new in django and trying to connect to my heroku database from my localhosted django app.
I've followed the instructions on heroku website but it's seems django won't understand that i'm trying to access an external database.
i get this error
relation "myAppName_user" does not exist
LINE 1: INSERT INTO "myAppName_user" ("title", "content") VALUES
('Beat...
However i never created or never intented to create a table named myAppName_user
I'm just trying to access the table user in my heroku postgres db but i don't know why it tries with myAppName_user
i just explicitly added myAppName in the INSTALLED_APPS config as django throws an error if it's not the case.
My DATABASE config :
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
DATABASES['default'] =
dj_database_url.config(default='postgres://xxxxx')
I want to test my database from my localhost. I'm doing this easily with Node JS but i can't find the solution in django.
Any suggestions ?
EDIT
from __future__ import unicode_literals
from django.db import models
class Fruits(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
def __str__(self):
return self.name

How install a extension in postgresql before creating the models in django?

Using django 1.8 + Postgres 9+, I have models with custom PG datatypes (like ltree). Creating de database from zero fail because
CREATE EXTENSION ltree;
is not executed. I try with a empty migration, but that run after the models creation. Exist a way to run sql before the models creation?
I know this is unanswered for long, and maybe now you already have figured out the answer. But I'm posting just in case someone gets a little bit of help from this.
For extensions that are available in Postgres
If the extension is one of the defaults that are available with Postgres, then you can simply create first migration as this, and then load other migrations.
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.postgres.operations import HStoreExtension
from django.db import migrations
class Migration(migrations.Migration):
run_before = [
('some_app_that_requires_hstore', '0001_initial'),
]
operations = [
HStoreExtension(),
]
Notice the use of run_before. It is the exact opposite of dependencies. Alternatively, you can make this migration as say 1st one and load all others after this using dependencies.
In case this migration fails to create an extension because of privileges issues, then you can simply use the superuser and nosuperuser in Postgres to temporarily provide privileges for the current user to run migrations like:
ALTER ROLE user_name superuser;
# create the extension and then remove the superuser privileges.
ALTER ROLE user_name nosuperuser;
For third-party extensions that are not available in Postgres
For third-party extensions, you can use run_python, to load the extension for you like:
from django.db import migrations
def create_third_party_extension(apps, schema_editor):
schema_editor.execute("CREATE EXTENSION my_custom_extension;")
def drop_third_party_extension(apps, schema_editor):
schema_editor.execute("DROP EXTENSION IF EXISTS my_custom_extension;")
class Migration(migrations.Migration):
dependencies = [
('venues', '0001_auto_20180607_1014'),
]
operations = [
migrations.RunPython(create_third_party_extension, reverse_code=drop_third_party_extension, atomic=True)
]
Alternatively, you can just have them as a part of your deployment scripts instead of migrations.
I hope this helps.
You can also install the extension on the template database, and when new databases are created (like when running tests), the new database will copy that template and include the extension.
psql -d template1 -c 'create extension if not exists hstore;'

In Django multiple databases should not creat a test database by manage.py on 1 specific database

In Django I'm using multple databases, but by testing the functionality 1 database of the multiple database should not create a test database if you run manage.py test **. How can I solve this issue.
In your settings.py you can tell Django what database to use when testing. Here is the code to do so if you would like to use SQLite for example:
settings.py:
if 'test' in sys.argv:
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': 'tests.db',
}
Django creates a new database every time you run your manage.py test, so you would want to use fixtures in your test.py file to preload you database with data before running tests (if you need it preloaded with data).
To generate a fixture for the User model for example, use this code:
python manage.py dumpdata auth.User --indent=2 > app_name/fixtures/admin.json
To use fixtures you would structure your tests.py like so:
tests.py:
from django.test import TestCase
class MyTests(TestCase):
fixtures = [admin.json]
def setUp(self):
# other setup code here
def test_the_obvious(self):
assert True == True

django oracle inspectdb failure

i'm using django 1.3. i have an existing oracle database (10g) i would like to build Model's from using inspectdb.
'db': {
'ENGINE': 'django.db.backends.oracle',
'NAME': 'DBNAME',
'USER': 'me',
'PASSWORD': 'something',
}
so when run inspectdb i get:
$ python manage.py inspectdb --database db
cx_Oracle.InterfaceError: Unable to acquire Oracle environment handle
so i add
$ export ORACLE_HOME=/usr/oracle/
$ TWO_TASK=DBNAME
i try logging on with sqlplus with the same credentials and everything looks good.
so... i run inspectdb again, but this time i get
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# Feel free to rename the models, but don't rename db_table values or field names.
#
# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'
# into your database.
from django.db import models
(ie it's blank)
any ideas? i had no problems getting this to work on a mysql database.
From the official docs.
inspectdb works with PostgreSQL, MySQL and SQLite. Foreign-key detection only works in PostgreSQL and with certain types of MySQL tables.
There is currently not a bug listed for it in the Django tracker if you wanted to submit it.
I have a similar setup at the top of my settings.py to set my environment variables for my oracle driver (Oracle 11.2). Not sure if this will help in your specific case.
### SETTING UP THE ENVIRONENT FOR OUR ORACLE RPM
import os
os.putenv('ORACLE_HOME', '/.../oracle/11.2')
os.putenv('LD_LIBRARY_PATH', '/.../oracle/11.2/lib')
I have had no issues with manage.py inspectdb (Django 1.2.7 and Django 1.4) on Oracle 11.2.