123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779 |
- =================================
- How to create 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: https://www.postgresql.org/docs/current/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:
- """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: https://en.wikipedia.org/wiki/Contract_bridge
- This is 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
- ----------------
- Let's start with model fields. If you break it down, a model field 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. (Such a format is also useful
- for serialization, but as we'll see later, that is easier 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 you will need a 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 predetermined 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().__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 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 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 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
- --------------------
- The counterpoint to writing your ``__init__()`` method is writing the
- :meth:`~.Field.deconstruct` method. It's used during :doc:`model migrations
- </topics/migrations>` to tell 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 recreate 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.
- ``deconstruct()`` 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().__init__(*args, **kwargs)
- def deconstruct(self):
- name, path, args, kwargs = super().deconstruct()
- del kwargs["max_length"]
- return name, path, args, kwargs
- If you add a new keyword argument, you need to write code in ``deconstruct()``
- that puts its value into ``kwargs`` yourself. You should also omit the value
- from ``kwargs`` when it isn't necessary to reconstruct the state of the field,
- such as when the default value is being used::
- 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().__init__(*args, **kwargs)
- def deconstruct(self):
- name, path, args, kwargs = super().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.
- 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 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)
- .. _custom-field-non_db_attrs:
- Field attributes not affecting database column definition
- ---------------------------------------------------------
- You can override ``Field.non_db_attrs`` to customize attributes of a field that
- don't affect a column definition. It's used during model migrations to detect
- no-op ``AlterField`` operations.
- For example::
- class CommaSepField(models.Field):
- @property
- def non_db_attrs(self):
- return super().non_db_attrs + ("separator",)
- Changing a custom field's base class
- ------------------------------------
- You can't change the base class of a custom field because Django won't detect
- the change and make a migration for it. For example, if you start with::
- class CustomCharField(models.CharField): ...
- and then decide that you want to use ``TextField`` instead, you can't change
- the subclass like this::
- class CustomCharField(models.TextField): ...
- Instead, you must create a new custom field class and update your models to
- reference it::
- class CustomCharField(models.CharField): ...
- class CustomTextField(models.TextField): ...
- As discussed in :ref:`removing fields <migrations-removing-model-fields>`, you
- must retain the original ``CustomCharField`` class as long as you have
- migrations that reference it.
- 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 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, 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``. You can handle this in a :meth:`~Field.db_type` method by
- checking the ``connection.vendor`` attribute. Current built-in vendor names
- are: ``sqlite``, ``postgresql``, ``mysql``, and ``oracle``.
- For example::
- class MyDateField(models.Field):
- def db_type(self, connection):
- if connection.vendor == "mysql":
- return "datetime"
- else:
- return "timestamp"
- The :meth:`~Field.db_type` and :meth:`~Field.rel_db_type` methods are called by
- Django when the framework constructs the ``CREATE TABLE`` statements for your
- application -- that is, when you first create your tables. The methods are 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.
- 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, 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().__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, but this gives you a way to tell Django to get out of
- the way.
- The :meth:`~Field.rel_db_type` method is called by fields such as ``ForeignKey``
- and ``OneToOneField`` that point to another field to determine their database
- column data types. For example, if you have an ``UnsignedAutoField``, you also
- need the foreign keys that point to that field to use the same data type::
- # MySQL unsigned integer (range 0 to 4294967295).
- class UnsignedAutoField(models.AutoField):
- def db_type(self, connection):
- return "integer UNSIGNED AUTO_INCREMENT"
- def rel_db_type(self, connection):
- return "integer UNSIGNED"
- .. _converting-values-to-python-objects:
- Converting values to Python objects
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 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
- from django.utils.translation import gettext_lazy as _
- 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, expression, 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.from_db_value` 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().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.
- .. _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.
- If you wish to exclude the field from the :class:`~django.forms.ModelForm`, you
- can override the :meth:`~Field.formfield` method to return ``None``.
- Continuing our ongoing example, we can write the :meth:`~Field.formfield` method
- as::
- class HandField(models.Field):
- # ...
- def formfield(self, **kwargs):
- # Exclude the field from the ModelForm when some condition is met.
- some_condition = kwargs.get("some_condition", False)
- if some_condition:
- return None
- # Set up some defaults while letting the caller override them.
- defaults = {"form_class": MyFormField}
- defaults.update(kwargs)
- return super().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>.base.DatabaseWrapper.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`. Using :meth:`~Field.value_from_object` is the
- best way to get the field's value prior to serialization. For example, since
- ``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.value_from_object(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:
- #. Look at the existing Django fields (in
- :source:`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.
- #. Put a ``__str__()`` 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
- ``str()`` on the value. (In our examples in this document, ``value`` would
- be a ``Hand`` instance, not a ``HandField``). So if your ``__str__()``
- method 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, 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.
- #. The source for Django's own ``ImageField`` (in
- :source:`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.
- #. 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.
|