简体   繁体   English

django:如何为工厂男孩动态指定数据库

[英]django: how to specify database dynamically for factory boy

I am setting up a Django application with a lot of databases, and some of them are using the same models (they are not replicas). 我正在设置一个包含大量数据库的Django应用程序,其中一些使用相同的模型(它们不是复制品)。 I already configured my routers and everything is working great. 我已经配置了我的路由器,一切都很好。 The problem appears when making the tests as I want to use factory-boy . 在进行测试时会出现问题,因为我想使用factory-boy

On a different project I could setup the database inside Meta but now, I have to select on which database to create an instance dynamically (if not, I would have to create a DjangoModelFactory for each database, which wouldn't be pretty). 在一个不同的项目中,我可以在Meta设置数据库但现在,我必须选择在哪个数据库上动态创建一个实例(如果没有,我将不得不为每个数据库创建一个DjangoModelFactory ,这不会很漂亮)。

Is there an (easier) way to specify the database dynamically for each creation? 是否有(更简单的)方法为每个创建动态指定数据库?

As far as I know factory_boy ( version <=2.10.0 ) doesn't provide anything like that. 据我所知, factory_boyversion <=2.10.0 )没有提供类似的东西。

Though, your problem is the perfect use case to use a context manager. 但是,您的问题是使用上下文管理器的完美用例。 It will allow you to set the database dynamically wherever you need and only under the desired scope, and also 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

and then, in your tests, you can do something like: 然后,在您的测试中,您可以执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM