question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot pass id instead of related object to DjangoModelFactory

See original GitHub issue

The problem

When I create an instance of a Django model, I can pass a related object directly, or its id.

article = Article.objects.create(author=author)
article = Article.objects.create(author_id=author.pk)

One would expect a Django model factory to work the same way, but it doesn’t. Everything breaks and there is no documentation regarding this use case.

Proposed solution

Ideally allow both strategies, but if not at least document this and explain how to do it.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:1
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
rbarroiscommented, Sep 14, 2020

Basically, factory_boy doesn’t care whether it’s working with IDs, instances, or anything else. It takes your declarations, computes the values (following subfactories, etc.), and sends the resulting payload as arguments and keyword arguments to the class you’ve provided for a model.

If you want a factory that will use a passed-in author_id if provided, but uses a SubFactory to create an Author if needed, you could use the following:

class ArticleFactory(factory.django.DjangoModelFactory):
    class Meta:
        model = Article

    author = factory.Maybe("author_id", no_declaration=factory.SubFactory(AuthorFactory))

This way:

  • If you simply call the factory, since no author_id has been provided, the Maybe declaration will use its “else” branch and call AuthorFactory to get an instance;
  • If you pass in an author_id (e.g ArticleFactory(author_id=42)), the Maybe declaration will be skipped and only the author_id will be passed to Article.objects.create().
  • If you pass both author_id and author, the result will depend on Django’s implementation.

The _adjust_kwargs function is useful in more complex cases, but is only called once the declarations have been resolved; it can’t prevent calling an AuthorFactory earlier on, which might be an issue for your code.

0reactions
rbarroiscommented, Nov 2, 2020

@MRigal Indeed. Feel free to open a pull request with that prose in there 😉

Read more comments on GitHub >

github_iconTop Results From Across the Web

Getting id of associated child records in factory_boy
For your example, I'd go with the following factories: class FunctionFactory(factory.django.DjangoModelFactory): class Meta: model = models.
Read more >
Pass id of generated object to SubFactory · Issue #763 - GitHub
I have the next piece of code: deliverer = factory.SubFactory( 'orders.tests.factories.DelivererFactory', company_made_id=factory.
Read more >
Reference — Factory Boy stable documentation
If set, the object generated by the factory declaring the RelatedFactory is passed as keyword argument to the related factory. class CityFactory(factory.Factory): ...
Read more >
Testing Models with Django using Faker and Factory Boy
you can add factory.Sequence. import factoryclass CompanyFactory(factory.DjangoModelFactory): """ | id | name | |:-- ...
Read more >
Factory Boy Fun - Adam Johnson
... to fill your development database rather than dumping from production. ... JSON objects with data to be passed to the model constructor; ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found