mirror of
				https://github.com/django/django.git
				synced 2025-10-27 07:36:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			243 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			243 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| PostgreSQL specific model fields
 | |
| ================================
 | |
| 
 | |
| All of these fields are available from the ``django.contrib.postgres.fields``
 | |
| module.
 | |
| 
 | |
| .. currentmodule:: django.contrib.postgres.fields
 | |
| 
 | |
| ArrayField
 | |
| ----------
 | |
| 
 | |
| .. class:: ArrayField(base_field, size=None, **options)
 | |
| 
 | |
|     A field for storing lists of data. Most field types can be used, you simply
 | |
|     pass another field instance as the :attr:`base_field
 | |
|     <ArrayField.base_field>`. You may also specify a :attr:`size
 | |
|     <ArrayField.size>`. ``ArrayField`` can be nested to store multi-dimensional
 | |
|     arrays.
 | |
| 
 | |
|     .. attribute:: base_field
 | |
| 
 | |
|         This is a required argument.
 | |
| 
 | |
|         Specifies the underlying data type and behavior for the array. It
 | |
|         should be an instance of a subclass of
 | |
|         :class:`~django.db.models.Field`. For example, it could be an
 | |
|         :class:`~django.db.models.IntegerField` or a
 | |
|         :class:`~django.db.models.CharField`. Most field types are permitted,
 | |
|         with the exception of those handling relational data
 | |
|         (:class:`~django.db.models.ForeignKey`,
 | |
|         :class:`~django.db.models.OneToOneField` and
 | |
|         :class:`~django.db.models.ManyToManyField`).
 | |
| 
 | |
|         It is possible to nest array fields - you can specify an instance of
 | |
|         ``ArrayField`` as the ``base_field``. For example::
 | |
| 
 | |
|             from django.db import models
 | |
|             from django.contrib.postgres.fields import ArrayField
 | |
| 
 | |
|             class ChessBoard(models.Model):
 | |
|                 board = ArrayField(
 | |
|                     ArrayField(
 | |
|                         CharField(max_length=10, blank=True, null=True),
 | |
|                         size=8),
 | |
|                     size=8)
 | |
| 
 | |
|         Transformation of values between the database and the model, validation
 | |
|         of data and configuration, and serialization are all delegated to the
 | |
|         underlying base field.
 | |
| 
 | |
|     .. attribute:: size
 | |
| 
 | |
|         This is an optional argument.
 | |
| 
 | |
|         If passed, the array will have a maximum size as specified. This will
 | |
|         be passed to the database, although PostgreSQL at present does not
 | |
|         enforce the restriction.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     When nesting ``ArrayField``, whether you use the `size` parameter or not,
 | |
|     PostgreSQL requires that the arrays are rectangular::
 | |
| 
 | |
|         from django.db import models
 | |
|         from django.contrib.postgres.fields import ArrayField
 | |
| 
 | |
|         class Board(models.Model):
 | |
|             pieces = ArrayField(ArrayField(models.IntegerField()))
 | |
| 
 | |
|         # Valid
 | |
|         Board(pieces=[
 | |
|             [2, 3],
 | |
|             [2, 1],
 | |
|         ])
 | |
| 
 | |
|         # Not valid
 | |
|         Board(pieces=[
 | |
|             [2, 3],
 | |
|             [2],
 | |
|         ])
 | |
| 
 | |
|     If irregular shapes are required, then the underlying field should be made
 | |
|     nullable and the values padded with ``None``.
 | |
| 
 | |
| Querying ArrayField
 | |
| ^^^^^^^^^^^^^^^^^^^
 | |
| 
 | |
| There are a number of custom lookups and transforms for :class:`ArrayField`.
 | |
| We will use the following example model::
 | |
| 
 | |
|     from django.db import models
 | |
|     from django.contrib.postgres.fields import ArrayField
 | |
| 
 | |
|     class Post(models.Model):
 | |
|         name = models.CharField(max_length=200)
 | |
|         tags = ArrayField(models.CharField(max_length=200), blank=True)
 | |
| 
 | |
|         def __str__(self):  # __unicode__ on python 2
 | |
|             return self.name
 | |
| 
 | |
| .. fieldlookup:: arrayfield.contains
 | |
| 
 | |
| contains
 | |
| ~~~~~~~~
 | |
| 
 | |
| The :lookup:`contains` lookup is overridden on :class:`ArrayField`. The
 | |
| returned objects will be those where the values passed are a subset of the
 | |
| data. It uses the SQL operator ``@>``. For example::
 | |
| 
 | |
|     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
 | |
|     >>> Post.objects.create(name='Second post', tags=['thoughts'])
 | |
|     >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
 | |
| 
 | |
|     >>> Post.objects.filter(tags__contains=['thoughts'])
 | |
|     [<Post: First post>, <Post: Second post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__contains=['django'])
 | |
|     [<Post: First post>, <Post: Third post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__contains=['django', 'thoughts'])
 | |
|     [<Post: First post>]
 | |
| 
 | |
| .. fieldlookup:: arrayfield.contained_by
 | |
| 
 | |
| contained_by
 | |
| ~~~~~~~~~~~~
 | |
| 
 | |
