Populating a non-nullable Django OneToOne field with a method

88 views
Skip to first unread message

dwil...@gmail.com

unread,
Aug 19, 2016, 6:49:21 PM8/19/16
to Factory Boy
Hello,

I have been dealing with this problem for a day and a half and I figured it was time to ask an expert.

I took the time to write it up as nicely as I could in a GitHubGist since groups does not support styling.

https://gist.github.com/dtw45/46fbbf01cf73f368ecb060f162705f22

Thanks,
Derek

Raphaël Barrois

unread,
Aug 20, 2016, 7:30:22 AM8/20/16
to dwil...@gmail.com, Factory Boy
Hi,

If I understand correctly, your use case is, globally:

1. Create a TourDay, maybe with a TourDayFactory
2. Create a Stop related that TourDay, with a StopFactory
3. Create an Advance object with an AdvanceFactory

However, the recipe for creating a ``Stop`` is complex, and needs its own method.

The best way is to use the dedicated extension point to override the factory's creation method
(http://factoryboy.readthedocs.io/en/latest/reference.html#factory.Factory._create) :

class StopFactory(factory.django.DjangoModelFactory):
class Meta:
model = models.Stop

day_order = 99
tour = factory.SelfAttribute('..tour')
location = factory.SelfAttribute('..venue.location')
drive_time = factory.SubFactory(TimeFactory, day=factory.SelfAttribute('...day'))

@classmethod
def _create(cls, model_class, location, drive_time, **kwargs):
"""Override the default ``create()`` recipe to use create_stop"""
day_id = drive_time.day_id
return model_class.objects.create_stop(day_id, location, **kwargs)

Cheers,

--
Raphaël Barrois

dwil...@gmail.com

unread,
Aug 23, 2016, 4:11:18 PM8/23/16
to Factory Boy, dwil...@gmail.com
Thanks for the response.

Overriding the _create method was exactly what I was looking for.

This is what I wound up with.

##### Begin code excerpt #####

class StopFactory(DjangoModelFactory):

class Meta:
model = Stop

# No need to add defaults since they will just
# be overwritten by the overridden create method

@classmethod
def _create(cls, model_class, day_id, location, **kwargs):
# Override the default `create()` recipe to use create_stop
return model_class.objects.create_stop(day_id, location, kwargs)

class AdvanceFactory(DjangoModelFactory):

class Meta:
model = Advance

day = factory.Iterator(TourDay.objects.all())
tour = factory.SelfAttribute('day.tour')
stop = factory.SubFactory(StopFactory,
day_id=factory.SelfAttribute('..day.id'),
location=factory.SelfAttribute('..venue.location'))
venue = factory.Iterator(Venue.objects.all())
label = factory.SelfAttribute('venue.name')
notes = lazy_attribute(lambda o: faker.sentence())
manager_notes = lazy_attribute(lambda o: faker.sentence())

##### End code excerpt #####

Thanks, again!

-Derek

Reply all
Reply to author
Forward
0 new messages