summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/reference.rst117
1 files changed, 93 insertions, 24 deletions
diff --git a/docs/reference.rst b/docs/reference.rst
index 03023fc..70ca38a 100644
--- a/docs/reference.rst
+++ b/docs/reference.rst
@@ -863,6 +863,7 @@ Some objects expect additional method calls or complex processing for proper def
For instance, a ``User`` may need to have a related ``Profile``, where the ``Profile`` is built from the ``User`` object.
To support this pattern, factory_boy provides the following tools:
+ - :class:`PostGenerationMethodCall`: allows you to hook a particular attribute to a function call
- :class:`PostGeneration`: this class allows calling a given function with the generated object as argument
- :func:`post_generation`: decorator performing the same functions as :class:`PostGeneration`
- :class:`RelatedFactory`: this builds or creates a given factory *after* building/creating the first Factory.
@@ -1047,60 +1048,121 @@ PostGenerationMethodCall
.. class:: PostGenerationMethodCall(method_name, extract_prefix=None, *args, **kwargs)
-.. OHAI_VIM*
+ .. OHAI_VIM*
+
+ The :class:`PostGenerationMethodCall` declaration will call a method on
+ the generated object just after instantiation. This declaration class
+ provides a friendly means of generating attributes of a factory instance
+ during initialization. The declaration is created using the following arguments:
+
+ .. attribute:: method_name
+
+ The name of the method to call on the :attr:`~Factory.FACTORY_FOR` object
-The :class:`PostGenerationMethodCall` declaration will call a method on the
-generated object just after it being called.
+ .. attribute:: extract_prefix
-Its sole argument is the name of the method to call.
-Extra arguments and keyword arguments for the target method may also be provided.
+ If a string, the keyword argument prefix by which the field will get its
+ overriding arguments. If ``None``, defaults to the name of the attribute.
-Once the object has been generated, the method will be called, with arguments
-taken from either the :class:`PostGenerationMethodCall` or prefix-based values:
+ .. deprecated:: 1.3.0
+ Will be removed in 2.0.0
-- If a value was extracted from kwargs (i.e an argument for the name the
- :class:`PostGenerationMethodCall` was declared under):
+ .. attribute:: args
- - If the declaration mentionned zero or one argument, the value is passed
- directly to the method
- - If the declaration used two or more arguments, the value is passed as
- ``*args`` to the method
+ The default set of unnamed arguments to pass to the method given in
+ :attr:`method_name`
-- Otherwise, the arguments used when declaring the :class:`PostGenerationMethodCall`
- are used
+ .. attrinbute:: kwargs
-- Keywords extracted from the factory arguments are merged into the defaults
- present in the :class:`PostGenerationMethodCall` declaration.
+ The default set of keyword arguments to pass to the method given in
+ :attr:`method_name`
+
+Once the factory instance has been generated, the method specified in
+:attr:`~PostGenerationMethodCall.method_name` will be called on the generated object
+with any arguments specified in the :class:`PostGenerationMethodCall` declaration, by
+default.
+
+For example, to set a default password on a generated User instance
+during instantiation, we could make a declaration for a ``password``
+attribute like below:
.. code-block:: python
class UserFactory(factory.Factory):
FACTORY_FOR = User
- password = factory.PostGenerationMethodCall('set_password', password='')
+ username = 'user'
+ password = factory.PostGenerationMethodCall('set_password',
+ 'defaultpassword')
+
+When we instantiate a user from the ``UserFactory``, the factory
+will create a password attribute by calling ``User.set_password('defaultpassword')``.
+Thus, by default, our users will have a password set to ``'defaultpassword'``.
.. code-block:: pycon
- >>> UserFactory() # Calls user.set_password(password='')
- >>> UserFactory(password='test') # Calls user.set_password('test')
- >>> UserFactory(password__disabled=True) # Calls user.set_password(password='', disabled=True)
+ >>> u = UserFactory() # Calls user.set_password('defaultpassword')
+ >>> u.check_password('defaultpassword')
+ True
+
+If the :class:`PostGenerationMethodCall` declaration contained no
+arguments or one argument, an overriding the value can be passed
+directly to the method through a keyword argument matching the attribute name.
+For example we can override the default password specified in the declaration
+above by simply passing in the desired password as a keyword argument to the
+factory during instantiation.
+
+.. code-block:: pycon
+
+ >>> other_u = UserFactory(password='different') # Calls user.set_password('different')
+ >>> other_u.check_password('defaultpassword')
+ False
+ >>> other_u.check_password('different')
+ True
+
+.. note:: For Django models, unless the object method called by
+ :class:`PostGenerationMethodCall` saves the object back to the
+ database, we will have to explicitly remember to save the object back
+ if we performed a ``create()``.
+
+ .. code-block:: pycon
+
+ >>> u = UserFactory.create() # u.password has not been saved back to the database
+ >>> u.save() # we must remember to do it ourselves
-When the :class:`PostGenerationMethodCall` declaration uses two or more arguments,
-the extracted value must be iterable:
+ We can avoid this by subclassing from :class:`DjangoModelFactory`,
+ instead, e.g.,
+
+ .. code-block:: python
+
+ class UserFactory(factory.DjangoModelFactory):
+ FACTORY_FOR = User
+
+ username = 'user'
+ password = factory.PostGenerationMethodCall('set_password',
+ 'defaultpassword')
+
+
+If instead the :class:`PostGenerationMethodCall` declaration uses two or
+more positional arguments, the overriding value must be an iterable. For
+example, if we declared the ``password`` attribute like the following,
.. code-block:: python
class UserFactory(factory.Factory):
FACTORY_FOR = User
+ username = 'user'
password = factory.PostGenerationMethodCall('set_password', '', 'sha1')
+then we must be cautious to pass in an iterable for the ``password``
+keyword argument when creating an instance from the factory:
+
.. code-block:: pycon
>>> UserFactory() # Calls user.set_password('', 'sha1')
>>> UserFactory(password=('test', 'md5')) # Calls user.set_password('test', 'md5')
- >>> UserFactory(password__disabled=True) # Calls user.set_password('', 'sha1', disabled=True)
>>> # Always pass in a good iterable:
>>> UserFactory(password=('test',)) # Calls user.set_password('test')
@@ -1116,6 +1178,13 @@ the extracted value must be iterable:
value to the :class:`PostGenerationMethodCall` declaration
(``PostGenerationMethodCall('method', 'x', 'y_that_is_the_default')``)
+Keywords extracted from the factory arguments are merged into the
+defaults present in the :class:`PostGenerationMethodCall` declaration.
+
+.. code-block:: pycon
+
+ >>> UserFactory(password__disabled=True) # Calls user.set_password('', 'sha1', disabled=True)
+
Module-level functions
----------------------