| This is the inverse of the :lookup:`contains <arrayfield.contains>` lookup -
 | |
| the objects returned will be those where the data is a subset of the values
 | |
| passed. It uses the SQL operator ``<@``. For example::
 | |
| 
 | |
|     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
 | |
|     >>> Post.objects.create(name='Second post', tags=['thoughts'])
 | |
|     >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
 | |
| 
 | |
|     >>> Post.objects.filter(tags__contained_by=['thoughts', 'django'])
 | |
|     [<Post: First post>, <Post: Second post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__contained_by=['thoughts', 'django', 'tutorial'])
 | |
|     [<Post: First post>, <Post: Second post>, <Post: Third post>]
 | |
| 
 | |
| .. fieldlookup:: arrayfield.overlap
 | |
| 
 | |
| overlap
 | |
| ~~~~~~~
 | |
| 
 | |
| Returns objects where the data shares any results with the values passed. Uses
 | |
| the SQL operator ``&&``. For example::
 | |
| 
 | |
|     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
 | |
|     >>> Post.objects.create(name='Second post', tags=['thoughts'])
 | |
|     >>> Post.objects.create(name='Third post', tags=['tutorial', 'django'])
 | |
| 
 | |
|     >>> Post.objects.filter(tags__overlap=['thoughts'])
 | |
|     [<Post: First post>, <Post: Second post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__overlap=['thoughts', 'tutorial'])
 | |
|     [<Post: First post>, <Post: Second post>, <Post: Third post>]
 | |
| 
 | |
| .. fieldlookup:: arrayfield.len
 | |
| 
 | |
| len
 | |
| ~~~
 | |
| 
 | |
| Returns the length of the array. The lookups available afterwards are those
 | |
| available for :class:`~django.db.models.IntegerField`. For example::
 | |
| 
 | |
|     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
 | |
|     >>> Post.objects.create(name='Second post', tags=['thoughts'])
 | |
| 
 | |
|     >>> Post.objects.filter(tags__len=1)
 | |
|     [<Post: Second post>]
 | |
| 
 | |
| .. fieldlookup:: arrayfield.index
 | |
| 
 | |
| Index transforms
 | |
| ~~~~~~~~~~~~~~~~
 | |
| 
 | |
| This class of transforms allows you to index into the array in queries. Any
 | |
| non-negative integer can be used. There are no errors if it exceeds the
 | |
| :attr:`size <ArrayField.size>` of the array. The lookups available after the
 | |
| transform are those from the :attr:`base_field <ArrayField.base_field>`. For
 | |
| example::
 | |
| 
 | |
|     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
 | |
|     >>> Post.objects.create(name='Second post', tags=['thoughts'])
 | |
| 
 | |
|     >>> Post.objects.filter(tags__0='thoughts')
 | |
|     [<Post: First post>, <Post: Second post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__1__iexact='Django')
 | |
|     [<Post: First post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__276='javascript')
 | |
|     []
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     PostgreSQL uses 1-based indexing for array fields when writing raw SQL.
 | |
|     However these indexes and those used in :lookup:`slices <arrayfield.slice>`
 | |
|     use 0-based indexing to be consistent with Python.
 | |
| 
 | |
| .. fieldlookup:: arrayfield.slice
 | |
| 
 | |
| Slice transforms
 | |
| ~~~~~~~~~~~~~~~~
 | |
| 
 | |
| This class of transforms allow you to take a slice of the array. Any two
 | |
| non-negative integers can be used, separated by a single underscore. The
 | |
| lookups available after the transform do not change. For example::
 | |
| 
 | |
|     >>> Post.objects.create(name='First post', tags=['thoughts', 'django'])
 | |
|     >>> Post.objects.create(name='Second post', tags=['thoughts'])
 | |
|     >>> Post.objects.create(name='Third post', tags=['django', 'python', 'thoughts'])
 | |
| 
 | |
|     >>> Post.objects.filter(tags__0_1=['thoughts'])
 | |
|     [<Post: First post>]
 | |
| 
 | |
|     >>> Post.objects.filter(tags__0_2__contains='thoughts')
 | |
|     [<Post: First post>, <Post: Second post>]
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     PostgreSQL uses 1-based indexing for array fields when writing raw SQL.
 | |
|     However these slices and those used in :lookup:`indexes <arrayfield.index>`
 | |
|     use 0-based indexing to be consistent with Python.
 | |
| 
 | |
| .. admonition:: Multidimensional arrays with indexes and slices
 | |
| 
 | |
|     PostgreSQL has some rather esoteric behavior when using indexes and slices
 | |
|     on multidimensional arrays. It will always work to use indexes to reach
 | |
|     down to the final underlying data, but most other slices behave strangely
 | |
|     at the database level and cannot be supported in a logical, consistent
 | |
|     fashion by Django.
 | |
| 
 | |
| Indexing ArrayField
 | |
| ^^^^^^^^^^^^^^^^^^^
 | |
| 
 | |
| At present using :attr:`~django.db.models.Field.db_index` will create a
 | |
| ``btree`` index. This does not offer particularly significant help to querying.
 | |
| A more useful index is a ``GIN`` index, which you should create using a
 | |
| :class:`~django.db.migrations.operations.RunSQL` operation.
 |