fields.txt 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. PostgreSQL specific model fields
  2. ================================
  3. All of these fields are available from the ``django.contrib.postgres.fields``
  4. module.
  5. .. currentmodule:: django.contrib.postgres.fields
  6. ArrayField
  7. ----------
  8. .. class:: ArrayField(base_field, size=None, **options)
  9. A field for storing lists of data. Most field types can be used, you simply
  10. pass another field instance as the :attr:`base_field
  11. <ArrayField.base_field>`. You may also specify a :attr:`size
  12. <ArrayField.size>`. ``ArrayField`` can be nested to store multi-dimensional
  13. arrays.
  14. .. attribute:: base_field
  15. This is a required argument.
  16. Specifies the underlying data type and behavior for the array. It
  17. should be an instance of a subclass of
  18. :class:`~django.db.models.Field`. For example, it could be an
  19. :class:`~django.db.models.IntegerField` or a
  20. :class:`~django.db.models.CharField`. Most field types are permitted,
  21. with the exception of those handling relational data
  22. (:class:`~django.db.models.ForeignKey`,
  23. :class:`~django.db.models.OneToOneField` and
  24. :class:`~django.db.models.ManyToManyField`).
  25. It is possible to nest array fields - you can specify an instance of
  26. ``ArrayField`` as the ``base_field``. For example::
  27. from django.db import models
  28. from django.contrib.postgres.fields import ArrayField
  29. class ChessBoard(models.Model):
  30. board = ArrayField(
  31. ArrayField(
  32. models.CharField(max_length=10, blank=True),
  33. size=8,
  34. ),
  35. size=8,
  36. )
  37. Transformation of values between the database and the model, validation
  38. of data and configuration, and serialization are all delegated to the
  39. underlying base field.
  40. .. attribute:: size
  41. This is an optional argument.
  42. If passed, the array will have a maximum size as specified. This will
  43. be passed to the database, although PostgreSQL at present does not
  44. enforce the restriction.
  45. .. note::
  46. When nesting ``ArrayField``, whether you use the `size` parameter or not,
  47. PostgreSQL requires that the arrays are rectangular::
  48. from django.contrib.postgres.fields import ArrayField
  49. from django.db import models
  50. class Board(models.Model):
  51. pieces = ArrayField(ArrayField(models.IntegerField()))
  52. # Valid
  53. Board(pieces=[
  54. [2, 3],
  55. [2, 1],
  56. ])
  57. # Not valid
  58. Board(pieces=[
  59. [2, 3],
  60. [2],
  61. ])
  62. If irregular shapes are required, then the underlying field should be made
  63. nullable and the values padded with ``None``.
  64. Querying ArrayField
  65. ^^^^^^^^^^^^^^^^^^^
  66. There are a number of custom lookups and transforms for :class:`ArrayField`.
  67. We will use the following example model::
  68. from django.db import models
  69. from django.contrib.postgres.fields import ArrayField
  70. class Post(models.Model):
  71. name = models.CharField(max_length=200)
  72. tags = ArrayField(models.CharField(max_length=200), blank=True)
  73. def __str__(self): # __unicode__ on Python 2
  74. return self.name
  75. .. fieldlookup:: arrayfield.contains
  76. contains
  77. ~~~~~~~~
  78. The :lookup:`contains` lookup is overridden on :class:`ArrayField`. The
  79. returned objects will be those where the values passed are a subset of the
  80. data. It uses the SQL operator ``@>``. For example::
  81. >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
  82. >>> Post.objects.create(name='Second post', tags=['thoughts'])
  83. >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
  84. >>> Post.objects.filter(tags__contains=['thoughts'])
  85. [<Post: First post>, <Post: Second post>]
  86. >>> Post.objects.filter(tags__contains=['django'])
  87. [<Post: First post>, <Post: Third post>]
  88. >>> Post.objects.filter(tags__contains=['django', 'thoughts'])
  89. [<Post: First post>]
  90. .. fieldlookup:: arrayfield.contained_by
  91. contained_by
  92. ~~~~~~~~~~~~
  93. This is the inverse of the :lookup:`contains <arrayfield.contains>` lookup -
  94. the objects returned will be those where the data is a subset of the values
  95. passed. It uses the SQL operator ``<@``. For example::
  96. >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
  97. >>> Post.objects.create(name='Second post', tags=['thoughts'])
  98. >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
  99. >>> Post.objects.filter(tags__contained_by=['thoughts', 'django'])
  100. [<Post: First post>, <Post: Second post>]
  101. >>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
  102. [<Post: First post>, <Post: Second post>, <Post: Third post>]
  103. .. fieldlookup:: arrayfield.overlap
  104. overlap
  105. ~~~~~~~
  106. Returns objects where the data shares any results with the values passed. Uses
  107. the SQL operator ``&&``. For example::
  108. >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
  109. >>> Post.objects.create(name='Second post', tags=['thoughts'])
  110. >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
  111. >>> Post.objects.filter(tags__overlap=['thoughts'])
  112. [<Post: First post>, <Post: Second post>]
  113. >>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
  114. [<Post: First post>, <Post: Second post>, <Post: Third post>]
  115. .. fieldlookup:: arrayfield.len
  116. len
  117. ~~~
  118. Returns the length of the array. The lookups available afterwards are those
  119. available for :class:`~django.db.models.IntegerField`. For example::
  120. >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
  121. >>> Post.objects.create(name='Second post', tags=['thoughts'])
  122. >>> Post.objects.filter(tags__len=1)
  123. [<Post: Second post>]
  124. .. fieldlookup:: arrayfield.index
  125. Index transforms
  126. ~~~~~~~~~~~~~~~~
  127. This class of transforms allows you to index into the array in queries. Any
  128. non-negative integer can be used. There are no errors if it exceeds the
  129. :attr:`size <ArrayField.size>` of the array. The lookups available after the
  130. transform are those from the :attr:`base_field <ArrayField.base_field>`. For
  131. example::
  132. >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
  133. >>> Post.objects.create(name='Second post', tags=['thoughts'])
  134. >>> Post.objects.filter(tags__0='thoughts')
  135. [<Post: First post>, <Post: Second post>]
  136. >>> Post.objects.filter(tags__1__iexact='Django')
  137. [<Post: First post>]
  138. >>> Post.objects.filter(tags__276='javascript')
  139. []
  140. .. note::
  141. PostgreSQL uses 1-based indexing for array fields when writing raw SQL.
  142. However these indexes and those used in :lookup:`slices <arrayfield.slice>`
  143. use 0-based indexing to be consistent with Python.
  144. .. fieldlookup:: arrayfield.slice
  145. Slice transforms
  146. ~~~~~~~~~~~~~~~~
  147. This class of transforms allow you to take a slice of the array. Any two
  148. non-negative integers can be used, separated by a single underscore. The
  149. lookups available after the transform do not change. For example::
  150. >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
  151. >>> Post.objects.create(name='Second post', tags=['thoughts'])
  152. >>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts'])
  153. >>> Post.objects.filter(tags__0_1=['thoughts'])
  154. [<Post: First post>]
  155. >>> Post.objects.filter(tags__0_2__contains='thoughts')
  156. [<Post: First post>, <Post: Second post>]
  157. .. note::
  158. PostgreSQL uses 1-based indexing for array fields when writing raw SQL.
  159. However these slices and those used in :lookup:`indexes <arrayfield.index>`
  160. use 0-based indexing to be consistent with Python.
  161. .. admonition:: Multidimensional arrays with indexes and slices
  162. PostgreSQL has some rather esoteric behavior when using indexes and slices
  163. on multidimensional arrays. It will always work to use indexes to reach
  164. down to the final underlying data, but most other slices behave strangely
  165. at the database level and cannot be supported in a logical, consistent
  166. fashion by Django.
  167. Indexing ArrayField
  168. ^^^^^^^^^^^^^^^^^^^
  169. At present using :attr:`~django.db.models.Field.db_index` will create a
  170. ``btree`` index. This does not offer particularly significant help to querying.
  171. A more useful index is a ``GIN`` index, which you should create using a
  172. :class:`~django.db.migrations.operations.RunSQL` operation.
  173. HStoreField
  174. -----------
  175. .. class:: HStoreField(**options)
  176. A field for storing mappings of strings to strings. The Python data type
  177. used is a ``dict``.
  178. To use this field, you'll need to:
  179. 1. Add ``'django.contrib.postgres'`` in your :setting:`INSTALLED_APPS`.
  180. 2. Setup the hstore extension in PostgreSQL before the first ``CreateModel``
  181. or ``AddField`` operation by adding a migration with the
  182. :class:`~django.contrib.postgres.operations.HStoreExtension` operation.
  183. You'll see an error like ``can't adapt type 'dict'`` if you skip the first
  184. step, or ``type "hstore" does not exist`` if you skip the second.
  185. .. note::
  186. On occasions it may be useful to require or restrict the keys which are
  187. valid for a given field. This can be done using the
  188. :class:`~django.contrib.postgres.validators.KeysValidator`.
  189. Querying HStoreField
  190. ^^^^^^^^^^^^^^^^^^^^
  191. In addition to the ability to query by key, there are a number of custom
  192. lookups available for ``HStoreField``.
  193. We will use the following example model::
  194. from django.contrib.postgres.fields import HStoreField
  195. from django.db import models
  196. class Dog(models.Model):
  197. name = models.CharField(max_length=200)
  198. data = HStoreField()
  199. def __str__(self): # __unicode__ on Python 2
  200. return self.name
  201. .. fieldlookup:: hstorefield.key
  202. Key lookups
  203. ~~~~~~~~~~~
  204. To query based on a given key, you simply use that key as the lookup name::
  205. >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
  206. >>> Dog.objects.create(name='Meg', data={'breed': 'collie'})
  207. >>> Dog.objects.filter(data__breed='collie')
  208. [<Dog: Meg>]
  209. You can chain other lookups after key lookups::
  210. >>> Dog.objects.filter(data__breed__contains='l')
  211. [<Dog: Rufus>, <Dog: Meg>]
  212. If the key you wish to query by clashes with the name of another lookup, you
  213. need to use the :lookup:`hstorefield.contains` lookup instead.
  214. .. warning::
  215. Since any string could be a key in a hstore value, any lookup other than
  216. those listed below will be interpreted as a key lookup. No errors are
  217. raised. Be extra careful for typing mistakes, and always check your queries
  218. work as you intend.
  219. .. fieldlookup:: hstorefield.contains
  220. contains
  221. ~~~~~~~~
  222. The :lookup:`contains` lookup is overridden on
  223. :class:`~django.contrib.postgres.fields.HStoreField`. The returned objects are
  224. those where the given ``dict`` of key-value pairs are all contained in the
  225. field. It uses the SQL operator ``@>``. For example::
  226. >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
  227. >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
  228. >>> Dog.objects.create(name='Fred', data={})
  229. >>> Dog.objects.filter(data__contains={'owner': 'Bob'})
  230. [<Dog: Rufus>, <Dog: Meg>]
  231. >>> Dog.objects.filter(data__contains={'breed': 'collie'})
  232. [<Dog: Meg>]
  233. .. fieldlookup:: hstorefield.contained_by
  234. contained_by
  235. ~~~~~~~~~~~~
  236. This is the inverse of the :lookup:`contains <hstorefield.contains>` lookup -
  237. the objects returned will be those where the key-value pairs on the object are
  238. a subset of those in the value passed. It uses the SQL operator ``<@``. For
  239. example::
  240. >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
  241. >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
  242. >>> Dog.objects.create(name='Fred', data={})
  243. >>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
  244. [<Dog: Meg>, <Dog: Fred>]
  245. >>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
  246. [<Dog: Fred>]
  247. .. fieldlookup:: hstorefield.has_key
  248. has_key
  249. ~~~~~~~
  250. Returns objects where the given key is in the data. Uses the SQL operator
  251. ``?``. For example::
  252. >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
  253. >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
  254. >>> Dog.objects.filter(data__has_key='owner')
  255. [<Dog: Meg>]
  256. .. fieldlookup:: hstorefield.has_keys
  257. has_keys
  258. ~~~~~~~~
  259. Returns objects where all of the given keys are in the data. Uses the SQL operator
  260. ``?&``. For example::
  261. >>> Dog.objects.create(name='Rufus', data={})
  262. >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
  263. >>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
  264. [<Dog: Meg>]
  265. .. fieldlookup:: hstorefield.keys
  266. keys
  267. ~~~~
  268. Returns objects where the array of keys is the given value. Note that the order
  269. is not guaranteed to be reliable, so this transform is mainly useful for using
  270. in conjunction with lookups on
  271. :class:`~django.contrib.postgres.fields.ArrayField`. Uses the SQL function
  272. ``akeys()``. For example::
  273. >>> Dog.objects.create(name='Rufus', data={'toy': 'bone'})
  274. >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
  275. >>> Dog.objects.filter(data__keys__overlap=['breed', 'toy'])
  276. [<Dog: Rufus>, <Dog: Meg>]
  277. .. fieldlookup:: hstorefield.values
  278. values
  279. ~~~~~~
  280. Returns objects where the array of values is the given value. Note that the
  281. order is not guaranteed to be reliable, so this transform is mainly useful for
  282. using in conjunction with lookups on
  283. :class:`~django.contrib.postgres.fields.ArrayField`. Uses the SQL function
  284. ``avalues()``. For example::
  285. >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
  286. >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
  287. >>> Dog.objects.filter(data__values__contains=['collie'])
  288. [<Dog: Meg>]
  289. .. _range-fields:
  290. Range Fields
  291. ------------
  292. There are five range field types, corresponding to the built-in range types in
  293. PostgreSQL. These fields are used to store a range of values; for example the
  294. start and end timestamps of an event, or the range of ages an activity is
  295. suitable for.
  296. All of the range fields translate to :ref:`psycopg2 Range objects
  297. <psycopg2:adapt-range>` in python, but also accept tuples as input if no bounds
  298. information is necessary. The default is lower bound included, upper bound
  299. excluded.
  300. IntegerRangeField
  301. ^^^^^^^^^^^^^^^^^
  302. .. class:: IntegerRangeField(**options)
  303. Stores a range of integers. Based on an
  304. :class:`~django.db.models.IntegerField`. Represented by an ``int4range`` in
  305. the database and a :class:`~psycopg2:psycopg2.extras.NumericRange` in
  306. Python.
  307. BigIntegerRangeField
  308. ^^^^^^^^^^^^^^^^^^^^
  309. .. class:: BigIntegerRangeField(**options)
  310. Stores a range of large integers. Based on a
  311. :class:`~django.db.models.BigIntegerField`. Represented by an ``int8range``
  312. in the database and a :class:`~psycopg2:psycopg2.extras.NumericRange` in
  313. Python.
  314. FloatRangeField
  315. ^^^^^^^^^^^^^^^
  316. .. class:: FloatRangeField(**options)
  317. Stores a range of floating point values. Based on a
  318. :class:`~django.db.models.FloatField`. Represented by a ``numrange`` in the
  319. database and a :class:`~psycopg2:psycopg2.extras.NumericRange` in Python.
  320. DateTimeRangeField
  321. ^^^^^^^^^^^^^^^^^^
  322. .. class:: DateTimeRangeField(**options)
  323. Stores a range of timestamps. Based on a
  324. :class:`~django.db.models.DateTimeField`. Represented by a ``tztsrange`` in
  325. the database and a :class:`~psycopg2:psycopg2.extras.DateTimeTZRange` in
  326. Python.
  327. DateRangeField
  328. ^^^^^^^^^^^^^^
  329. .. class:: DateRangeField(**options)
  330. Stores a range of dates. Based on a
  331. :class:`~django.db.models.DateField`. Represented by a ``daterange`` in the
  332. database and a :class:`~psycopg2:psycopg2.extras.DateRange` in Python.
  333. Querying Range Fields
  334. ^^^^^^^^^^^^^^^^^^^^^
  335. There are a number of custom lookups and transforms for range fields. They are
  336. available on all the above fields, but we will use the following example
  337. model::
  338. from django.contrib.postgres.fields import IntegerRangeField
  339. from django.db import models
  340. class Event(models.Model):
  341. name = models.CharField(max_length=200)
  342. ages = IntegerRangeField()
  343. def __str__(self): # __unicode__ on Python 2
  344. return self.name
  345. We will also use the following example objects::
  346. >>> Event.objects.create(name='Soft play', ages=(0, 10))
  347. >>> Event.objects.create(name='Pub trip', ages=(21, None))
  348. and ``NumericRange``:
  349. >>> from psycopg2.extras import NumericRange
  350. Containment functions
  351. ~~~~~~~~~~~~~~~~~~~~~
  352. As with other PostgreSQL fields, there are three standard containment
  353. operators: ``contains``, ``contained_by`` and ``overlap``, using the SQL
  354. operators ``@>``, ``<@``, and ``&&`` respectively.
  355. .. fieldlookup:: rangefield.contains
  356. contains
  357. ''''''''
  358. >>> Event.objects.filter(ages__contains=NumericRange(4, 5))
  359. [<Event: Soft play>]
  360. .. fieldlookup:: rangefield.contained_by
  361. contained_by
  362. ''''''''''''
  363. >>> Event.objects.filter(ages__contained_by=NumericRange(0, 15))
  364. [<Event: Soft play>]
  365. .. fieldlookup:: rangefield.overlap
  366. overlap
  367. '''''''
  368. >>> Event.objects.filter(ages__overlap=NumericRange(8, 12))
  369. [<Event: Soft play>]
  370. Comparison functions
  371. ~~~~~~~~~~~~~~~~~~~~
  372. Range fields support the standard lookups: :lookup:`lt`, :lookup:`gt`,
  373. :lookup:`lte` and :lookup:`gte`. These are not particularly helpful - they
  374. compare the lower bounds first and then the upper bounds only if necessary.
  375. This is also the strategy used to order by a range field. It is better to use
  376. the specific range comparison operators.
  377. .. fieldlookup:: rangefield.fully_lt
  378. fully_lt
  379. ''''''''
  380. The returned ranges are strictly less than the passed range. In other words,
  381. all the points in the returned range are less than all those in the passed
  382. range.
  383. >>> Event.objects.filter(ages__fully_lt=NumericRange(11, 15))
  384. [<Event: Soft play>]
  385. .. fieldlookup:: rangefield.fully_gt
  386. fully_gt
  387. ''''''''
  388. The returned ranges are strictly greater than the passed range. In other words,
  389. the all the points in the returned range are greater than all those in the
  390. passed range.
  391. >>> Event.objects.filter(ages__fully_gt=NumericRange(11, 15))
  392. [<Event: Pub trip>]
  393. .. fieldlookup:: rangefield.not_lt
  394. not_lt
  395. ''''''
  396. The returned ranges do not contain any points less than the passed range, that
  397. is the lower bound of the returned range is at least the lower bound of the
  398. passed range.
  399. >>> Event.objects.filter(ages__not_lt=NumericRange(0, 15))
  400. [<Event: Soft play>, <Event: Pub trip>]
  401. .. fieldlookup:: rangefield.not_gt
  402. not_gt
  403. ''''''
  404. The returned ranges do not contain any points greater than the passed range, that
  405. is the upper bound of the returned range is at most the upper bound of the
  406. passed range.
  407. >>> Event.objects.filter(ages__not_gt=NumericRange(3, 10))
  408. [<Event: Soft play>]
  409. .. fieldlookup:: rangefield.adjacent_to
  410. adjacent_to
  411. '''''''''''
  412. The returned ranges share a bound with the passed range.
  413. >>> Event.objects.filter(ages__adjacent_to=NumericRange(10, 21))
  414. [<Event: Soft play>, <Event: Pub trip>]
  415. Querying using the bounds
  416. ~~~~~~~~~~~~~~~~~~~~~~~~~
  417. There are three transforms available for use in queries. You can extract the
  418. lower or upper bound, or query based on emptiness.
  419. .. fieldlookup:: rangefield.startswith
  420. startswith
  421. ''''''''''
  422. Returned objects have the given lower bound. Can be chained to valid lookups
  423. for the base field.
  424. >>> Event.objects.filter(ages__startswith=21)
  425. [<Event: Pub trip>]
  426. .. fieldlookup:: rangefield.endswith
  427. endswith
  428. ''''''''
  429. Returned objects have the given upper bound. Can be chained to valid lookups
  430. for the base field.
  431. >>> Event.objects.filter(ages__endswith=10)
  432. [<Event: Soft play>]
  433. .. fieldlookup:: rangefield.isempty
  434. isempty
  435. '''''''
  436. Returned objects are empty ranges. Can be chained to valid lookups for a
  437. :class:`~django.db.models.BooleanField`.
  438. >>> Event.objects.filter(ages__isempty=True)
  439. []
  440. Defining your own range types
  441. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  442. PostgreSQL allows the definition of custom range types. Django's model and form
  443. field implementations use base classes below, and psycopg2 provides a
  444. :func:`~psycopg2:psycopg2.extras.register_range` to allow use of custom range
  445. types.
  446. .. class:: RangeField(**options)
  447. Base class for model range fields.
  448. .. attribute:: base_field
  449. The model field to use.
  450. .. attribute:: range_type
  451. The psycopg2 range type to use.
  452. .. attribute:: form_field
  453. The form field class to use. Should be a subclass of
  454. :class:`django.contrib.postgres.forms.BaseRangeField`.
  455. .. class:: django.contrib.postgres.forms.BaseRangeField
  456. Base class for form range fields.
  457. .. attribute:: base_field
  458. The form field to use.
  459. .. attribute:: range_type
  460. The psycopg2 range type to use.