django: как динамически указать базу данных для фабричного мальчика
Я устанавливаю приложение Django с большим количеством баз данных, и некоторые из них используют одни и те же модели (они не являются репликами). Я уже настроил свои роутеры и все работает отлично. Проблема появляется при выполнении тестов, как я хочу использовать factory-boy
,
В другом проекте я мог бы настроить базу данных внутри Meta
но теперь я должен выбрать базу данных для динамического создания экземпляра (если нет, то мне нужно создать DjangoModelFactory
для каждой базы данных, что было бы не красиво).
Есть ли (более простой) способ динамически определять базу данных для каждого создания?
1 ответ
Насколько я знаю factory_boy
(version <=2.10.0
) не предоставляет ничего подобного.
Хотя ваша проблема - идеальный вариант использования контекстного менеджера. Это позволит вам динамически устанавливать базу данных там, где вам нужно, и только под желаемую область, а также DRY!:
# factoryboy_utils.py
@classmethod
def _get_manager(cls, model_class):
return super(cls, cls)._get_manager(model_class).using(cls.database)
class DBAwareFactory(object):
"""
Context manager to make model factories db aware
Usage:
with DBAwareFactory(PersonFactory, 'db_qa') as personfactory_on_qa:
person_on_qa = personfactory_on_qa()
...
"""
def __init__(self, cls, db):
# Take a copy of the original cls
self.original_cls = cls
# Patch with needed bits for dynamic db support
setattr(cls, 'database', db)
setattr(cls, '_get_manager', _get_manager)
# save the patched class
self.patched_cls = cls
def __enter__(self):
return self.patched_cls
def __exit__(self, type, value, traceback):
return self.original_cls
и тогда, в ваших тестах, вы можете сделать что-то вроде:
from factoryboy_utils import DBAwareFactory
class MyTest(TestCase):
def test_mymodel_on_db1(self):
...
with DBAwareFactory(MyModelFactory, 'db1') as MyModelFactoryForDB1:
mymodelinstance_on_db1 = MyModelFactoryForDB1()
# whatever you need with that model instance
...
# something else here
def test_mymodel_on_db2(self):
...
with DBAwareFactory(MyModelFactory, 'db2') as MyModelFactoryForDB2:
mymodelinstance_on_db2 = MyModelFactoryForDB2()
# whatever you need with that model instance
...
# something else here