I have a many-to-one relationship in my SQLAlchemy models. One report has many samples (simplified for brevity):
class Sample(db.Model, CRUDMixin):
sample_id = Column(Integer, primary_key=True)
report_id = Column(Integer, ForeignKey('report.report_id', ondelete='CASCADE'), index=True, nullable=False)
report = relationship('Report', back_populates='samples')
class Report(db.Model, CRUDMixin):
report_id = Column(Integer, primary_key=True)
samples = relationship('Sample', back_populates='report')
Now in my tests, I want to be able to generate a Sample
instance, or a Report
instance, and fill in the missing relationships.
class ReportFactory(BaseFactory):
class Meta:
model = models.Report
report_id = Faker('pyint')
samples = RelatedFactoryList('tests.factories.SampleFactory', size=3)
class SampleFactory(BaseFactory):
class Meta:
model = models.Sample
sample_id = Faker('pyint')
report = SubFactory(ReportFactory)
When I go to create an instance of these, the factories get stuck in an infinite loop:
RecursionError: maximum recursion depth exceeded in comparison
However, if I try to use SelfAttribute
s to stop the infinite loop, I end up with a report without any samples:
class ReportFactory(BaseFactory):
samples = RelatedFactoryList('tests.factories.SampleFactory', size=3, report_id=SelfAttribute('..report_id'))
class SampleFactory(BaseFactory):
report = SubFactory(ReportFactory, samples=[])
report = factories.ReportFactory()
l = len(report.samples) # 0
However, if I generate a Sample
with SampleFactory()
, it correctly has a Report
object.
How should I correctly design my factories such that SampleFactory()
will generate a Sample
with associated Report
, and ReportFactory()
will generate a Report
with 2 associated Samples
, without infinite loops?
report.samples
, SQLAlchemy will dynamically fetch a list ofSample
objects in the DB (or session) pointing to that specificReport
. If you're not working with an ORM, you have to link them manually. – Rehabilitate