diff options
author | Thomas Goirand <thomas@goirand.fr> | 2014-05-03 22:57:46 +0800 |
---|---|---|
committer | Thomas Goirand <thomas@goirand.fr> | 2014-05-03 22:57:46 +0800 |
commit | 1073f2ae50fb0999712b6744b082f7424e4490c3 (patch) | |
tree | 26943f3545ce1fc1ae54e0398fbbd78df641f54d /docs/recipes.rst | |
parent | c9f01d77941527b62ca67b1064bd3fb849b6a064 (diff) | |
parent | 90db123ada9739a19f3b408b50e006700923f651 (diff) | |
download | factory-boy-1073f2ae50fb0999712b6744b082f7424e4490c3.tar factory-boy-1073f2ae50fb0999712b6744b082f7424e4490c3.tar.gz |
Merge tag '2.3.1' into debian/unstable
Release of factory_boy 2.3.1
Diffstat (limited to 'docs/recipes.rst')
-rw-r--r-- | docs/recipes.rst | 79 |
1 files changed, 69 insertions, 10 deletions
diff --git a/docs/recipes.rst b/docs/recipes.rst index e226732..c1f3700 100644 --- a/docs/recipes.rst +++ b/docs/recipes.rst @@ -25,7 +25,7 @@ use the :class:`~factory.SubFactory` declaration: import factory from . import models - class UserFactory(factory.DjangoModelFactory): + class UserFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.User first_name = factory.Sequence(lambda n: "Agent %03d" % n) @@ -52,7 +52,7 @@ use a :class:`~factory.RelatedFactory` declaration: # factories.py - class UserFactory(factory.DjangoModelFactory): + class UserFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.User log = factory.RelatedFactory(UserLogFactory, 'user', action=models.UserLog.ACTION_CREATE) @@ -62,6 +62,65 @@ When a :class:`UserFactory` is instantiated, factory_boy will call ``UserLogFactory(user=that_user, action=...)`` just before returning the created ``User``. +Example: Django's Profile +""""""""""""""""""""""""" + +Django (<1.5) provided a mechanism to attach a ``Profile`` to a ``User`` instance, +using a :class:`~django.db.models.ForeignKey` from the ``Profile`` to the ``User``. + +A typical way to create those profiles was to hook a post-save signal to the ``User`` model. + +factory_boy allows to define attributes of such profiles dynamically when creating a ``User``: + +.. code-block:: python + + class ProfileFactory(factory.django.DjangoModelFactory): + FACTORY_FOR = my_models.Profile + + title = 'Dr' + # We pass in profile=None to prevent UserFactory from creating another profile + # (this disables the RelatedFactory) + user = factory.SubFactory('app.factories.UserFactory', profile=None) + + class UserFactory(factory.django.DjangoModelFactory): + FACTORY_FOR = auth_models.User + + username = factory.Sequence(lambda n: "user_%d" % n) + + # We pass in 'user' to link the generated Profile to our just-generated User + # This will call ProfileFactory(user=our_new_user), thus skipping the SubFactory. + profile = factory.RelatedFactory(ProfileFactory, 'user') + + @classmethod + def _generate(cls, create, attrs): + """Override the default _generate() to disable the post-save signal.""" + + # Note: If the signal was defined with a dispatch_uid, include that in both calls. + post_save.disconnect(handler_create_user_profile, auth_models.User) + user = super(UserFactory, cls)._generate(create, attrs) + post_save.connect(handler_create_user_profile, auth_models.User) + return user + +.. OHAI_VIM:* + + +.. code-block:: pycon + + >>> u = UserFactory(profile__title=u"Lord") + >>> u.get_profile().title + u"Lord" + +Such behaviour can be extended to other situations where a signal interferes with +factory_boy related factories. + +.. note:: When any :class:`~factory.RelatedFactory` or :class:`~factory.post_generation` + attribute is defined on the :class:`~factory.django.DjangoModelFactory` subclass, + a second ``save()`` is performed *after* the call to ``_create()``. + + Code working with signals should thus override the :meth:`~factory.Factory._generate` + method. + + Simple ManyToMany ----------------- @@ -85,12 +144,12 @@ hook: # factories.py - class GroupFactory(factory.DjangoModelFactory): + class GroupFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.Group name = factory.Sequence(lambda n: "Group #%s" % n) - class UserFactory(factory.DjangoModelFactory): + class UserFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.User name = "John Doe" @@ -140,17 +199,17 @@ If more links are needed, simply add more :class:`RelatedFactory` declarations: # factories.py - class UserFactory(factory.DjangoModelFactory): + class UserFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.User name = "John Doe" - class GroupFactory(factory.DjangoModelFactory): + class GroupFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.Group name = "Admins" - class GroupLevelFactory(factory.DjangoModelFactory): + class GroupLevelFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.GroupLevel user = factory.SubFactory(UserFactory) @@ -213,20 +272,20 @@ Here, we want: .. code-block:: python # factories.py - class CountryFactory(factory.DjangoModelFactory): + class CountryFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.Country name = factory.Iterator(["France", "Italy", "Spain"]) lang = factory.Iterator(['fr', 'it', 'es']) - class UserFactory(factory.DjangoModelFactory): + class UserFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.User name = "John" lang = factory.SelfAttribute('country.lang') country = factory.SubFactory(CountryFactory) - class CompanyFactory(factory.DjangoModelFactory): + class CompanyFactory(factory.django.DjangoModelFactory): FACTORY_FOR = models.Company name = "ACME, Inc." |