customfields.rst 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. .. _custom-fields:
  2. Custom Fields
  3. =============
  4. The Problem
  5. -----------
  6. South stores field definitions by storing both their class and the arguments that
  7. need to be passed to the field's constructor, so it can recreate the field
  8. instance simply by calling the class with the stored arguments.
  9. However, since Python offers no way to get the arguments used in a class'
  10. constructor directly, South uses something called the *model introspector* to
  11. work out what arguments fields were passed. This knows what variables the
  12. arguments are stored into on the field, and using this knowledge, can
  13. reconstruct the arguments directly.
  14. This isn't the case for custom fields [#]_, however; South has never seen them
  15. before, and it can't guess at which variables mean what arguments, or what
  16. arguments are even needed; it only knows the rules for Django's internal fields
  17. and those of common third-party apps (those which are either South-aware, or
  18. which South ships with a rules module for, such as django-tagging).
  19. .. [#] 'Custom Fields' in this context refers to any field that is not part
  20. of Django's core. GeoDjango fields are part of the core, but ones in
  21. third-party apps are 'custom'. Note also that a field is considered
  22. custom even if it inherits directly from a core field and doesn't
  23. override anything; there's no way for South to reliably tell that it does
  24. so.
  25. The Solution
  26. ------------
  27. There are two ways to tell South how to work with a custom field; if it's
  28. similar in form to other fields (in that it has a set type and a few options)
  29. you'll probably want to :ref:`extend South's introspection rules
  30. <extending-introspection>`.
  31. However, if it's particularly odd - such as a field which takes fields as
  32. arguments, or dynamically changes based on other factors - you'll probably find
  33. it easier to :ref:`add a south_field_triple method <south-field-triple>`.
  34. .. _extending-introspection:
  35. Extending Introspection
  36. =======================
  37. (Note: This is also featured in the tutorial in :ref:`tutorial-part-4`)
  38. South does the majority of its field introspection using a set of simple rules;
  39. South works out what class a field is, and then runs all rules which have been
  40. defined for either that class or a parent class of it.
  41. This way, all of the common options (such as ``null=``) are defined against the
  42. main ``Field`` class (which all fields inherit from), while specific options
  43. (such as ``max_length``) are defined on the specific fields they apply to
  44. (in this case, ``CharField``).
  45. If your custom field inherits from a core Django field, and doesn't add any new
  46. attributes, then you probably won't have to add any rules for it, as it will
  47. inherit all those from its parents.
  48. However, South first checks that it has explicitly been told a class is
  49. introspectable first; even though it will probably have rules defined (since it
  50. inherits from Field, at least), there's no way to guarantee that it knows about
  51. all of the possible rules until it has been told so.
  52. Thus, there are two stages to adding support for your custom field to South;
  53. firstly, adding some rules for the new arguments it introduces (or possibly
  54. not adding any), and secondly, adding its field name to the list of patterns
  55. South knows are safe to introspect.
  56. Rules
  57. -----
  58. Rules are what make up the core logic of the introspector; you'll need to pass
  59. South a (possibly empty) list of them. They consist of a tuple, containing:
  60. - A class or tuple of classes to which the rules apply (remember, the rules
  61. apply to the specified classes and all subclasses of them).
  62. - Rules for recovering positional arguments, in order of the arguments (you are
  63. strongly advised not to use this feature, and use keyword argument instead).
  64. - A dictionary of keyword argument rules, with the key being the name of the
  65. keyword argument, and the value being the rule.
  66. Each rule is itself a list or tuple with two elements:
  67. - The first element is the name of the attribute the value is taken from - if
  68. a field stored its max_length argument as ``self.max_length``, say, this
  69. would be ``"max_length"``.
  70. - The second element is a (possibly empty) dictionary of options describing the
  71. various different variations on handling of the value.
  72. An example (this is the South rule for the many-to-one relationships in core
  73. Django)::
  74. rules = [
  75. (
  76. (models.ForeignKey, models.OneToOneField),
  77. [],
  78. {
  79. "to": ["rel.to", {}],
  80. "to_field": ["rel.field_name", {"default_attr": "rel.to._meta.pk.name"}],
  81. "related_name": ["rel.related_name", {"default": None}],
  82. "db_index": ["db_index", {"default": True}],
  83. },
  84. )
  85. ]
  86. You'll notice that you're allowed to have dots in the attribute name; ForeignKeys,
  87. for example, store their destination model as ``self.rel.to``, so the attribute
  88. name is ``"rel.to"``.
  89. The various options are detailed below; most of them allow you to specify the
  90. default value for a parameter, so arguments can be omitted for clarity where
  91. they're not necessary.
  92. .. _is-value-keyword:
  93. The one special case is the ``is_value`` keyword; if this is present and True,
  94. then the first item in the list will be interpreted as the actual value, rather
  95. than the attribute path to it on the field. For example::
  96. "frozen_by_south": [True, {"is_value": True}],
  97. Parameters
  98. ^^^^^^^^^^
  99. - default: The default value of this field (directly as a Python object).
  100. If the value retrieved ends up being this, the keyword will be omitted
  101. from the frozen result. For example, the base Field class' "null" attribute
  102. has {'default':False}, so it's usually omitted, much like in the models.
  103. - default_attr: Similar to default, but the value given is another attribute
  104. to compare to for the default. This is used in to_field above, as this
  105. attribute's default value is the other model's pk name.
  106. - default_attr_concat: For when your default value is even more complex,
  107. default_attr_concat is a list where the first element is a format string,
  108. and the rest is a list of attribute names whose values should be formatted
  109. into the string.
  110. - ignore_if: Specifies an attribute that, if it coerces to true, causes this
  111. keyword to be omitted. Useful for ``db_index``, which has
  112. ``{'ignore_if': 'primary_key'}``, since it's always True in that case.
  113. - ignore_dynamics: If this is True, any value that is "dynamic" - such as model
  114. instances - will cause the field to be omitted instead. Used internally
  115. for the ``default`` keyword.
  116. - is_value: If present, the 'attribute name' is instead used directly as the
  117. value. See :ref:`above <is-value-keyword>` for more info.
  118. Field name patterns
  119. -------------------
  120. The second of the two steps is to tell South that your field is now safe to
  121. introspect (as you've made sure you've added all the rules it needs).
  122. Internally, South just has a long list of regular expressions it checks fields'
  123. classes against; all you need to do is provide extra arguments to this list.
  124. Example (this is in the GeoDjango module South ships with, and presumes
  125. ``rules`` is the rules triple you defined previously)::
  126. from south.modelsinspector import add_introspection_rules
  127. add_introspection_rules(rules, ["^django\.contrib\.gis"])
  128. Additionally, you can ignore some fields completely if you know they're not
  129. needed. For example, django-taggit has a manager that actually shows up as a
  130. fake field (this makes the API for using it much nicer, but confuses South to no
  131. end). The django-taggit module we ship with contains this rule to ignore it::
  132. from south.modelsinspector import add_ignored_fields
  133. add_ignored_fields(["^taggit\.managers"])
  134. Where to put the code
  135. ---------------------
  136. You need to put the call to ``add_introspection_rules`` somewhere where it will
  137. get called before South runs; it's probably a good choice to have it either in
  138. your ``models.py`` file or the module the custom fields are defined in.
  139. General Caveats
  140. ---------------
  141. If you have a custom field which adds other fields to the model dynamically
  142. (i.e. it overrides contribute_to_class and adds more fields onto the model),
  143. you'll need to write your introspection rules appropriately, to make South
  144. ignore the extra fields at migration-freezing time, or to add a flag to your
  145. field which tells it not to make the new fields again. An example can be
  146. found `here <http://bitbucket.org/carljm/django-markitup/src/tip/markitup/fields.py#cl-68>`_.
  147. .. _south-field-triple:
  148. south_field_triple
  149. ==================
  150. There are some cases where introspection of fields just isn't enough;
  151. for example, field classes which dynamically change their database column
  152. type based on options, or other odd things.
  153. Note: :ref:`Extending the introspector <extending-introspection>` is often far
  154. cleaner and easier than this method.
  155. The method to implement for these fields is ``south_field_triple()``.
  156. It should return the standard triple of::
  157. ('full.path.to.SomeFieldClass', ['positionalArg1', '"positionalArg2"'], {'kwarg':'"value"'})
  158. (this is the same format used by the :ref:`ORM Freezer <orm-freezing>`;
  159. South will just use your output verbatim).
  160. Note that the strings are ones that will be passed into eval, so for this
  161. reason, a variable reference would be ``'foo'`` while a string
  162. would be ``'"foo"'``.
  163. Example
  164. -------
  165. Here's an example of this method for django-modeltranslation's TranslationField.
  166. This custom field stores the type it's wrapping in an attribute of itself,
  167. so we'll just use that::
  168. def south_field_triple(self):
  169. "Returns a suitable description of this field for South."
  170. # We'll just introspect the _actual_ field.
  171. from south.modelsinspector import introspector
  172. field_class = self.translated_field.__class__.__module__ + "." + self.translated_field.__class__.__name__
  173. args, kwargs = introspector(self.translated_field)
  174. # That's our definition!
  175. return (field_class, args, kwargs)