Search code examples
djangopython-3.xfactory-boypytest-django

Django factory boy post_generation in field with default value don't work


I have a model with a field that is a int type, that field have a default value

I'm trying to set a value in that field with post_generation but nothing is happening, the field stay with the default value, when I try to use .set I get the following error:

AttributeError: 'int' object has no attribute 'set'

this is the field that I'm trying to populate

@factory.post_generation
def priority(obj, create, extracted, **kwargs):
    for series in range(obj.patrimony.count()): # this is a sequence of numbers
        series += 1
        obj.priority.set(series)

and this is the model, is just a simple model

class Series(models.Model):
    priority = models.IntegerField(_("Priority"), default=0, null=True)

Can someone open my eyes please?


Solution

  • You are meeting two issues:

    Setting the field value

    Series.priority is always an int, and integers have no .set() method (they are immutable objects). You should set it by using obj.priority = series

    Setting the value at the right time

    factory_boy creates objects in 3 steps: 1. Evaluate all pre-declarations (LazyAttribute, Sequence, etc.); 2. Create the object in the database (calling Series.objects.create(...)) 3. Evaluate post-generation declarations

    If obj.patrimony is known before creating the series, you could simply have:

    class SeriesFactory(factory.django.DjangoModelFactory):
        class Meta:
            model = Series
        priority = factory.LazyAttribute(lambda o: o.patrimony.count())
    

    (I've also adjusted the declaration, since your for series in ... loop is strictly equivalent to obj.priority = obj.patrimony.count())