Skip to content

Commit 706301f

Browse files
committed
stub out docs
1 parent 7ed5b91 commit 706301f

File tree

4 files changed

+181
-0
lines changed

4 files changed

+181
-0
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ repos:
4444
hooks:
4545
- id: rstcheck
4646
additional_dependencies: [sphinx]
47+
args: ["--ignore-directives=fieldlookup", "--ignore-roles=lookup"]
4748

4849
# We use the Python version instead of the original version which seems to require Docker
4950
# https://github.com/koalaman/shellcheck-precommit

docs/source/_ext/djangodocs.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
def setup(app):
2+
app.add_crossref_type(
3+
directivename="fieldlookup",
4+
rolename="lookup",
5+
indextemplate="pair: %s; field lookup type",
6+
)

docs/source/conf.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@
77
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
88
from __future__ import annotations
99

10+
import sys
1011
from importlib.metadata import version as _version
12+
from pathlib import Path
13+
14+
# If extensions (or modules to document with autodoc) are in another directory,
15+
# add these directories to sys.path here. If the directory is relative to the
16+
# documentation root, use os.path.abspath to make it absolute, like shown here.
17+
sys.path.append(str((Path(__file__).parent / "_ext").resolve()))
1118

1219
project = "django_mongodb"
1320
copyright = "2024, The MongoDB Python Team"
@@ -22,6 +29,7 @@
2229
add_module_names = False
2330

2431
extensions = [
32+
"djangodocs",
2533
"sphinx.ext.intersphinx",
2634
]
2735

docs/source/fields.rst

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,172 @@ Model field reference
55

66
Some MongoDB-specific fields are available in ``django_mongodb.fields``.
77

