Instances returned by get due to django_get_or_create don't apply kwargs
See original GitHub issueModel
class Currency(models.Model):
iso = models.CharField(max_length=4, unique=True)
fee = models.DecimalField(max_digits=8, decimal_places=2)
Factory
class CurrencyFactory(DjangoModelFactory):
iso = factory.LazyAttribute(lambda x: fake.currency_code())
class Meta:
model = Currency
django_get_or_create = ('iso',)
Test
>>> CurrencyFactory(iso='HKD').fee
Decimal('10.00')
>>> CurrencyFactory(iso='HKD', fee=5).fee
Decimal('10.00')
>>> CurrencyFactory(iso='ABC', fee=5).fee
Decimal('5.00')
>>> CurrencyFactory(iso='ABC', fee=6).fee
Decimal('5.00')
Despite the overriding value provided in the factory constructor, the overriding values are ignored. Is this by design and the docs should ideally clarify this or is this an oversight? It’s particularly annoying to debug this issue in a large test suite that may run in a random order and so sometimes collide.
Issue Analytics
- State:
- Created 5 years ago
- Comments:7 (4 by maintainers)
Top Results From Across the Web
django get_or_create depending on result from a custom ...
Seems to return expected results, although not fully tested in a ... is to try to get an existing instance from # the...
Read more >QuerySet API reference | Django documentation
Django provides a range of QuerySet refinement methods that modify either the types of results returned by the QuerySet or the way its...
Read more >problems with get_or_create - Google Groups
hi,. I have a model like this: name - unique slno - not null mode - not null. If the instance does not...
Read more >Django: Using get_or_create to prevent race conditions
The problem is this: if you hit this part of the code in one thread (meaning the lookup has already taken place and...
Read more >Source code for django.db.models.fields.related_descriptors
Related objects manager for related instances on the reverse side of a ... class (we don't need it) """ if instance is None:...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Hi! FWIW I lost some time today debugging this exact situation. I think the reasoning for not implementing the feature as
update_or_create
is fair, but it violates expectation to explicitly pass in a field value and receive back an object with a different value.+1 for at least updating the docs to make it clear that kwargs are not applied when
get_or_create
is used. I’ll look into submitting a patch for the docs this weekend (but can’t promise I’ll get to it).I see two sources for confusion in my example:
CurrencyFactory(iso='HKD')
) has different results depending on whether it ran before or after the call toCurrencyFactory(iso='HKD', fee=5)
. I think that’s the ordering issue Federico was referring to.CurrencyFactory(iso='HKD')
gets outdated whenCurrencyFactory(iso='HKD', fee=5)
is executed. It updates the row in the DB, but (obviously) does not invalidates previously created test objects.django_update_or_create
adds side effects to a factory call, where the library modifies objects somewhat behind the users’ back. The job of factories is to create test objects, not be a wrapper to update entries in the database.I agree, that’s why in general I prefer not to use
django_get_or_create
at all and create test data from scratch. The test database should ideally be empty and populated with the data that’s relevant for the test. In that case, I know whether the object should be created, or I can get a reference to it if it exists. If the database has an initial state, that state should be known and factories do not seem like the right tool to retrieve or modify existing objects from the database.