edx/XBlock — pull request #247 by mtyaka (2014-10-21 08:03:58+00:00)
Title: Implement callable field defaults.

This patch implements support for callable field defaults.

One of the use cases is to be able to set the field to a random
value at block creation time, for example:

my_field = String(scope=Scope.settings, default: lambda: uuid4().hex)

The standard way to do this without support for callable defaults
is to use a lazy property to populate the field when it is first accessed,
or to generate the default value inside a view. Callable field defaults
provide a more concise way to do it.

Static defaults are not persisted on save, but callable defaults need to
be persisted to be useful, especially when they generate a random value.
This patch introduces a new field parameter `persist_default` that let's
you control whether the default value should be persisted when `save()`
is called. If not given, `persist_default` is `True` for callable defaults
and `False` for static defaults to maintain backwards compatibility.

One difficulty with defaults that persist on save is that the default
value might get generated in a context where it cannot be persisted.
The LMS for example won't write to `content` or `settings` scopes.

This patch introduces `FieldData.is_writable(self, block, name)` method
to be able to only persist default values that can be persisted
in the current context.

Callable defaults were briefly discussed in
https://groups.google.com/forum/#!topic/edx-code/eRZtQ7t4JJY.

Callable defaults as a proof of concept were implemented in the
edx-solutions fork:
https://github.com/edx-solutions/XBlock/commit/f0112919e625ef037d1f

Several edx-solutions XBlocks have been using this feature, for example:
https://github.com/edx-solutions/xblock-discussion/blob/bcd0dcb1c00e07e7/discussion_forum/discussion_forum.py#L49-L51

Two questions for the reviewers:

- Does it make sense to expose the `persist_default` setting?
Would it be acceptable if `persist_default` always defaulted to
`True` (event for static defaults)?
- Is it worth adding `FieldData.is_writtable` to avoid failing with
an error when trying to write default values to a read-only backend?
Would it actually be preferrable to fail in that case?