Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 当两个外键指向同一个表时如何使用Factory boy_Python_Django_Python 3.x_Django Models_Factory Boy - Fatal编程技术网

Python 当两个外键指向同一个表时如何使用Factory boy

Python 当两个外键指向同一个表时如何使用Factory boy,python,django,python-3.x,django-models,factory-boy,Python,Django,Python 3.x,Django Models,Factory Boy,我试图使用Factory Boy链接两个Django模型,但我找不到解决此问题的简单解决方案。以下是具有相应工厂的模型: class Currency(models.Model): id = models.CharField(max_length=3, primary_key=True) class ConversionRate(models.Model): currency = models.ForeignKey(Currency, null=False, on_delet

我试图使用Factory Boy链接两个Django模型,但我找不到解决此问题的简单解决方案。以下是具有相应工厂的模型:

class Currency(models.Model):
    id = models.CharField(max_length=3, primary_key=True)


class ConversionRate(models.Model):
    currency = models.ForeignKey(Currency, null=False, on_delete=models.CASCADE)
    quote = models.ForeignKey(Currency, null=False, on_delete=models.CASCADE)
    rate = models.DecimalField(max_digits=6, decimal_places=2)


class CurrencyFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Currency

    id = factory.Sequence(lambda n: ['EUR', 'USD'][n%2])
    conversion_rate = factory.RelatedFactory('my_app.factories.ConversionRateFactory', 'currency')


class ConversionRateFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = ConversionRate

    currency = factory.SubFactory(CurrencyFactory)
    quote = factory.SubFactory(CurrencyFactory, id='EUR')
    rate = 1.2
这是测试表的默认内容:

+--------+   +--------------------------+ 
|Currency|   |       ConversionRate     |
+--------+   +----------+--------+------+ 
|   id   |   | currency |  quote | rate |
+--------+   +----------+--------+------+ 
|  EUR   |   |    USD   |  EUR   |  1.2 |
+--------+   +----------+--------+------+  
|  USD   |   |    EUR   |  EUR   |   1  |
+--------+   +----------+--------+------+  
当我尝试构建工厂时,将抛出完整性错误:

CurrencyFactory.create()
# Error:  UNIQUE constraint failed: Currency.id
我还尝试在CurrencyFactory的“Meta”部分中添加
django\u get\u或\u create=('id',)
,但这会创建一个无限循环

过去有人遇到过这样的问题吗?有什么建议吗

这是使用
django\u get\u或\u create=('id',)
时的回溯:

env/lib/python3.6/site-packages/factory/builder.py:272:in-build
步骤.解决(预处理)
env/lib/python3.6/site-packages/factory/builder.py:221:解析中
self.attributes[field\u name]=getattr(self.stub,field\u name)
env/lib/python3.6/site packages/factory/builder.py:375:in\uuu getattr__
额外=上下文,
env/lib/python3.6/site-packages/factory/declarations.py:324:in-evaluate
返回self.generate(步骤,默认值)
env/lib/python3.6/site-packages/factory/declarations.py:414:in-generate
返回步骤递归(子工厂,参数,强制顺序=强制顺序)
env/lib/python3.6/site-packages/factory/builder.py:233:in-recurse
返回builder.build(父步骤=自,强制顺序=强制顺序)
env/lib/python3.6/site-packages/factory/builder.py:299:in-build
上下文=后生成上下文,
env/lib/python3.6/site-packages/factory/declarations.py:675:in-call
返回步骤递归(工厂,已通过)
env/lib/python3.6/site-packages/factory/builder.py:233:in-recurse
返回builder.build(父步骤=自,强制顺序=强制顺序)
env/lib/python3.6/site-packages/factory/builder.py:272:in-build
步骤.解决(预处理)
env/lib/python3.6/site-packages/factory/builder.py:221:解析中
self.attributes[field\u name]=getattr(self.stub,field\u name)
env/lib/python3.6/site packages/factory/builder.py:375:in\uuu getattr__
额外=上下文,
env/lib/python3.6/site-packages/factory/declarations.py:324:in-evaluate
返回self.generate(步骤,默认值)
env/lib/python3.6/site-packages/factory/declarations.py:414:in-generate
返回步骤递归(子工厂,参数,强制顺序=强制顺序)
env/lib/python3.6/site-packages/factory/builder.py:233:in-recurse
返回builder.build(父步骤=自,强制顺序=强制顺序)
env/lib/python3.6/site-packages/factory/builder.py:279:内置
kwargs=kwargs,
env/lib/python3.6/site packages/factory/base.py:314:in实例化
返回self.factory.\u创建(模型,*args,**kwargs)
env/lib/python3.6/site-packages/factory/django.py:163:in\u-create
返回cls.\u获取或创建(模型类,*args,**kwargs)
env/lib/python3.6/site-packages/factory/django.py:154:in\u-get\u或\u-create
实例,_created=manager.get_或_create(*args,**键\u字段)
env/lib/python3.6/site-packages/django/db/models/manager.py:82:in-manager\u方法
返回getattr(self.get_queryset(),name)(*args,**kwargs)
env/lib/python3.6/site-packages/django/db/models/query.py:487:in-get\u或\u-create
返回self.get(**查找),False
env/lib/python3.6/site-packages/django/db/models/query.py:394:in-get
clone=self.filter(*args,**kwargs)
env/lib/python3.6/site-packages/django/db/models/query.py:836:in-filter
返回self.\u filter\u或\u exclude(False、*args、**kwargs)
env/lib/python3.6/site-packages/django/db/models/query.py:850:in\u-filter\u或\u-exclude
克隆=自我。_chain()
env/lib/python3.6/site-packages/django/db/models/query.py:1156:in\u-chain
obj=自我。_克隆()
env/lib/python3.6/site packages/django/db/models/query.py:1168:in\u clone
c=self.\uuuuu类(model=self.model,query=self.query.chain(),using=self.\u db,hints=self.\u hints)
env/lib/python3.6/site-packages/django/db/models/sql/query.py:337:in-chain
obj=self.clone()
env/lib/python3.6/site-packages/django/db/models/sql/query.py:300:in-clone
obj.where=self.where.clone()
env/lib/python3.6/site-packages/django/db/models/sql/where.py:148:in-clone
子项=[],连接器=self.connector,否定=self.negated)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls=,children=[],connector='和',negated=False
@类方法
def_新实例(cls,children=None,connector=None,negated=False):
"""
创建新节点(或子类)时创建此类的新实例
该类的内部代码中需要。通常,它只是阴影
__但是,具有uu init_uu签名的子类
Node.\uuu init\uuuu的扩展可能需要实现此方法以
允许节点创建它们的新实例(如果它们有额外的
设置要做的事情)。
"""
>obj=节点(子节点、连接器、否定)
E RecursionError:调用Python对象时超出了最大递归深度

