factory_boy objects seem to lack primary keys
Asked Answered
M

2

9

When I create factory_boy objects, the object doesn't appear to have a primary key and I'm not sure why. Here's my model and factory:

# models.py
from django.db import models
from django.contrib.auth.models import User

class UserProfile(models.Model):
    # UserProfile is a subset table of User.  They have a 1:1 relationship.
    user = models.ForeignKey(User, unique=True)
    gender = models.CharField(max_length=1)

# factories.py
import factory
from django.contrib.auth.models import User
from .models import UserProfile

class UserFactory(factory.Factory):
    FACTORY_FOR = User
    username = 'jdoe'

class UserProfileFactory(factory.Factory):
    FACTORY_FOR = UserProfile
    user = factory.lazy_attribute(lambda a: UserFactory())
    gender = 'M'

Now according to the factory_boy documentation on associations, if I create a User instance, I should get an 'id' field. However, I don't. This is what I get (in the interpreter):

>>> from app.factories import UserFactory, UserProfileFactory
>>> user = UserFactory()
>>> user.username  # This result is correct
'jdoe'
>>> user.id is None   # User should be 'saved' and so this should return False
True

Similarly:

>>> user_profile = UserProfileFactory()
>>> user_profile.gender   # This is OK
'M'
>>> user_profile.user     # This is OK
<User: jdoe>
>>> user_profile.id is None  # Why isn't this False?
True

The documentation says these user.id and user_profile.id commands should return 'False' instead of 'True' since I'm creating (as opposed to building) factory_boy instances. What am I missing here? Why am I not getting an 'id' value when I create these instances? It seems that the only way I can get an id is by explicitly creating an 'id' attribute in my factories. However, I don't see this done anywhere in the documentation so I don't think that's what you're supposed to do.

Thanks.

Mentor answered 23/9, 2013 at 15:47 Comment(0)
H
20

For django support you need to use DjangoModelFactory:

https://factoryboy.readthedocs.org/en/latest/orms.html#the-djangomodelfactory-subclass

Harrietteharrigan answered 23/9, 2013 at 17:9 Comment(2)
Thanks, mariodev. I might add, for the benefit of others, than the example code at the above link appears to be incorrect. If you say, "FACTORY_FOR = 'myapp.User', you'll get the error: "AttributeError: 'str' object has no attribute 'object'." You shouldn't put quotes around myapp.User.Mentor
Had this issue a year ago, solved it with this answer. Came back now, after struggling with this on different project, and just saw I already +1 you. Eventually I will learn!Scheider
A
5

For the sake of completeness, it's also worthwhile to note that in order to explicitly save a factory to the database, the documentation says you can use:

user = UserProfile.create()

which does the same thing as the following once you are using a subclass of DjangoModelFactory:

user = UserProfile()

Only when objects are saved to the database do they recieve PK's.

To create a factory and explicitly not save it to the database, use:

user = UserProfile.build()
Argenteuil answered 29/10, 2013 at 16:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.