summaryrefslogtreecommitdiff
path: root/docs/recipes.rst
diff options
context:
space:
mode:
Diffstat (limited to 'docs/recipes.rst')
-rw-r--r--docs/recipes.rst79
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."