正如您所指出的,问题来自于
CurrencyFactory
创建
转换率工厂
,该工厂反过来创建2
CurrencyFactory

我建议使用
factory.Trait
通过递归禁用它:

  • 在工厂
    类参数
    部分定义特征:启用时(通过设置布尔标志),它将添加附加的声明
  • 为该特征设置一个默认值
    True
    :直接调用
    CurrencyFactory
    将添加一个
    ConversionRate
  • 转换率工厂中
    
        env/lib/python3.6/site-packages/factory/builder.py:272: in build
            step.resolve(pre)
        env/lib/python3.6/site-packages/factory/builder.py:221: in resolve
            self.attributes[field_name] = getattr(self.stub, field_name)
        env/lib/python3.6/site-packages/factory/builder.py:375: in __getattr__
            extra=context,
        env/lib/python3.6/site-packages/factory/declarations.py:324: in evaluate
            return self.generate(step, defaults)
        env/lib/python3.6/site-packages/factory/declarations.py:414: in generate
            return step.recurse(subfactory, params, force_sequence=force_sequence)
        env/lib/python3.6/site-packages/factory/builder.py:233: in recurse
            return builder.build(parent_step=self, force_sequence=force_sequence)
        env/lib/python3.6/site-packages/factory/builder.py:299: in build
            context=postgen_context,
        env/lib/python3.6/site-packages/factory/declarations.py:675: in call
            return step.recurse(factory, passed_kwargs)
        env/lib/python3.6/site-packages/factory/builder.py:233: in recurse
            return builder.build(parent_step=self, force_sequence=force_sequence)
        env/lib/python3.6/site-packages/factory/builder.py:272: in build
            step.resolve(pre)
        env/lib/python3.6/site-packages/factory/builder.py:221: in resolve
            self.attributes[field_name] = getattr(self.stub, field_name)
        env/lib/python3.6/site-packages/factory/builder.py:375: in __getattr__
            extra=context,
        env/lib/python3.6/site-packages/factory/declarations.py:324: in evaluate
            return self.generate(step, defaults)
        env/lib/python3.6/site-packages/factory/declarations.py:414: in generate
            return step.recurse(subfactory, params, force_sequence=force_sequence)
        env/lib/python3.6/site-packages/factory/builder.py:233: in recurse
            return builder.build(parent_step=self, force_sequence=force_sequence)
        env/lib/python3.6/site-packages/factory/builder.py:279: in build
            kwargs=kwargs,
        env/lib/python3.6/site-packages/factory/base.py:314: in instantiate
            return self.factory._create(model, *args, **kwargs)
        env/lib/python3.6/site-packages/factory/django.py:163: in _create
            return cls._get_or_create(model_class, *args, **kwargs)
        env/lib/python3.6/site-packages/factory/django.py:154: in _get_or_create
            instance, _created = manager.get_or_create(*args, **key_fields)
        env/lib/python3.6/site-packages/django/db/models/manager.py:82: in manager_method
            return getattr(self.get_queryset(), name)(*args, **kwargs)
        env/lib/python3.6/site-packages/django/db/models/query.py:487: in get_or_create
            return self.get(**lookup), False
        env/lib/python3.6/site-packages/django/db/models/query.py:394: in get
            clone = self.filter(*args, **kwargs)
        env/lib/python3.6/site-packages/django/db/models/query.py:836: in filter
            return self._filter_or_exclude(False, *args, **kwargs)
        env/lib/python3.6/site-packages/django/db/models/query.py:850: in _filter_or_exclude
            clone = self._chain()
        env/lib/python3.6/site-packages/django/db/models/query.py:1156: in _chain
            obj = self._clone()
        env/lib/python3.6/site-packages/django/db/models/query.py:1168: in _clone
            c = self.__class__(model=self.model, query=self.query.chain(), using=self._db, hints=self._hints)
        env/lib/python3.6/site-packages/django/db/models/sql/query.py:337: in chain
            obj = self.clone()
        env/lib/python3.6/site-packages/django/db/models/sql/query.py:300: in clone
            obj.where = self.where.clone()
        env/lib/python3.6/site-packages/django/db/models/sql/where.py:148: in clone
            children=[], connector=self.connector, negated=self.negated)
    
        _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    
        cls = <class 'django.db.models.sql.where.WhereNode'>, children = [], connector = 'AND', negated = False
    
            @classmethod
            def _new_instance(cls, children=None, connector=None, negated=False):
                """
                    Create a new instance of this class when new Nodes (or subclasses) are
                    needed in the internal code in this class. Normally, it just shadows
                    __init__(). However, subclasses with an __init__ signature that aren't
                    an extension of Node.__init__ might need to implement this method to
                    allow a Node to create a new instance of them (if they have any extra
                    setting up to do).
                    """
        >       obj = Node(children, connector, negated)
        E       RecursionError: maximum recursion depth exceeded while calling a Python object
    
    class CurrencyFactory(factory.django.DjangoModelFactory):
        class Meta:
            model = models.Currency
            django_get_or_create = ['id']
    
        class Params:
            with_conversion_rate = factory.Trait(
                conversion_rate=factory.RelatedFactory('my_app.factories.ConversionRateFactory', 'currency'),
            )
    
        # Small improvement: use a `factory.Iterator` to cycle between value
        id = factory.Iterator(['EUR', 'USD'])
        # By default, force each CurrencyFactory to create a ConversionRate.
        with_conversion_rate = True
    
    class ConversionRateFactory(factory.django.DjangoModelFactory):
        class Meta:
            model = models.ConversionRate
    
        rate = 1.2
        currency = factory.SubFactory(
            CurrencyFactory,
            with_conversion_rate=False,
        )
        quote = factory.SubFactory(
            CurrencyFactory,
            id='EUR',
            with_conversion_rate=False,
        )