8+
``ArrayField``
9+
--------------
10+
11+
.. class:: ArrayField(base_field, size=None, **options)
12+
13+
A field for storing lists of data. Most field types can be used, and you
14+
pass another field instance as the :attr:`base_field
15+
<ArrayField.base_field>`. You may also specify a :attr:`size
16+
<ArrayField.size>`. ``ArrayField`` can be nested to store multi-dimensional
17+
arrays.
18+
19+
If you give the field a :attr:`~django.db.models.Field.default`, ensure
20+
it's a callable such as ``list`` (for an empty default) or a callable that
21+
returns a list (such as a function). Incorrectly using ``default=[]``
22+
creates a mutable default that is shared between all instances of
23+
``ArrayField``.
24+
25+
.. attribute:: base_field
26+
27+
This is a required argument.
28+
29+
Specifies the underlying data type and behavior for the array. It
30+
should be an instance of a subclass of
31+
:class:`~django.db.models.Field`. For example, it could be an
32+
:class:`~django.db.models.IntegerField` or a
33+
:class:`~django.db.models.CharField`. Most field types are permitted,
34+
with the exception of those handling relational data
35+
(:class:`~django.db.models.ForeignKey`,
36+
:class:`~django.db.models.OneToOneField` and
37+
:class:`~django.db.models.ManyToManyField`) and file fields (
38+
:class:`~django.db.models.FileField` and
39+
:class:`~django.db.models.ImageField`).
40+
41+
It is possible to nest array fields - you can specify an instance of
42+
``ArrayField`` as the ``base_field``. For example::
43+
44+
from django.db import models
45+
from django_mongodb.fields import ArrayField
46+
47+
48+
class ChessBoard(models.Model):
49+
board = ArrayField(
50+
ArrayField(
51+
models.CharField(max_length=10, blank=True),
52+
size=8,
53+
),
54+
size=8,
55+
)
56+
57+
Transformation of values between the database and the model, validation
58+
of data and configuration, and serialization are all delegated to the
59+
underlying base field.
60+
61+
.. attribute:: size
62+
63+
This is an optional argument.
64+
65+
If passed, the array will have a maximum size as specified, validated
66+
only by forms.
67+
68+
Querying ``ArrayField``
69+
~~~~~~~~~~~~~~~~~~~~~~~
70+
71+
There are a number of custom lookups and transforms for :class:`ArrayField`.
72+
We will use the following example model::
73+
74+
from django.db import models
75+
from django_mongodb.fields import ArrayField
76+
77+
78+
class Post(models.Model):
79+
name = models.CharField(max_length=200)
80+
tags = ArrayField(models.CharField(max_length=200), blank=True)
81+
82+
def __str__(self):
83+
return self.name
84+
85+
.. fieldlookup:: arrayfield.contains
86+
87+
``contains``
88+
^^^^^^^^^^^^
89+
90+
The :lookup:`contains` lookup is overridden on :class:`ArrayField`. The
91+
returned objects will be those where the values passed are a subset of the
92+
data. It uses the ``$setIntersection`` operator. For example:
93+
94+
.. code-block:: pycon
95+
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+
100+
>>> Post.objects.filter(tags__contains=["thoughts"])
101+
<QuerySet [<Post: First post>, <Post: Second post>]>
102+
103+
>>> Post.objects.filter(tags__contains=["django"])
104+
<QuerySet [<Post: First post>, <Post: Third post>]>
105+
106+
>>> Post.objects.filter(tags__contains=["django", "thoughts"])
107+
<QuerySet [<Post: First post>]>
108+
109+
.. fieldlookup:: arrayfield.len
110+
111+
``len``
112+
^^^^^^^
113+
114+
Returns the length of the array. The lookups available afterward are those
115+
available for :class:`~django.db.models.IntegerField`. For example:
116+
117+
.. code-block:: pycon
118+
119+
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
120+
>>> Post.objects.create(name="Second post", tags=["thoughts"])
121+
122+
>>> Post.objects.filter(tags__len=1)
123+
<QuerySet [<Post: Second post>]>
124+
125+
.. fieldlookup:: arrayfield.index
126+
127+
Index transforms
128+
^^^^^^^^^^^^^^^^
129+
130+
Index transforms index into the array. Any non-negative integer can be used.
131+
There are no errors if it exceeds the :attr:`size <ArrayField.size>` of the
132+
array. The lookups available after the transform are those from the
133+
:attr:`base_field <ArrayField.base_field>`. For example:
134+
135+
.. code-block:: pycon
136+
137+
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
138+
>>> Post.objects.create(name="Second post", tags=["thoughts"])
139+
140+
>>> Post.objects.filter(tags__0="thoughts")
141+
<QuerySet [<Post: First post>, <Post: Second post>]>
142+
143+
>>> Post.objects.filter(tags__1__iexact="Django")
144+
<QuerySet [<Post: First post>]>
145+
146+
>>> Post.objects.filter(tags__276="javascript")
147+
<QuerySet []>
148+
149+
These indexes use 0-based indexing.
150+
151+
.. fieldlookup:: arrayfield.slice
152+
153+
Slice transforms
154+
^^^^^^^^^^^^^^^^
155+
156+
Slice transforms take a slice of the array. Any two non-negative integers can
157+
be used, separated by a single underscore. The lookups available after the
158+
transform do not change. For example:
159+
160+
.. code-block:: pycon
161+
162+
>>> Post.objects.create(name="First post", tags=["thoughts", "django"])
163+
>>> Post.objects.create(name="Second post", tags=["thoughts"])
164+
>>> Post.objects.create(name="Third post", tags=["django", "python", "thoughts"])
165+
166+
>>> Post.objects.filter(tags__0_1=["thoughts"])
167+
<QuerySet [<Post: First post>, <Post: Second post>]>
168+
169+
>>> Post.objects.filter(tags__0_2__contains=["thoughts"])
170+
<QuerySet [<Post: First post>, <Post: Second post>]>
171+
172+
These indexes use 0-based indexing.
173+
8174
``ObjectIdField``
9175
-----------------
10176

0 commit comments

Comments
 (0)