123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785 |
- ===========================
- Writing custom model fields
- ===========================
- .. currentmodule:: django.db.models
- Introduction
- ============
- The :doc:`model reference </topics/db/models>` documentation explains how to use
- Django's standard field classes -- :class:`~django.db.models.CharField`,
- :class:`~django.db.models.DateField`, etc. For many purposes, those classes are
- all you'll need. Sometimes, though, the Django version won't meet your precise
- requirements, or you'll want to use a field that is entirely different from
- those shipped with Django.
- Django's built-in field types don't cover every possible database column type --
- only the common types, such as ``VARCHAR`` and ``INTEGER``. For more obscure
- column types, such as geographic polygons or even user-created types such as
- `PostgreSQL custom types`_, you can define your own Django ``Field`` subclasses.
- .. _PostgreSQL custom types: http://www.postgresql.org/docs/current/interactive/sql-createtype.html
- Alternatively, you may have a complex Python object that can somehow be
- serialized to fit into a standard database column type. This is another case
- where a ``Field`` subclass will help you use your object with your models.
- Our example object
- ------------------
- Creating custom fields requires a bit of attention to detail. To make things
- easier to follow, we'll use a consistent example throughout this document:
- wrapping a Python object representing the deal of cards in a hand of Bridge_.
- Don't worry, you don't have to know how to play Bridge to follow this example.
- You only need to know that 52 cards are dealt out equally to four players, who
- are traditionally called *north*, *east*, *south* and *west*. Our class looks
- something like this::
- class Hand(object):
- """A hand of cards (bridge style)"""
- def __init__(self, north, east, south, west):
- # Input parameters are lists of cards ('Ah', '9s', etc)
- self.north = north
- self.east = east
- self.south = south
- self.west = west
- # ... (other possibly useful methods omitted) ...
- .. _Bridge: http://en.wikipedia.org/wiki/Contract_bridge
- This is just an ordinary Python class, with nothing Django-specific about it.
- We'd like to be able to do things like this in our models (we assume the
- ``hand`` attribute on the model is an instance of ``Hand``)::
- example = MyModel.objects.get(pk=1)
- print(example.hand.north)
- new_hand = Hand(north, east, south, west)
- example.hand = new_hand
- example.save()
- We assign to and retrieve from the ``hand`` attribute in our model just like
- any other Python class. The trick is to tell Django how to handle saving and
- loading such an object.
- In order to use the ``Hand`` class in our models, we **do not** have to change
- this class at all. This is ideal, because it means you can easily write
- model support for existing classes where you cannot change the source code.
- .. note::
- You might only be wanting to take advantage of custom database column
- types and deal with the data as standard Python types in your models;
- strings, or floats, for example. This case is similar to our ``Hand``
- example and we'll note any differences as we go along.
- Background theory
- =================
- Database storage
- ----------------
- The simplest way to think of a model field is that it provides a way to take a
- normal Python object -- string, boolean, ``datetime``, or something more
- complex like ``Hand`` -- and convert it to and from a format that is useful
- when dealing with the database (and serialization, but, as we'll see later,
- that falls out fairly naturally once you have the database side under control).
- Fields in a model must somehow be converted to fit into an existing database
- column type. Different databases provide different sets of valid column types,
- but the rule is still the same: those are the only types you have to work
- with. Anything you want to store in the database must fit into one of
- those types.
- Normally, you're either writing a Django field to match a particular database
- column type, or there's a fairly straightforward way to convert your data to,
- say, a string.
- For our ``Hand`` example, we could convert the card data to a string of 104
- characters by concatenating all the cards together in a pre-determined order --
- say, all the *north* cards first, then the *east*, *south* and *west* cards. So
- ``Hand`` objects can be saved to text or character columns in the database.
- What does a field class do?
- ---------------------------
- All of Django's fields (and when we say *fields* in this document, we always
- mean model fields and not :doc:`form fields </ref/forms/fields>`) are subclasses
- of :class:`django.db.models.Field`. Most of the information that Django records
- about a field is common to all fields -- name, help text, uniqueness and so
- forth. Storing all that information is handled by ``Field``. We'll get into the
- precise details of what ``Field`` can do later on; for now, suffice it to say
- that everything descends from ``Field`` and then customizes key pieces of the
- class behavior.
- It's important to realize that a Django field class is not what is stored in
- your model attributes. The model attributes contain normal Python objects. The
- field classes you define in a model are actually stored in the ``Meta`` class
- when the model class is created (the precise details of how this is done are
- unimportant here). This is because the field classes aren't necessary when
- you're just creating and modifying attributes. Instead, they provide the
- machinery for converting between the attribute value and what is stored in the
- database or sent to the :doc:`serializer </topics/serialization>`.
- Keep this in mind when creating your own custom fields. The Django ``Field``
- subclass you write provides the machinery for converting between your Python
- instances and the database/serializer values in various ways (there are
- differences between storing a value and using a value for lookups, for
- example). If this sounds a bit tricky, don't worry -- it will become clearer in
- the examples below. Just remember that you will often end up creating two
- classes when you want a custom field:
- * The first class is the Python object that your users will manipulate.
- They will assign it to the model attribute, they will read from it for
- displaying purposes, things like that. This is the ``Hand`` class in our
- example.
- * The second class is the ``Field`` subclass. This is the class that knows
- how to convert your first class back and forth between its permanent
- storage form and the Python form.
- Writing a field subclass
- ========================
- When planning your :class:`~django.db.models.Field` subclass, first give some
- thought to which existing :class:`~django.db.models.Field` class your new field
- is most similar to. Can you subclass an existing Django field and save yourself
- some work? If not, you should subclass the :class:`~django.db.models.Field`
- class, from which everything is descended.
- Initializing your new field is a matter of separating out any arguments that are
- specific to your case from the common arguments and passing the latter to the
- ``__init__()`` method of :class:`~django.db.models.Field` (or your parent
- class).
- In our example, we'll call our field ``HandField``. (It's a good idea to call
- your :class:`~django.db.models.Field` subclass ``<Something>Field``, so it's
- easily identifiable as a :class:`~django.db.models.Field` subclass.) It doesn't
- behave like any existing field, so we'll subclass directly from
- :class:`~django.db.models.Field`::
- from django.db import models
- class HandField(models.Field):
- description = "A hand of cards (bridge style)"
- def __init__(self, *args, **kwargs):
- kwargs['max_length'] = 104
- super(HandField, self).__init__(*args, **kwargs)
- Our ``HandField`` accepts most of the standard field options (see the list
- below), but we ensure it has a fixed length, since it only needs to hold 52
- card values plus their suits; 104 characters in total.
- .. note::
- Many of Django's model fields accept options that they don't do anything
- with. For example, you can pass both
- :attr:`~django.db.models.Field.editable` and
- :attr:`~django.db.models.DateField.auto_now` to a
- :class:`django.db.models.DateField` and it will simply ignore the
- :attr:`~django.db.models.Field.editable` parameter
- (:attr:`~django.db.models.DateField.auto_now` being set implies
- ``editable=False``). No error is raised in this case.
- This behavior simplifies the field classes, because they don't need to
- check for options that aren't necessary. They just pass all the options to
- the parent class and then don't use them later on. It's up to you whether
- you want your fields to be more strict about the options they select, or to
- use the simpler, more permissive behavior of the current fields.
- The ``Field.__init__()`` method takes the following parameters:
- * :attr:`~django.db.models.Field.verbose_name`
- * ``name``
- * :attr:`~django.db.models.Field.primary_key`
- * :attr:`~django.db.models.CharField.max_length`
- * :attr:`~django.db.models.Field.unique`
- * :attr:`~django.db.models.Field.blank`
- * :attr:`~django.db.models.Field.null`
- * :attr:`~django.db.models.Field.db_index`
- * ``rel``: Used for related fields (like :class:`ForeignKey`). For advanced
- use only.
- * :attr:`~django.db.models.Field.default`
- * :attr:`~django.db.models.Field.editable`
- * ``serialize``: If ``False``, the field will not be serialized when the model
- is passed to Django's :doc:`serializers </topics/serialization>`. Defaults to
- ``True``.
- * :attr:`~django.db.models.Field.unique_for_date`
- * :attr:`~django.db.models.Field.unique_for_month`
- * :attr:`~django.db.models.Field.unique_for_year`
- * :attr:`~django.db.models.Field.choices`
- * :attr:`~django.db.models.Field.help_text`
- * :attr:`~django.db.models.Field.db_column`
- * :attr:`~django.db.models.Field.db_tablespace`: Only for index creation, if the
- backend supports :doc:`tablespaces </topics/db/tablespaces>`. You can usually
- ignore this option.
- * :attr:`~django.db.models.Field.auto_created`: ``True`` if the field was
- automatically created, as for the :class:`~django.db.models.OneToOneField`
- used by model inheritance. For advanced use only.
- All of the options without an explanation in the above list have the same
- meaning they do for normal Django fields. See the :doc:`field documentation
- </ref/models/fields>` for examples and details.
- .. _custom-field-deconstruct-method:
- Field deconstruction
- --------------------
- .. versionadded:: 1.7
- ``deconstruct()`` is part of the migrations framework in Django 1.7 and
- above. If you have custom fields from previous versions they will
- need this method added before you can use them with migrations.
- The counterpoint to writing your ``__init__()`` method is writing the
- ``deconstruct()`` method. This method tells Django how to take an instance
- of your new field and reduce it to a serialized form - in particular, what
- arguments to pass to ``__init__()`` to re-create it.
- If you haven't added any extra options on top of the field you inherited from,
- then there's no need to write a new ``deconstruct()`` method. If, however,
- you're, changing the arguments passed in ``__init__()`` (like we are in
- ``HandField``), you'll need to supplement the values being passed.
- The contract of ``deconstruct()`` is simple; it returns a tuple of four items:
- the field's attribute name, the full import path of the field class, the
- positional arguments (as a list), and the keyword arguments (as a dict). Note
- this is different from the ``deconstruct()`` method :ref:`for custom classes
- <custom-deconstruct-method>` which returns a tuple of three things.
- As a custom field author, you don't need to care about the first two values;
- the base ``Field`` class has all the code to work out the field's attribute
- name and import path. You do, however, have to care about the positional
- and keyword arguments, as these are likely the things you are changing.
- For example, in our ``HandField`` class we're always forcibly setting
- max_length in ``__init__()``. The ``deconstruct()`` method on the base ``Field``
- class will see this and try to return it in the keyword arguments; thus,
- we can drop it from the keyword arguments for readability::
- from django.db import models
- class HandField(models.Field):
- def __init__(self, *args, **kwargs):
- kwargs['max_length'] = 104
- super(HandField, self).__init__(*args, **kwargs)
- def deconstruct(self):
- name, path, args, kwargs = super(HandField, self).deconstruct()
- del kwargs["max_length"]
- return name, path, args, kwargs
- If you add a new keyword argument, you need to write code to put its value
- into ``kwargs`` yourself::
- from django.db import models
- class CommaSepField(models.Field):
- "Implements comma-separated storage of lists"
- def __init__(self, separator=",", *args, **kwargs):
- self.separator = separator
- super(CommaSepField, self).__init__(*args, **kwargs)
- def deconstruct(self):
- name, path, args, kwargs = super(CommaSepField, self).deconstruct()
- # Only include kwarg if it's not the default
- if self.separator != ",":
- kwargs['separator'] = self.separator
- return name, path, args, kwargs
- More complex examples are beyond the scope of this document, but remember -
- for any configuration of your Field instance, ``deconstruct()`` must return
- arguments that you can pass to ``__init__`` to reconstruct that state.
- Pay extra attention if you set new default values for arguments in the
- ``Field`` superclass; you want to make sure they're always included, rather
- than disappearing if they take on the old default value.
- In addition, try to avoid returning values as positional arguments; where
- possible, return values as keyword arguments for maximum future compatibility.
- Of course, if you change the names of things more often than their position
- in the constructor's argument list, you might prefer positional, but bear in
- mind that people will be reconstructing your field from the serialized version
- for quite a while (possibly years), depending how long your migrations live for.
- You can see the results of deconstruction by looking in migrations that include
- the field, and you can test deconstruction in unit tests by just deconstructing
- and reconstructing the field::
- name, path, args, kwargs = my_field_instance.deconstruct()
- new_instance = MyField(*args, **kwargs)
- self.assertEqual(my_field_instance.some_attribute, new_instance.some_attribute)
- Documenting your custom field
- -----------------------------
- As always, you should document your field type, so users will know what it is.
- In addition to providing a docstring for it, which is useful for developers,
- you can also allow users of the admin app to see a short description of the
- field type via the :doc:`django.contrib.admindocs
- </ref/contrib/admin/admindocs>` application. To do this simply provide
- descriptive text in a :attr:`~Field.description` class attribute of your custom
- field. In the above example, the description displayed by the ``admindocs``
- application for a ``HandField`` will be 'A hand of cards (bridge style)'.
- In the :mod:`django.contrib.admindocs` display, the field description is
- interpolated with ``field.__dict__`` which allows the description to
- incorporate arguments of the field. For example, the description for
- :class:`~django.db.models.CharField` is::
- description = _("String (up to %(max_length)s)")
- Useful methods
- --------------
- Once you've created your :class:`~django.db.models.Field` subclass and set up
- the ``__metaclass__``, you might consider overriding a few standard methods,
- depending on your field's behavior. The list of methods below is in
- approximately decreasing order of importance, so start from the top.
- .. _custom-database-types:
- Custom database types
- ~~~~~~~~~~~~~~~~~~~~~
- Say you've created a PostgreSQL custom type called ``mytype``. You can
- subclass ``Field`` and implement the :meth:`~Field.db_type` method, like so::
- from django.db import models
- class MytypeField(models.Field):
- def db_type(self, connection):
- return 'mytype'
- Once you have ``MytypeField``, you can use it in any model, just like any other
- ``Field`` type::
- class Person(models.Model):
- name = models.CharField(max_length=80)
- something_else = MytypeField()
- If you aim to build a database-agnostic application, you should account for
- differences in database column types. For example, the date/time column type
- in PostgreSQL is called ``timestamp``, while the same column in MySQL is called
- ``datetime``. The simplest way to handle this in a :meth:`~Field.db_type`
- method is to check the ``connection.settings_dict['ENGINE']`` attribute.
- For example::
- class MyDateField(models.Field):
- def db_type(self, connection):
- if connection.settings_dict['ENGINE'] == 'django.db.backends.mysql':
- return 'datetime'
- else:
- return 'timestamp'
- The :meth:`~Field.db_type` method is called by Django when the framework
- constructs the ``CREATE TABLE`` statements for your application -- that is,
- when you first create your tables. It is also called when constructing a
- ``WHERE`` clause that includes the model field -- that is, when you retrieve data
- using QuerySet methods like ``get()``, ``filter()``, and ``exclude()`` and have
- the model field as an argument. It's not called at any other time, so it can afford to
- execute slightly complex code, such as the ``connection.settings_dict`` check in
- the above example.
- Some database column types accept parameters, such as ``CHAR(25)``, where the
- parameter ``25`` represents the maximum column length. In cases like these,
- it's more flexible if the parameter is specified in the model rather than being
- hard-coded in the ``db_type()`` method. For example, it wouldn't make much
- sense to have a ``CharMaxlength25Field``, shown here::
- # This is a silly example of hard-coded parameters.
- class CharMaxlength25Field(models.Field):
- def db_type(self, connection):
- return 'char(25)'
- # In the model:
- class MyModel(models.Model):
- # ...
- my_field = CharMaxlength25Field()
- The better way of doing this would be to make the parameter specifiable at run
- time -- i.e., when the class is instantiated. To do that, just implement
- ``Field.__init__()``, like so::
- # This is a much more flexible example.
- class BetterCharField(models.Field):
- def __init__(self, max_length, *args, **kwargs):
- self.max_length = max_length
- super(BetterCharField, self).__init__(*args, **kwargs)
- def db_type(self, connection):
- return 'char(%s)' % self.max_length
- # In the model:
- class MyModel(models.Model):
- # ...
- my_field = BetterCharField(25)
- Finally, if your column requires truly complex SQL setup, return ``None`` from
- :meth:`.db_type`. This will cause Django's SQL creation code to skip
- over this field. You are then responsible for creating the column in the right
- table in some other way, of course, but this gives you a way to tell Django to
- get out of the way.
- .. _converting-values-to-python-objects:
- Converting values to Python objects
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. versionchanged:: 1.8
- Historically, Django provided a metaclass called ``SubfieldBase`` which
- always called :meth:`~Field.to_python` on assignment. This did not play
- nicely with custom database transformations, aggregation, or values
- queries, so it has been replaced with :meth:`~Field.from_db_value`.
- If your custom :class:`~Field` class deals with data structures that are more
- complex than strings, dates, integers, or floats, then you may need to override
- :meth:`~Field.from_db_value` and :meth:`~Field.to_python`.
- If present for the field subclass, ``from_db_value()`` will be called in all
- circumstances when the data is loaded from the database, including in
- aggregates and :meth:`~django.db.models.query.QuerySet.values` calls.
- ``to_python()`` is called by deserialization and during the
- :meth:`~django.db.models.Model.clean` method used from forms.
- As a general rule, ``to_python()`` should deal gracefully with any of the
- following arguments:
- * An instance of the correct type (e.g., ``Hand`` in our ongoing example).
- * A string
- * ``None`` (if the field allows ``null=True``)
- In our ``HandField`` class, we're storing the data as a VARCHAR field in the
- database, so we need to be able to process strings and ``None`` in the
- ``from_db_value()``. In ``to_python()``, we need to also handle ``Hand``
- instances::
- import re
- from django.core.exceptions import ValidationError
- from django.db import models
- def parse_hand(hand_string):
- """Takes a string of cards and splits into a full hand."""
- p1 = re.compile('.{26}')
- p2 = re.compile('..')
- args = [p2.findall(x) for x in p1.findall(hand_string)]
- if len(args) != 4:
- raise ValidationError("Invalid input for a Hand instance")
- return Hand(*args)
- class HandField(models.Field):
- # ...
- def from_db_value(self, value, connection):
- if value is None:
- return value
- return parse_hand(value)
- def to_python(self, value):
- if isinstance(value, Hand):
- return value
- if value is None:
- return value
- return parse_hand(value)
- Notice that we always return a ``Hand`` instance from these methods. That's the
- Python object type we want to store in the model's attribute.
- For ``to_python()``, if anything goes wrong during value conversion, you should
- raise a :exc:`~django.core.exceptions.ValidationError` exception.
- .. _converting-python-objects-to-query-values:
- Converting Python objects to query values
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Since using a database requires conversion in both ways, if you override
- :meth:`~Field.to_python` you also have to override :meth:`~Field.get_prep_value`
- to convert Python objects back to query values.
- For example::
- class HandField(models.Field):
- # ...
- def get_prep_value(self, value):
- return ''.join([''.join(l) for l in (value.north,
- value.east, value.south, value.west)])
- .. warning::
- If your custom field uses the ``CHAR``, ``VARCHAR`` or ``TEXT``
- types for MySQL, you must make sure that :meth:`.get_prep_value`
- always returns a string type. MySQL performs flexible and unexpected
- matching when a query is performed on these types and the provided
- value is an integer, which can cause queries to include unexpected
- objects in their results. This problem cannot occur if you always
- return a string type from :meth:`.get_prep_value`.
- .. _converting-query-values-to-database-values:
- Converting query values to database values
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Some data types (for example, dates) need to be in a specific format
- before they can be used by a database backend.
- :meth:`~Field.get_db_prep_value` is the method where those conversions should
- be made. The specific connection that will be used for the query is
- passed as the ``connection`` parameter. This allows you to use
- backend-specific conversion logic if it is required.
- For example, Django uses the following method for its
- :class:`BinaryField`::
- def get_db_prep_value(self, value, connection, prepared=False):
- value = super(BinaryField, self).get_db_prep_value(value, connection, prepared)
- if value is not None:
- return connection.Database.Binary(value)
- return value
- In case your custom field needs a special conversion when being saved that is
- not the same as the conversion used for normal query parameters, you can
- override :meth:`~Field.get_db_prep_save`.
- .. _preprocessing-values-before-saving:
- Preprocessing values before saving
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- If you want to preprocess the value just before saving, you can use
- :meth:`~Field.pre_save`. For example, Django's
- :class:`~django.db.models.DateTimeField` uses this method to set the attribute
- correctly in the case of :attr:`~django.db.models.DateField.auto_now` or
- :attr:`~django.db.models.DateField.auto_now_add`.
- If you do override this method, you must return the value of the attribute at
- the end. You should also update the model's attribute if you make any changes
- to the value so that code holding references to the model will always see the
- correct value.
- .. _preparing-values-for-use-in-database-lookups:
- Preparing values for use in database lookups
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- As with value conversions, preparing a value for database lookups is a
- two phase process.
- :meth:`.get_prep_lookup` performs the first phase of lookup preparation:
- type conversion and data validation.
- Prepares the ``value`` for passing to the database when used in a lookup (a
- ``WHERE`` constraint in SQL). The ``lookup_type`` parameter will be one of the
- valid Django filter lookups: ``exact``, ``iexact``, ``contains``, ``icontains``,
- ``gt``, ``gte``, ``lt``, ``lte``, ``in``, ``startswith``, ``istartswith``,
- ``endswith``, ``iendswith``, ``range``, ``year``, ``month``, ``day``,
- ``isnull``, ``search``, ``regex``, and ``iregex``.
- .. versionadded:: 1.7
- If you are using :doc:`Custom lookups </howto/custom-lookups>` the
- ``lookup_type`` can be any ``lookup_name`` used by the project's custom
- lookups.
- Your method must be prepared to handle all of these ``lookup_type`` values and
- should raise either a ``ValueError`` if the ``value`` is of the wrong sort (a
- list when you were expecting an object, for example) or a ``TypeError`` if
- your field does not support that type of lookup. For many fields, you can get
- by with handling the lookup types that need special handling for your field
- and pass the rest to the :meth:`~Field.get_db_prep_lookup` method of the parent
- class.
- If you needed to implement :meth:`.get_db_prep_save`, you will usually need to
- implement :meth:`.get_prep_lookup`. If you don't, :meth:`.get_prep_value` will
- be called by the default implementation, to manage ``exact``, ``gt``, ``gte``,
- ``lt``, ``lte``, ``in`` and ``range`` lookups.
- You may also want to implement this method to limit the lookup types that could
- be used with your custom field type.
- Note that, for ``"range"`` and ``"in"`` lookups, ``get_prep_lookup`` will receive
- a list of objects (presumably of the right type) and will need to convert them
- to a list of things of the right type for passing to the database. Most of the
- time, you can reuse ``get_prep_value()``, or at least factor out some common
- pieces.
- For example, the following code implements ``get_prep_lookup`` to limit the
- accepted lookup types to ``exact`` and ``in``::
- class HandField(models.Field):
- # ...
- def get_prep_lookup(self, lookup_type, value):
- # We only handle 'exact' and 'in'. All others are errors.
- if lookup_type == 'exact':
- return self.get_prep_value(value)
- elif lookup_type == 'in':
- return [self.get_prep_value(v) for v in value]
- else:
- raise TypeError('Lookup type %r not supported.' % lookup_type)
- For performing database-specific data conversions required by a lookup,
- you can override :meth:`~Field.get_db_prep_lookup`.
- .. _specifying-form-field-for-model-field:
- Specifying the form field for a model field
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- To customize the form field used by :class:`~django.forms.ModelForm`, you can
- override :meth:`~Field.formfield`.
- The form field class can be specified via the ``form_class`` and
- ``choices_form_class`` arguments; the latter is used if the field has choices
- specified, the former otherwise. If these arguments are not provided,
- :class:`~django.forms.CharField` or :class:`~django.forms.TypedChoiceField`
- will be used.
- All of the ``kwargs`` dictionary is passed directly to the form field's
- ``__init__()`` method. Normally, all you need to do is set up a good default
- for the ``form_class`` (and maybe ``choices_form_class``) argument and then
- delegate further handling to the parent class. This might require you to write
- a custom form field (and even a form widget). See the :doc:`forms documentation
- </topics/forms/index>` for information about this.
- Continuing our ongoing example, we can write the :meth:`~Field.formfield` method
- as::
- class HandField(models.Field):
- # ...
- def formfield(self, **kwargs):
- # This is a fairly standard way to set up some defaults
- # while letting the caller override them.
- defaults = {'form_class': MyFormField}
- defaults.update(kwargs)
- return super(HandField, self).formfield(**defaults)
- This assumes we've imported a ``MyFormField`` field class (which has its own
- default widget). This document doesn't cover the details of writing custom form
- fields.
- .. _helper functions: ../forms/#generating-forms-for-models
- .. _forms documentation: ../forms/
- .. _emulating-built-in-field-types:
- Emulating built-in field types
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- If you have created a :meth:`.db_type` method, you don't need to worry about
- :meth:`.get_internal_type` -- it won't be used much. Sometimes, though, your
- database storage is similar in type to some other field, so you can use that
- other field's logic to create the right column.
- For example::
- class HandField(models.Field):
- # ...
- def get_internal_type(self):
- return 'CharField'
- No matter which database backend we are using, this will mean that
- :djadmin:`migrate` and other SQL commands create the right column type for
- storing a string.
- If :meth:`.get_internal_type` returns a string that is not known to Django for
- the database backend you are using -- that is, it doesn't appear in
- ``django.db.backends.<db_name>.creation.data_types`` -- the string will still be
- used by the serializer, but the default :meth:`~Field.db_type` method will
- return ``None``. See the documentation of :meth:`~Field.db_type` for reasons why
- this might be useful. Putting a descriptive string in as the type of the field
- for the serializer is a useful idea if you're ever going to be using the
- serializer output in some other place, outside of Django.
- .. _converting-model-field-to-serialization:
- Converting field data for serialization
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- To customize how the values are serialized by a serializer, you can override
- :meth:`~Field.value_to_string`. Calling ``Field._get_val_from_obj(obj)`` is the
- best way to get the value serialized. For example, since our ``HandField`` uses
- strings for its data storage anyway, we can reuse some existing conversion code::
- class HandField(models.Field):
- # ...
- def value_to_string(self, obj):
- value = self._get_val_from_obj(obj)
- return self.get_prep_value(value)
- Some general advice
- --------------------
- Writing a custom field can be a tricky process, particularly if you're doing
- complex conversions between your Python types and your database and
- serialization formats. Here are a couple of tips to make things go more
- smoothly:
- 1. Look at the existing Django fields (in
- :file:`django/db/models/fields/__init__.py`) for inspiration. Try to find
- a field that's similar to what you want and extend it a little bit,
- instead of creating an entirely new field from scratch.
- 2. Put a ``__str__()`` (``__unicode__()`` on Python 2) method on the class you're
- wrapping up as a field. There are a lot of places where the default
- behavior of the field code is to call
- :func:`~django.utils.encoding.force_text` on the value. (In our
- examples in this document, ``value`` would be a ``Hand`` instance, not a
- ``HandField``). So if your ``__str__()`` method (``__unicode__()`` on
- Python 2) automatically converts to the string form of your Python object,
- you can save yourself a lot of work.
- Writing a ``FileField`` subclass
- ================================
- In addition to the above methods, fields that deal with files have a few other
- special requirements which must be taken into account. The majority of the
- mechanics provided by ``FileField``, such as controlling database storage and
- retrieval, can remain unchanged, leaving subclasses to deal with the challenge
- of supporting a particular type of file.
- Django provides a ``File`` class, which is used as a proxy to the file's
- contents and operations. This can be subclassed to customize how the file is
- accessed, and what methods are available. It lives at
- ``django.db.models.fields.files``, and its default behavior is explained in the
- :doc:`file documentation </ref/files/file>`.
- Once a subclass of ``File`` is created, the new ``FileField`` subclass must be
- told to use it. To do so, simply assign the new ``File`` subclass to the special
- ``attr_class`` attribute of the ``FileField`` subclass.
- A few suggestions
- ------------------
- In addition to the above details, there are a few guidelines which can greatly
- improve the efficiency and readability of the field's code.
- 1. The source for Django's own ``ImageField`` (in
- ``django/db/models/fields/files.py``) is a great example of how to
- subclass ``FileField`` to support a particular type of file, as it
- incorporates all of the techniques described above.
- 2. Cache file attributes wherever possible. Since files may be stored in
- remote storage systems, retrieving them may cost extra time, or even
- money, that isn't always necessary. Once a file is retrieved to obtain
- some data about its content, cache as much of that data as possible to
- reduce the number of times the file must be retrieved on subsequent
- calls for that information.
|