You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
MongoDB collections do not enforce document structure by default, so you have the flexibility to make whatever data-modelling choices best match your application and its performance requirements. So, it's not unusual to create models when working with a MongoDB database.
46
+
47
+
Tutorial
48
+
--------
49
+
26
50
Prerequisites
27
-
-------------
51
+
~~~~~~~~~~~~~
28
52
29
53
- Python v3.9.0 or later
30
54
- A MongoDB Atlas cluster
@@ -33,7 +57,7 @@ Prerequisites
33
57
account and MongoDB cluster.
34
58
35
59
Set-up
36
-
------
60
+
~~~~~~
37
61
38
62
1. Clone the example code from the `mongodb-with-fastapi repository <https://github.com/mongodb-developer/mongodb-with-fastapi>`__:
39
63
@@ -84,7 +108,7 @@ Set-up
84
108
:alt: Screenshot of browser and swagger UI
85
109
86
110
Create Your Application
87
-
-----------------------
111
+
~~~~~~~~~~~~~~~~~~~~~~~
88
112
89
113
All the code for the example application is stored in ``app.py``.
90
114
@@ -107,12 +131,11 @@ The _id Attribute and ObjectIds
107
131
# It will be represented as a `str` on the model so that it can be serialized to JSON.
108
132
PyObjectId = Annotated[str, BeforeValidator(str)]
109
133
110
-
MongoDB stores data as `BSON <https://www.mongodb.com/json-and-bson>`__. FastAPI encodes and decodes data as JSON strings. BSON has support for additional non-JSON-native data types, including ``ObjectId`` which can't be directly encoded as JSON. Because of this, we convert ``ObjectId``s to strings before storing them as the ``id`` field.
134
+
111
135
112
136
Database Models
113
137
~~~~~~~~~~~~~~~
114
-
115
-
Many people think of MongoDB as being schema-less, which is wrong. MongoDB has a flexible schema. That is to say that collections do not enforce document structure by default, so you have the flexibility to make whatever data-modelling choices best match your application and its performance requirements. So, it's not unusual to create models when working with a MongoDB database. Our application has three models, the ``StudentModel``, the ``UpdateStudentModel``, and the ``StudentCollection``.
138
+
Our application has three models, the ``StudentModel``, the ``UpdateStudentModel``, and the ``StudentCollection``.
116
139
117
140
.. code-block:: python
118
141
@@ -122,7 +145,7 @@ Many people think of MongoDB as being schema-less, which is wrong. MongoDB has
122
145
"""
123
146
124
147
# The primary key for the StudentModel, stored as a `str` on the instance.
125
-
# This will be aliased to `_id` when sent to MongoDB,
148
+
# This will be aliased to ``_id`` when sent to MongoDB,
126
149
# but provided as ``id`` in the API requests and responses.
@@ -144,9 +167,9 @@ Many people think of MongoDB as being schema-less, which is wrong. MongoDB has
144
167
145
168
This is the primary model we use as the `response model <https://fastapi.tiangolo.com/tutorial/response-model/>`__ for the majority of our endpoints.
146
169
147
-
I want to draw attention to the ``id`` field on this model. MongoDB uses ``_id``, but in Python, underscores at the start of attributes have special meaning. If you have an attribute on your model that starts with an underscore, `pydantic <https://pydantic-docs.helpmanual.io/>`__—the data validation framework used by FastAPI—will assume that it is a private variable, meaning you will not be able to assign it a value! To get around this, we name the field ``id`` but give it an alias of `_id`. You also need to set `populate_by_name` to `True` in the model's `model_config`
170
+
I want to draw attention to the ``id`` field on this model. MongoDB uses ``_id``, but in Python, underscores at the start of attributes have special meaning. If you have an attribute on your model that starts with an underscore, `pydantic <https://pydantic-docs.helpmanual.io/>`__—the data validation framework used by FastAPI—will assume that it is a private variable, meaning you will not be able to assign it a value! To get around this, we name the field ``id`` but give it an alias of ``_id``. You also need to set ``populate_by_name`` to ``True`` in the model's ``model_config``
148
171
149
-
We set this ``id`` value automatically to `None`, so you do not need to supply it when creating a new student.
172
+
We set this ``id`` value automatically to ``None``, so you do not need to supply it when creating a new student.
150
173
151
174
.. code-block:: python
152
175
@@ -172,12 +195,12 @@ We set this ``id`` value automatically to `None`, so you do not need to supply i
172
195
},
173
196
)
174
197
175
-
The `UpdateStudentModel` has two key differences from the `StudentModel`:
198
+
The ``UpdateStudentModel`` has two key differences from the ``StudentModel``:
176
199
177
200
- It does not have an ``id`` attribute as this cannot be modified.
178
201
- All fields are optional, so you only need to supply the fields you wish to update.
179
202
180
-
Finally, `StudentCollection` is defined to encapsulate a list of `StudentModel` instances. In theory, the endpoint could return a top-level list of StudentModels, but there are some vulnerabilities associated with returning JSON responses with top-level lists.
203
+
Finally, ``StudentCollection`` is defined to encapsulate a list of ``StudentModel`` instances. In theory, the endpoint could return a top-level list of StudentModels, but there are some vulnerabilities associated with returning JSON responses with top-level lists.
181
204
182
205
.. code-block:: python
183
206
@@ -195,11 +218,28 @@ Application Routes
195
218
196
219
Our application has five routes:
197
220
198
-
- POST /students/ - creates a new student.
199
-
- GET /students/ - view a list of all students.
200
-
- GET /students/{id} - view a single student.
201
-
- PUT /students/{id} - update a student.
202
-
- DELETE /students/{id} - delete a student.
221
+
.. list-table::
222
+
:header-rows: 1
223
+
:stub-columns: 1
224
+
:widths: 25,75
225
+
226
+
* - Route
227
+
- Description
228
+
229
+
* - ``POST /students/``
230
+
- Creates a new student
231
+
232
+
* - ``GET /students/``
233
+
- View a list of all students
234
+
235
+
* - ``GET /students/{id}``
236
+
- View a single student
237
+
238
+
* - ``PUT /students/{id}``
239
+
- Update a student
240
+
241
+
* - ``DELETE /students/{id}``
242
+
- Delete a student
203
243
204
244
Create Student Route
205
245
````````````````````
@@ -236,7 +276,7 @@ FastAPI returns an HTTP ``200`` status code by default; but in this instance, a
236
276
Read Routes
237
277
+++++++++++
238
278
239
-
The application has two read routes: one for viewing all students and the other for viewing an individual student.
279
+
The application has two read routes: one for viewing all students, and one for viewing an individual student.
240
280
241
281
.. code-block:: python
242
282
@@ -266,7 +306,7 @@ Motor's ``to_list`` method requires a max document count argument. For this exam
266
306
)
267
307
async def show_student(id: str):
268
308
"""
269
-
Get the record for a specific student, looked up by `id`.
309
+
Get the record for a specific student, looked up by ``id``.
0 commit comments