There are lots of great answers here, but I can't quite find the one to solve my problem.
Two SQLAlchemy models: Calendar and Transaction. Transactions link to the Calendar model:
class Calendar(Model):
calendar_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
cal_date = db.Column(db.Date, unique=True, nullable=False)
class Transactions(Model):
transaction_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
transaction_date = Column(db.Date, nullable=False)
transaction_calendar_id = reference_col('calendar', pk_name='calendar_id')
transaction_calendar = relationship('Calendar', backref=db.backref('transaction_dates'))
Then Factory Boy classes to generate SQLAlchemy objects:
class CalendarFactory(BaseFactory):
calendar_id = Sequence(lambda n: n)
cal_date = Sequence(lambda n: datetime.date(2021,1,1) + relativedelta(days=n))
class Meta:
model = Calendar
sqlalchemy_get_or_create = ('cal_date', )
class TransactionFactory(BaseFactory):
transaction_date = Sequence(lambda n: datetime.date(2022,1,1) + relativedelta(days=n))
transaction_calendar = SubFactory(CalendarFactory, cal_date=SelfAttribute('..transaction_date'))
class Meta:
model = Transactions
The trouble I'm having is that when my TransactionFactory
is generated, it tries to generate a CalendarFactory object even when there is already one for the given date, and I get the following error:
(sqlite3.IntegrityError) UNIQUE constraint failed: calendar.cal_date
I've tried a number of strategies including StaticFactory
as describe in Avoiding duplicates with factory_boy factories
The solution I'm trying to work on now is described in Choosing from a populated table in factory boy while using flask
This is what I'm trying, but it ain't working:
def lazy_calendar(cal_date):
"""Turn query into a lazily evaluated generator"""
yield from Calendar.query.filter_by(cal_date=cal_date).all()
class TransactionFactory(BaseFactory):
transaction_date = Sequence(lambda n: datetime.date(2022,1,1) + relativedelta(days=n))
transaction_calendar = LazyAttribute(lambda c: lazy_calendar(c.transaction_date))
Question: can I call a Factory Boy Iterator
with a parameter so I can get back the generator with the single date that I want?
Or am I completely barking up the wrong tree here?
Note: this issue has only come to light when I'm running unit tests simulatenously via VS Code Testing feature. When I run my tests sequentially via pytest, it's fine. But I would like to get the multithreaded version working if poss.