简体   繁体   中英

Installing hstore extension in django nose tests

I've installed the hstore extension successfully, and everything works when I syncdb . (I'm using djorm-ext-hstore )

However, nose creates a new temp database to run tests in, and hstore is not installed in it.

I need to run CREATE EXTENSION HSTORE; on the test db right before nose syncs the db, but I can't find any info on how to do that.

Any ideas?

This is a non-issue: The best way to fix this is to apply the hstore extension on the default database, template1

psql -d template1 -c 'create extension hstore;'

Reference: How to create a new database with the hstore extension already installed?

With Django 1.8:

from django.contrib.postgres.operations import HStoreExtension

class Migration(migrations.Migration):
    ...

    operations = [
        HStoreExtension(),
        ...
    ]

https://docs.djangoproject.com/en/1.8/ref/contrib/postgres/fields/#hstorefield

EDIT: Just note that there is also a JSONField which handles (un)marshalling of json already and inline search. The HStoreExtension is not necessary for it. Requires Django >=1.11 and Postgres >=9.4.

I'm assuming you're using django-nose . In this case you should create your own TestSuiteRunner :

from django.db import connections, DEFAULT_DB_ALIAS
from django_nose import NoseTestSuiteRunner

class MyTestSuiteRunner(NoseTestSuiteRunner):
    def setup_databases(self):
        result = super(MyTestSuiteRunner, self).setup_databases()

        connection = connections[DEFAULT_DB_ALIAS]
        cursor = connection.cursor()
        cursor.execute('CREATE EXTENSION HSTORE')

        return result

Then in settings.py you should specify your custom test runner:

TEST_RUNNER = 'path.to.my.module.MyTestSuiteRunner'

Since my last answer, Django deprecated and removed pre_syncdb signal. I've updated the answer to accommodate more recent versions. The basic mechanics are identical for newer versions as both methods rely on signals and the SQL code that only executes if HSTORE extension does not exist.

Django 1.8+

Since Django introduced DB migrations, pre_syncdb signals were marked deprecated in 1.7 and completely removed in 1.9 . However, they introduced a new signal calledpre_migrate which can be used the same way.

"""
This is an example models.py which contains all model definition.
"""
from django.dispatch import receiver
from django.db import connection, models
from django.db.models.signals import pre_migrate
import sys

# The sender kwarg is optional but will be called for every pre_syncdb signal
# if omitted. Specifying it ensures this callback to be called once.
@receiver(pre_migrate, sender=sys.modules[__name__])
def setup_postgres_hstore(sender, **kwargs):
    """
    Always create PostgreSQL HSTORE extension if it doesn't already exist
    on the database before syncing the database.
    Requires PostgreSQL 9.1 or newer.
    """
    cursor = connection.cursor()
    cursor.execute("CREATE EXTENSION IF NOT EXISTS hstore")

# ...rest of your model definition goes here
class Foo(models.Model):
    # ...field definitions, etc.

Django 1.6+ (original answer)

My suggestion is to use pre_syncdb signal hook.

See my answer on the other question .

"""
This is an example models.py which contains all model definition.
"""
from django.dispatch import receiver
from django.db import connection, models
from django.db.models.signals import pre_syncdb
import sys

# The sender kwarg is optional but will be called for every pre_syncdb signal
# if omitted. Specifying it ensures this callback to be called once.
@receiver(pre_syncdb, sender=sys.modules[__name__])
def setup_postgres_hstore(sender, **kwargs):
    """
    Always create PostgreSQL HSTORE extension if it doesn't already exist
    on the database before syncing the database.
    Requires PostgreSQL 9.1 or newer.
    """
    cursor = connection.cursor()
    cursor.execute("CREATE EXTENSION IF NOT EXISTS hstore")

# ...rest of your model definition goes here
class Foo(models.Model):
    # ...field definitions, etc.

The pre_syncdb signal is fired before the model table is created, making it ideal to ensure the extension is installed when the test database is being set up every time. The IF NOT EXISTS ensures that PostgreSQL ignores the command if the extension is already installed. You'll get an error if you run CREATE EXTENSION on an extension that already exists.

This works for the default Django unit test framework and will most likely work for Django nose tests.

More info on signals: https://docs.djangoproject.com/en/1.6/ref/signals/#management-signals

Also you can run sql command in a migration (Django 1.8):

class Migration(migrations.Migration):

    # ...

    operations = [
        migrations.RunSQL('create extension hstore;'),
        # ...

It's work for mehttps://gist.github.com/smcoll/bb2533e4b53ae570e11eb2ab011b887b

from django.db.backends.base import creation
from django.test.runner import DiscoverRunner


class CustomDiscovererRunner(DiscoverRunner):
    def setup_databases(self, **kwargs):
        def wrap_create_test_db(function):
            def decorated_create_test_db(self, verbosity, autoclobber, keepdb):
                test_database_name = function(self, verbosity, autoclobber, keepdb)
                self.connection.close()
                self.connection.settings_dict["NAME"] = test_database_name
                cursor = self.connection.cursor()
                cursor.execute('CREATE EXTENSION IF NOT EXISTS hstore')
                return test_database_name

            return decorated_create_test_db
        creation.BaseDatabaseCreation._create_test_db = wrap_create_test_db(
            creation.BaseDatabaseCreation._create_test_db
        )

        return super(CustomDiscovererRunner, self).setup_databases(**kwargs)

settings.py

TEST_RUNNER = 'my_project.settings_test.CustomDiscovererRunner'

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM