Set attribute using LazyAttribute only if another attribute exists
Hello, I have this kind of Django model:
from djmoney.models.fields import MoneyField
from moneyed import Money
class Item(models.Model):
total_due = MoneyField(max_digits=17,
decimal_places=7,
default_currency=DEFAULT_CURRENCY,
currency_choices=CURRENCIES_CHOICES,
null=True, blank=True)
c_total_due = = MoneyField(max_digits=17,
decimal_places=7,
default_currency=DEFAULT_CURRENCY,
currency_choices=CURRENCIES_CHOICES,
null=True, blank=True)
The field c_total_due is computed from total_due so its value is always related to it.
Given that, if the total_due is set then I would like my factory to generate the the c_total_due to be exactly the same as total_due if not explicitly set:
class ItemFactory(factory.DjangoModelFactory):
class Meta:
model = Item
c_total_due = factory.LazyAttribute(lambda o: o.total_due)
The problem is that if I don't explicitly create a factory object by passing a total_due this will fail.
AttributeError: The parameter total_charged is unknown.
Is there a way to set a value of an attribute based on another one using the LazyAttribute lambda only if the first attribute is set in the first place?
I hope I was clear : ]
Recommended option:
You can simply set total_due = None in your factory (which is actually what would be used by Django if you don't provide anything):
class ItemFactory:
total_due = None
c_total_due = factory.SelfAttribute('total_due')
This way, ItemFactory() will call Item.objects.create(total_due=None, c_total_due=None), and ItemFactory(total_due=42) calls Item.objects.create(total_due=42, c_total_due=42).
Other option:
Another option would be to use factory.Maybe:
class ItemFactory:
c_total_due = factory.Maybe('total_due', factory.SelfAttribute('total_due'), None)
This will set c_total_due to the value of total_due if total_due is set, and will hide it if total_due isn't provided:
ItemFactory()will callItem.objects.create()ItemFactory(total_due=42)callsItem.objects.create(total_due=42, c_total_due=42).
This second option is mostly useful if your model itself has some rules to compute default values for total_due / c_total_due that you don't want to override/copy to the factory.
Thank you very much!
The second option seems to fit perfectly for my requirements. Although, I couldn't make it work :\
class ItemFactory(factory.DjangoModelFactory):
class Meta:
model = Item
c_total_due = factory.Maybe('total_due', factory.SelfAttribute('total_due'), None)
class SpecificFactory(ItemFactory):
another_field = None
And I call it like this:
my_obj = SpecificFactory(another_field=42, **{'total_due': 400})
I can see that my_obj.total_due == 400 but my_obj.c_total_due seems to be always None.
Did I skip a step or am I missing something?
I'm using
factory-boy==2.11.1
Django==1.11.5
with python 3.5