summaryrefslogtreecommitdiff
path: root/docs/ref
diff options
context:
space:
mode:
authorMarc Tamlyn <marc.tamlyn@gmail.com>2015-01-10 16:14:20 +0000
committerMarc Tamlyn <marc.tamlyn@gmail.com>2015-01-10 16:18:19 +0000
commit48ad288679a0cb2e2cfb17f128903e6c5b1c4870 (patch)
tree75bacb810dbe071058b5c5cf7d8dcb8e20f3f500 /docs/ref
parent916e38802f151b34aaca487dc7e928946e81be73 (diff)
Fixed #24001 -- Added range fields for PostgreSQL.
Added support for PostgreSQL range types to contrib.postgres. - 5 new model fields - 4 new form fields - New validators - Uses psycopg2's range type implementation in python
Diffstat (limited to 'docs/ref')
-rw-r--r--docs/ref/contrib/postgres/fields.txt263
-rw-r--r--docs/ref/contrib/postgres/forms.txt45
-rw-r--r--docs/ref/contrib/postgres/validators.txt13
3 files changed, 321 insertions, 0 deletions
diff --git a/docs/ref/contrib/postgres/fields.txt b/docs/ref/contrib/postgres/fields.txt
index 1cdd21a59b..f4fae93da0 100644
--- a/docs/ref/contrib/postgres/fields.txt
+++ b/docs/ref/contrib/postgres/fields.txt
@@ -402,3 +402,266 @@ using in conjunction with lookups on
>>> Dog.objects.filter(data__values__contains=['collie'])
[<Dog: Meg>]
+
+.. _range-fields:
+
+Range Fields
+------------
+
+There are five range field types, corresponding to the built-in range types in
+PostgreSQL. These fields are used to store a range of values; for example the
+start and end timestamps of an event, or the range of ages an activity is
+suitable for.
+
+All of the range fields translate to :ref:`psycopg2 Range objects
+<psycopg2:adapt-range>` in python, but also accept tuples as input if no bounds
+information is necessary. The default is lower bound included, upper bound
+excluded.
+
+IntegerRangeField
+^^^^^^^^^^^^^^^^^
+
+.. class:: IntegerRangeField(**options)
+
+ Stores a range of integers. Based on an
+ :class:`~django.db.models.IntegerField`. Represented by an ``int4range`` in
+ the database and a :class:`~psycopg2:psycopg2.extras.NumericRange` in
+ Python.
+
+BigIntegerRangeField
+^^^^^^^^^^^^^^^^^^^^
+
+.. class:: BigIntegerRangeField(**options)
+
+ Stores a range of large integers. Based on a
+ :class:`~django.db.models.BigIntegerField`. Represented by an ``int8range``
+ in the database and a :class:`~psycopg2:psycopg2.extras.NumericRange` in
+ Python.
+
+FloatRangeField
+^^^^^^^^^^^^^^^
+
+.. class:: FloatRangeField(**options)
+
+ Stores a range of floating point values. Based on a
+ :class:`~django.db.models.FloatField`. Represented by a ``numrange`` in the
+ database and a :class:`~psycopg2:psycopg2.extras.NumericRange` in Python.
+
+DateTimeRangeField
+^^^^^^^^^^^^^^^^^^
+
+.. class:: DateTimeRangeField(**options)
+
+ Stores a range of timestamps. Based on a
+ :class:`~django.db.models.DateTimeField`. Represented by a ``tztsrange`` in
+ the database and a :class:`~psycopg2:psycopg2.extras.DateTimeTZRange` in
+ Python.
+
+DateRangeField
+^^^^^^^^^^^^^^
+
+.. class:: DateRangeField(**options)
+
+ Stores a range of dates. Based on a
+ :class:`~django.db.models.DateField`. Represented by a ``daterange`` in the
+ database and a :class:`~psycopg2:psycopg2.extras.DateRange` in Python.
+
+Querying Range Fields
+^^^^^^^^^^^^^^^^^^^^^
+
+There are a number of custom lookups and transforms for range fields. They are
+available on all the above fields, but we will use the following example
+model::
+
+ from django.contrib.postgres.fields import IntegerRangeField
+ from django.db import models
+
+ class Event(models.Model):
+ name = models.CharField(max_length=200)
+ ages = IntegerRangeField()
+
+ def __str__(self): # __unicode__ on Python 2
+ return self.name
+
+We will also use the following example objects::
+
+ >>> Event.objects.create(name='Soft play', ages=(0, 10))
+ >>> Event.objects.create(name='Pub trip', ages=(21, None))
+
+and ``NumericRange``:
+
+ >>> from psycopg2.extras import NumericRange
+
+Containment functions
+~~~~~~~~~~~~~~~~~~~~~
+
+As with other PostgreSQL fields, there are three standard containment
+operators: ``contains``, ``contained_by`` and ``overlap``, using the SQL
+operators ``@>``, ``<@``, and ``&&`` respectively.
+
+.. fieldlookup:: rangefield.contains
+
+contains
+''''''''
+
+ >>> Event.objects.filter(ages__contains=NumericRange(4, 5))
+ [<Event: Soft play>]
+
+.. fieldlookup:: rangefield.contained_by
+
+contained_by
+''''''''''''
+
+ >>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
+ [<Event: Soft play>]
+
+.. fieldlookup:: rangefield.overlap
+
+overlap
+'''''''
+
+ >>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
+ [<Event: Soft play>]
+
+Comparison functions
+~~~~~~~~~~~~~~~~~~~~
+
+Range fields support the standard lookups: :lookup:`lt`, :lookup:`gt`,
+:lookup:`lte` and :lookup:`gte`. These are not particularly helpful - they
+compare the lower bounds first and then the upper bounds only if necessary.
+This is also the strategy used to order by a range field. It is better to use
+the specific range comparison operators.
+
+.. fieldlookup:: rangefield.fully_lt
+
+fully_lt
+''''''''
+
+The returned ranges are strictly less than the passed range. In other words,
+all the points in the returned range are less than all those in the passed
+range.
+
+ >>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
+ [<Event: Soft play>]
+
+.. fieldlookup:: rangefield.fully_gt
+
+fully_gt
+''''''''
+
+The returned ranges are strictly greater than the passed range. In other words,
+the all the points in the returned range are greater than all those in the
+passed range.
+
+ >>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
+ [<Event: Pub trip>]
+
+.. fieldlookup:: rangefield.not_lt
+
+not_lt
+''''''
+
+The returned ranges do not contain any points less than the passed range, that
+is the lower bound of the returned range is at least the lower bound of the
+passed range.
+
+ >>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
+ [<Event: Soft play>, <Event: Pub trip>]
+
+.. fieldlookup:: rangefield.not_gt
+
+not_gt
+''''''
+
+The returned ranges do not contain any points greater than the passed range, that
+is the upper bound of the returned range is at most the upper bound of the
+passed range.
+
+ >>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
+ [<Event: Soft play>]
+
+.. fieldlookup:: rangefield.adjacent_to
+
+adjacent_to
+'''''''''''
+
+The returned ranges share a bound with the passed range.
+
+ >>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
+ [<Event: Soft play>, <Event: Pub trip>]
+
+Querying using the bounds
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+There are three transforms available for use in queries. You can extract the
+lower or upper bound, or query based on emptiness.
+
+.. fieldlookup:: rangefield.startswith
+
+startswith
+''''''''''
+
+Returned objects have the given lower bound. Can be chained to valid lookups
+for the base field.
+
+ >>> Event.objects.filter(ages__startswith=21)
+ [<Event: Pub trip>]
+
+.. fieldlookup:: rangefield.endswith
+
+endswith
+''''''''
+
+Returned objects have the given upper bound. Can be chained to valid lookups
+for the base field.
+
+ >>> Event.objects.filter(ages__endswith=10)
+ [<Event: Soft play>]
+
+.. fieldlookup:: rangefield.isempty
+
+isempty
+'''''''
+
+Returned objects are empty ranges. Can be chained to valid lookups for a
+:class:`~django.db.models.BooleanField`.
+
+ >>> Event.objects.filter(ages__isempty=True)
+ []
+
+Defining your own range types
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+PostgreSQL allows the definition of custom range types. Django's model and form
+field implementations use base classes below, and psycopg2 provides a
+:func:`~psycopg2:psycopg2.extras.register_range` to allow use of custom range
+types.
+
+.. class:: RangeField(**options)
+
+ Base class for model range fields.
+
+ .. attribute:: base_field
+
+ The model field to use.
+
+ .. attribute:: range_type
+
+ The psycopg2 range type to use.
+
+ .. attribute:: form_field
+
+ The form field class to use. Should be a sublcass of
+ :class:`django.contrib.postgres.forms.BaseRangeField`.
+
+.. class:: django.contrib.postgres.forms.BaseRangeField
+
+ Base class for form range fields.
+
+ .. attribute:: base_field
+
+ The form field to use.
+
+ .. attribute:: range_type
+
+ The psycopg2 range type to use.
diff --git a/docs/ref/contrib/postgres/forms.txt b/docs/ref/contrib/postgres/forms.txt
index fcf44ce6a5..f6226c4b55 100644
--- a/docs/ref/contrib/postgres/forms.txt
+++ b/docs/ref/contrib/postgres/forms.txt
@@ -154,3 +154,48 @@ HStoreField
On occasions it may be useful to require or restrict the keys which are
valid for a given field. This can be done using the
:class:`~django.contrib.postgres.validators.KeysValidator`.
+
+Range Fields
+------------
+
+This group of fields all share similar functionality for accepting range data.
+They are based on :class:`~django.forms.MultiValueField`. They treat one
+omitted value as an unbounded range. They also validate that the lower bound is
+not greater than the upper bound.
+
+IntegerRangeField
+~~~~~~~~~~~~~~~~~
+
+.. class:: IntegerRangeField
+
+ Based on :class:`~django.forms.IntegerField` and translates its input into
+ :class:`~psycopg2:psycopg2.extras.NumericRange`. Default for
+ :class:`~django.contrib.postgres.fields.IntegerRangeField` and
+ :class:`~django.contrib.postgres.fields.BigIntegerRangeField`.
+
+FloatRangeField
+~~~~~~~~~~~~~~~
+
+.. class:: FloatRangeField
+
+ Based on :class:`~django.forms.FloatField` and translates its input into
+ :class:`~psycopg2:psycopg2.extras.NumericRange`. Default for
+ :class:`~django.contrib.postgres.fields.FloatRangeField`.
+
+DateTimeRangeField
+~~~~~~~~~~~~~~~~~~
+
+.. class:: DateTimeRangeField
+
+ Based on :class:`~django.forms.DateTimeField` and translates its input into
+ :class:`~psycopg2:psycopg2.extras.DateTimeTZRange`. Default for
+ :class:`~django.contrib.postgres.fields.DateTimeRangeField`.
+
+DateRangeField
+~~~~~~~~~~~~~~
+
+.. class:: DateRangeField
+
+ Based on :class:`~django.forms.DateField` and translates its input into
+ :class:`~psycopg2:psycopg2.extras.DateRange`. Default for
+ :class:`~django.contrib.postgres.fields.DateRangeField`.
diff --git a/docs/ref/contrib/postgres/validators.txt b/docs/ref/contrib/postgres/validators.txt
index 76cd52510a..f35a40dd27 100644
--- a/docs/ref/contrib/postgres/validators.txt
+++ b/docs/ref/contrib/postgres/validators.txt
@@ -18,3 +18,16 @@ Validators
.. note::
Note that this checks only for the existence of a given key, not that
the value of a key is non-empty.
+
+Range validators
+----------------
+
+.. class:: RangeMaxValueValidator(limit_value, message=None)
+
+ Validates that the upper bound of the range is not greater than
+ ``limit_value``.
+
+.. class:: RangeMinValueValidator(limit_value, message=None)
+
+ Validates that the lower bound of the range is not less than the
+ ``limit_value``.