【问题标题】:Installing hstore extension in django nose tests在 django 鼻子测试中安装 hstore 扩展
【发布时间】:2013-04-27 16:17:52
【问题描述】:

我已经成功安装了 hstore 扩展,当我 syncdb 时一切正常。 (我用的是djorm-ext-hstore

但是,nose 会创建一个新的临时数据库来运行测试,并且其中没有安装 hstore。

我需要在鼻子同步数据库之前在测试数据库上运行CREATE EXTENSION HSTORE;,但我找不到任何有关如何执行此操作的信息。

有什么想法吗?

【问题讨论】:

  • 您可以通过在template1 postgres 数据库上创建扩展来为自己省去很多麻烦。然后您创建的任何数据库都将具有 HSTORE 扩展名。
  • rantaplan,这应该是答案!
  • 没关系,我通常避免给出单行答案。很高兴我能帮上忙。
  • 当答案是单行时,它是合法的!非常感谢:-)

标签: python django postgresql nose hstore


【解决方案1】:

使用 Django 1.8(现在已经过时,但在 3.2 中仍然存在):

from django.contrib.postgres.operations import HStoreExtension

class Migration(migrations.Migration):
    ...

    operations = [
        HStoreExtension(),
        ...
    ]

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

编辑:请注意,还有一个 JSONField 已经处理(un)编组 json 和内联搜索。 HStoreExtension 不是它所必需的。需要 Django >=1.11 和 Postgres >=9.4。

【讨论】:

  • 这应该是第一次迁移中的第一个操作 - 在执行任何 hstore 相关操作的迁移之前。
  • 这是一个很好的答案,唯一的缺点是它需要手动编辑/修改迁移(至少在我的情况下)。我想知道为什么在首次使用 hstore 列时不将其作为初始迁移的一部分?
  • 安装扩展需要 postgres 中的超级用户权限。您可以选择在常规 Django 设置之外安装扩展程序,以避免为您的 Django 系统提供这些权限。
【解决方案2】:

这对我有用 https://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'

【讨论】:

    【解决方案3】:

    自从我上次回答以来,Django 弃用并删除了pre_syncdb 信号。我已经更新了答案以适应更新的版本。新版本的基本机制是相同的,因为这两种方法都依赖于信号和仅在 HSTORE 扩展不存在时执行的 SQL 代码。

    Django 1.8+

    自从 Django 引入数据库迁移以来,pre_syncdb 信号为marked deprecated in 1.7completely removed in 1.9。但是,他们引入了一个名为pre_migrate 的新信号,可以以相同的方式使用。

    """
    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+(原始答案)

    我的建议是使用pre_syncdb 信号挂钩。

    在另一个 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.
    

    pre_syncdb 信号在模型表创建之前被触发,因此非常适合在每次设置测试数据库时确保安装扩展。 IF NOT EXISTS 确保 PostgreSQL 在已安装扩展程序时忽略该命令。如果您在已存在的扩展程序上运行 CREATE EXTENSION,则会收到错误消息。

    这适用于默认的 Django 单元测试框架,并且很可能适用于 Django 鼻子测试。

    有关信号的更多信息: https://docs.djangoproject.com/en/1.6/ref/signals/#management-signals

    【讨论】:

      【解决方案4】:

      您还可以在迁移中运行 sql 命令(Django 1.8):

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

      【讨论】:

        【解决方案5】:

        这不是问题:解决此问题的最佳方法是在默认数据库上应用 hstore 扩展,template1

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

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

        【讨论】:

          【解决方案6】:

          我假设您使用的是django-nose。在这种情况下,您应该创建自己的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
          

          然后在 settings.py 你应该指定你的自定义测试运行器:

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

          【讨论】:

          • 谢谢!如果不运行它,我会看到一个问题:如果 setup_databases() 实际上创建了表。我们不应该先创建扩展程序吗?
          • 我会在运行时通知您。
          • 不工作恐怕,如果我把创建扩展放在第一位,测试数据库就不在那里,如果我把它放在超级之后,它永远不会运行,因为那是发生错误。 :-/
          • 它也适用于 DiscoverRunner (django.test.runner)
          猜你喜欢
          • 2018-08-16
          • 2018-07-02
          • 2018-09-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-03
          • 2014-01-19
          • 1970-01-01
          相关资源
          最近更新 更多