Джанго: как динамически указать базу данных для фабричного мальчика

Я настраиваю приложение Django с большим количеством баз данных, и некоторые из них используют одни и те же модели (они не являются репликами). Я уже настроил свои маршрутизаторы, и все работает отлично. Проблема возникает при выполнении тестов, так как я хочу использовать factory-boy.

В другом проекте я мог бы настроить базу данных внутри Meta, но теперь мне нужно выбрать, в какой базе данных создавать экземпляр динамически (если нет, мне пришлось бы создать DjangoModelFactory для каждой базы данных, что было бы некрасиво).

Есть ли (более простой) способ динамического указания базы данных для каждого создания?


person eLRuLL    schedule 12.02.2018    source источник
comment
stackoverflow.com/ вопросы/26550262/   -  person trinchet    schedule 16.02.2018
comment
У меня есть ответ, и мне нужно динамически указывать базу данных каждый раз, когда я хочу создать объект   -  person eLRuLL    schedule 16.02.2018


Ответы (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
person trinchet    schedule 16.02.2018