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
Другие вопросы по тегам