我使用factory_boy创建测试装置。我有两个简单的工厂,由SQLAlchemy模型支持(简化如下)。
我希望能够多次致电AddressFactory.create()
,并且如果它已经存在则创建Country
,否则我希望它重复使用现有记录。
class CountryFactory(factory.Factory):
FACTORY_FOR = Country
cc = "US"
name = "United States"
class AddressFactory(factory.Factory):
FACTORY_FOR = Address
name = "Joe User"
city = "Seven Mile Beach"
country = factory.SubFactory(CountryFactory, cc="KY", name="Cayman Islands")
我的问题是:如何设置这些工厂,以便factory_boy每次创建地址时都不会尝试创建新的国家/地区?
答案 0 :(得分:6)
在最新的工厂男孩== 2.3.1中你可以添加FACTORY_DJANGO_GET_OR_CREATE
class CountryFactory(factory.django.DjangoModelFactory):
FACTORY_FOR = 'appname.Country'
FACTORY_DJANGO_GET_OR_CREATE = ('cc',)
cc = "US"
name = "United States"
假设cc字段是唯一标识符。
答案 1 :(得分:3)
While you're right that there's no get_or_create
function for SQLAlchemy-based factories, if the objects you want to use as a foreign key already exist, you can iterate through them:
http://factoryboy.readthedocs.org/en/latest/recipes.html#choosing-from-a-populated-table
So conceivably you could hack together a solution in your factory by using a lazy attribute that first checks if the object exists in the db, and if so it uses this method to iterate through them, but if the object doesn't exist, it calls a SubFactory
to create the object first.
答案 2 :(得分:0)
另一个hacky解决方案是以一种查询和缓存结果来搜索对象的方式覆盖工厂的create
方法。
这个简单的例子虽然没有对**kwargs
进行过滤:
class StaticFactory(SQLAlchemyModelFactory):
counter = 0
cache = []
model = None
@classmethod
def create(cls, **kwargs):
if not cls.cache:
cls.cache = your_session.query(cls.model).all()
instance = cls.cache[cls.counter]
cls.counter = (cls.counter + 1) % len(cls.cache)
return instance
答案 3 :(得分:0)
对于SqlAlchemy,您可以尝试此操作。这也是cahce工厂:
class StaticFactory(factory.alchemy.SQLAlchemyModelFactory):):
__static_exclude = ('__static_exclude', '__static_cache',)
__static_cache = {}
@classmethod
def _create(cls, model_class, *args, **kwargs):
"""Helper for avoid duplicate factory"""
# Exclude static cache
cls._meta.exclude += cls.__static_exclude
_unique_key = None
# Get first unique keys from table. I'll be cache key.
for col in model_class.__table__.columns:
if any([col.primary_key, col.unique]):
_unique_key = kwargs.get(col.name)
if _unique_key:
break
_instance = cls.__static_cache.get(_unique_key)
if _instance:
return _instance
_session = cls._meta.sqlalchemy_session
with _session.no_autoflush:
obj = model_class(*args, **kwargs)
_session.add(obj)
cls.__static_cache.update({_unique_key: obj})
return obj
class LanguageFactory(StaticFactory):
class Meta:
model = Language
exclude = ('lang',)
答案 4 :(得分:0)
我们可以使用 factory.Iterator 方法
用现有的国家/地区实例创建地址的新实例import factory, factory.django
from . import models
class CountryFactory(factory.Factory.DjangoModelFactory):
model = models.Country
cc = "US"
name = "United States"
class AddressFactory(factory.Factory.DjangoModelFactory):
model = models.Address
name = "Joe User"
city = "Seven Mile Beach"
country = factory.Iterator(models.Country.objects.all())
在这里,我们从数据库访问Country实例,并将其传递给AddressFactory的country属性,该属性使用数据库中已经创建的country实例创建一个地址实例。