【问题标题】:Django unit test failing for multiple Postgres schemas多个 Postgres 模式的 Django 单元测试失败
【发布时间】:2014-10-31 05:18:27
【问题描述】:

我的 Postgres DB 有 3 个模式:default、cedirData 和 webData。

对于那些指向不同于默认模式的模型,我指定如下:

class Person(models.Model):
    first_name = models.CharField(max_length=200, null=False, blank=False)
    last_name = models.CharField(max_length=200, null=False, blank=False)

    class Meta:
        db_table = 'cedirData\".\"persons'

应用程序运行良好,但是当我尝试运行测试时:

$ ./manage.py test

我得到以下信息:

  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/core/management/commands/migrate.py", line 160, in handle
    executor.migrate(targets, plan, fake=options.get("fake", False))
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 63, in migrate
    self.apply_migration(migration, fake=fake)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/migrations/executor.py", line 97, in apply_migration
    migration.apply(project_state, schema_editor)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/migrations/migration.py", line 107, in apply
    operation.database_forwards(self.app_label, schema_editor, project_state, new_state)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/migrations/operations/models.py", line 36, in database_forwards
    schema_editor.create_model(model)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/backends/schema.py", line 270, in create_model
    self.execute(sql, params)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/backends/schema.py", line 98, in execute
    cursor.execute(sql, params)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/utils.py", line 94, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/home/wbrunetti/.virtualenvs/cedir/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 65, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: schema "cedirData" does not exist

看起来这可能与迁移有关。由于数据库表已经存在,我刚刚创建了初始迁移并运行了 --fake:

$ python manage.py makemigrations
$ ./manage.py migrate --fake

仅使用默认架构创建测试数据库。

我正在使用 Django 1.7 和 Python 2.7.6。

任何想法或想法都会有所帮助。

谢谢!

【问题讨论】:

    标签: python django postgresql


    【解决方案1】:

    许多其他数据库引擎中不使用架构。通过在模型中指定模式,您在代码中为 postgres 引入了依赖项。

    有两种方法可以解决您的问题;

    首先,您可以为您的 postgres 用户添加默认搜索路径。这种方法的缺点是模式不能再用于命名空间,但优点是如果您的数据库更改为不同的引擎,您的代码将正常运行。可以通过选择一些标准的表命名方式来实现表的命名空间,类似于 Django 默认的方式(例如 appName_className)

    有两种方法可以实现这一点。这样做的 postgres 命令是:

    ALTER USER (your user) SET search_path = "$user",(schema1),(schema2),(schema3),(...)
    

    django 唯一的方法是:

    # Warning! This is untested, I just glanced at the docs and it looks right.
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.postgresql_psycopg2',
            # some configuration here
            'OPTIONS': {
                'options': '-c search_path=schema1,schema2,schema3'
            }
        }
    }
    

    你也想改变:

    db_table = 'cedirData\".\"persons'
    

    到:

    db_table = 'persons'
    

    作为奖励,您现在可以使用:

    manage.py inspectdb > models.py
    

    这是一个不错的功能,这样您就不必手动复制现有数据库。

    但是,如果在您的数据库上大量使用模式命名空间并且其他应用程序依赖它,则此解决方案将无济于事。另一种方法是编写自定义测试运行程序以在您的测试数据库中创建这些模式。这比上述方法涉及更多,并且可能有点混乱。我真的不建议这样做,但如果您有兴趣,我可以尝试提供帮助。

    一种不那么凌乱但更“hacky”的方法是在运行测试时简单地覆盖 meta。这也将是一个测试运行者。

    from django.test.simple import DjangoTestSuiteRunner
    from django.db.models.loading import get_models
    
    class SchemaModelTestRunner(DjangoTestSuiteRunner):
        """Docstring"""
        def setup_test_environment(self, *args, **kwargs):
            self.original_db_tables = {}
            self.schema_models = [m for m in get_models()
                                     if '"."' in m._meta.db_table]
            for m in self.schema_models:
                schema, table = m._meta.db_table.split('"."')
                self.original_db_tables[m] = m._meta.db_table
                m._meta.db_table = 'schema_'+schema+'_table_'+table
    
            super(SchemaModelTestRunner, self).setup_test_environment(*args,
                                                                       **kwargs)
        def teardown_test_environment(self, *args, **kwargs):
            super(SchemaModelTestRunner, self).teardown_test_environment(*args,
                                                                          **kwargs)
            # reset models
            for m in self.schema_models:
                m._meta.db_table = self.original_db_tables[m]
    

    您还需要在 settings.py 文件中将其定义为测试运行程序。

    【讨论】:

    • settings.py 中的“OPTIONS”技巧是个好主意,是 IMO 的最佳选择
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-12
    • 2018-11-25
    • 2020-01-01
    • 2013-01-19
    相关资源
    最近更新 更多