Я хотел бы определить две модели, Company
и Package
. Каждый Package
имеет только один Company
, но Company
может иметь несколько Packages
. Однако у каждой компании может быть только один default_package
(который может быть нулевым). Я установил это следующим образом:
class Company(models.Model):
default_package = models.OneToOneField(
'dashboard.Package',
on_delete=models.SET_NULL,
blank=True,
null=True,
related_name='default_for_%(class)s')
class Package(models.Model):
company = models.ForeignKey(Company, on_delete=models.CASCADE)
где dashboard
— метка приложения.
Чтобы упростить тесты с этими моделями, я создал для них фабрики тестов, используя factory_boy
. следующим образом:
import factory
from .models import Company, Package
class CompanyFactory(factory.Factory):
class Meta:
model = Company
default_package = factory.SubFactory('dashboard.test_factories.PackageFactory')
class PackageFactory(factory.Factory):
class Meta:
model = Package
company = factory.SubFactory(CompanyFactory)
Теперь я пробую два теста:
class DefaultPackageTest(TestCase):
def test_1(self):
company = Company.objects.create()
def test_2(self):
company = CompanyFactory()
Первый просто создает Company
, тогда как второй пытается сделать то же самое, используя CompanyFactory
.
Как ни странно, первый тест проходит, а второй не проходит:
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/factory/builder.py", line 233, in recurse
return builder.build(parent_step=self, force_sequence=force_sequence)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/factory/builder.py", line 272, in build
step.resolve(pre)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/factory/builder.py", line 221, in resolve
self.attributes[field_name] = getattr(self.stub, field_name)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/factory/builder.py", line 355, in __getattr__
declaration = self.__declarations[name]
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/factory/builder.py", line 121, in __getitem__
context=self.contexts[key],
RecursionError: maximum recursion depth exceeded
----------------------------------------------------------------------
Ran 2 tests in 0.012s
FAILED (errors=1)
Destroying test database for alias 'default'...
Любая идея, почему это не работает? Кажется, я следил за документацией (http://factoryboy.readthedocs.io/en/latest/reference.html#circular-imports), указав полный путь к подфабрике CompanyFactory
.
Обновить
Похоже, что этот вариант использования решается постгенерации Factory Boy. крючки. Что кажется многообещающим, так это RelatedFactory
, для которого приведен следующий пример. :
class CityFactory(factory.Factory):
class Meta:
model = City
capital_of = None
name = "Toronto"
class CountryFactory(factory.Factory):
class Meta:
model = Country
lang = 'fr'
capital_city = factory.RelatedFactory(CityFactory, 'capital_of', name="Paris")
который тестируется в Python REPL следующим образом:
>>> france = CountryFactory()
>>> City.objects.get(capital_of=france)
<City: Paris>
Однако мне трудно применить этот пример к моей ситуации. (Не помогает то, что в документах нет текстового объяснения или кода моделей City
и Country
). Кажется, что capital_city
в моем случае аналогично default_package
, поэтому я попытался превратить его в RelatedFactory
вот так,
default_package = factory.RelatedFactory('dashboard.test_factories.PackageFactory')
но я все еще получаю ту же ошибку.
company = CompanyFactory(default_package=None)
, а затем сCompanyFactory(default_package__company=company)
? - person Paulo Almeida   schedule 17.03.2018Company
не будет иметь атрибутаdefault_package
. Что я на самом деле хотел бы сделать, так это когда я создаю компанию сCompanyFactory
, также создаю объектPackage
,default_for_company
которого является этой компанией. Как я могу этого добиться? - person Kurt Peek   schedule 17.03.2018company
, не могли бы вы создать пакет с этой компанией, а затем установитьdefault_package
company
в этот пакет? - person Paulo Almeida   schedule 17.03.2018