2014-10-03 65 views
2

我的Postgres數據庫有3個模式:默認,cedirData和webData。Django單元測試失敗多個Postgres模式

對於那些都指向一個不同的模式比默認的模型,我指定此如下:

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 

測試DB僅與默認的模式中創建。

我正在使用Django 1.7和Python 2.7.6。

任何想法或想法都將有所幫助。

謝謝!

回答

4

架構並未在許多其他數據庫引擎中使用。通過在模型中指定模式,您已經在代碼中爲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' 

作爲獎勵,您現在可以將我們e:

manage.py inspectdb > models.py 

這是一個很好的功能,這樣你就不必手工複製你現有的數據庫。

但是,如果架構命名空間在您的數據庫中大量使用,並且其他應用程序依賴它,則此解決方案無法幫助您。一種不同的方法是編寫一個自定義的testrunner來在你的測試數據庫中創建這些模式。這比上述方法涉及更多,並且可能有點混亂。我真的不建議這樣做,但如果你有興趣,我可以嘗試提供幫助。

一個不那麼混亂,但更多'哈克'的方式是簡單地重寫元測試運行時。這也將成爲一名testrunner。

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文件中的testrunner。

+0

settings.py中的'OPTIONS'技巧是一個好主意,最好的選擇IMO – oden 2015-03-18 05:01:01