Installing hstore extension in django nose tests

2019-02-09 19:05发布

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?

5条回答
再贱就再见
2楼-- · 2019-02-09 19:36

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.

查看更多
3楼-- · 2019-02-09 19:40

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?

查看更多
唯我独甜
4楼-- · 2019-02-09 19:53

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 called pre_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_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_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

查看更多
时光不老,我们不散
5楼-- · 2019-02-09 19:56

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

class Migration(migrations.Migration):

    # ...

    operations = [
        migrations.RunSQL('create extension hstore;'),
        # ...
查看更多
放我归山
6楼-- · 2019-02-09 19:59

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'
查看更多
登录 后发表回答