mirror of
https://github.com/fastapi/fastapi.git
synced 2025-12-28 08:40:21 -05:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3ff504f03f | ||
|
|
eea9ab6106 | ||
|
|
e9e07c41bb | ||
|
|
17a5e18f46 | ||
|
|
9148bd8b6f | ||
|
|
39766d0f96 | ||
|
|
2d9bca56b2 | ||
|
|
f158d95ce9 | ||
|
|
7a4164ef60 | ||
|
|
f3730a79af | ||
|
|
42eff23a79 | ||
|
|
25bc33350d | ||
|
|
b84d082005 | ||
|
|
1f01ce9615 | ||
|
|
352c5f5ecc | ||
|
|
e5594e860f | ||
|
|
50926faead | ||
|
|
a303afc0e5 | ||
|
|
12607e85e3 | ||
|
|
38fd363e89 | ||
|
|
7f62cfd231 | ||
|
|
c5168bd036 | ||
|
|
be472c5215 | ||
|
|
adac38ecea | ||
|
|
c8b634226e | ||
|
|
ca4cf7cc70 |
14
.github/workflows/pr-approvals.yml
vendored
Normal file
14
.github/workflows/pr-approvals.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
name: Label approved pull requests
|
||||
on: pull_request_review
|
||||
jobs:
|
||||
labelWhenApproved:
|
||||
name: Label when approved
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Label when approved
|
||||
uses: pullreminders/label-when-approved-action@v1.0.7
|
||||
env:
|
||||
APPROVALS: "2"
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ADD_LABEL: "approved-2"
|
||||
REMOVE_LABEL: "awaiting%20review"
|
||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -16,3 +16,8 @@ Pipfile.lock
|
||||
env3.*
|
||||
env
|
||||
docs_build
|
||||
venv
|
||||
|
||||
# vim temporary files
|
||||
*~
|
||||
.*.sw?
|
||||
|
||||
18
README.md
18
README.md
@@ -131,6 +131,8 @@ $ pip install uvicorn
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -142,7 +144,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -151,7 +153,9 @@ def read_item(item_id: int, q: str = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -163,7 +167,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -241,7 +245,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -251,7 +257,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -260,7 +266,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -168,7 +168,7 @@ You can use this same `responses` parameter to add different media types for the
|
||||
|
||||
For example, you can add an additional media type of `image/png`, declaring that your *path operation* can return a JSON object (with media type `application/json`) or a PNG image:
|
||||
|
||||
```Python hl_lines="17 18 19 20 21 22 23 24 28"
|
||||
```Python hl_lines="19 20 21 22 23 24 28"
|
||||
{!../../../docs_src/additional_responses/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -228,7 +228,7 @@ You can use that technique to re-use some predefined responses in your *path ope
|
||||
|
||||
For example:
|
||||
|
||||
```Python hl_lines="11 12 13 14 15 24"
|
||||
```Python hl_lines="13 14 15 16 17 26"
|
||||
{!../../../docs_src/additional_responses/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ But you also want it to accept new items. And when the items didn't exist before
|
||||
|
||||
To achieve that, import `JSONResponse`, and return your content there directly, setting the `status_code` that you want:
|
||||
|
||||
```Python hl_lines="2 19"
|
||||
```Python hl_lines="4 23"
|
||||
{!../../../docs_src/additional_status_codes/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ It will have a *path operation* that will receive an `Invoice` body, and a query
|
||||
|
||||
This part is pretty normal, most of the code is probably already familiar to you:
|
||||
|
||||
```Python hl_lines="8 9 10 11 12 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53"
|
||||
```Python hl_lines="10 11 12 13 14 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -92,7 +92,7 @@ Because of that, you need to declare what will be the `default_response_class`,
|
||||
|
||||
But as we are never calling `app.include_router(some_router)`, we need to set the `default_response_class` during creation of the `APIRouter`.
|
||||
|
||||
```Python hl_lines="3 24"
|
||||
```Python hl_lines="5 26"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -105,7 +105,7 @@ It should look just like a normal FastAPI *path operation*:
|
||||
* It should probably have a declaration of the body it should receive, e.g. `body: InvoiceEvent`.
|
||||
* And it could also have a declaration of the response it should return, e.g. `response_model=InvoiceEventReceived`.
|
||||
|
||||
```Python hl_lines="15 16 17 20 21 27 28 29 30 31"
|
||||
```Python hl_lines="17 18 19 22 23 29 30 31 32 33"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -172,7 +172,7 @@ At this point you have the *callback path operation(s)* needed (the one(s) that
|
||||
|
||||
Now use the parameter `callbacks` in *your API's path operation decorator* to pass the attribute `.routes` (that's actually just a `list` of routes/*path operations*) from that callback router:
|
||||
|
||||
```Python hl_lines="34"
|
||||
```Python hl_lines="36"
|
||||
{!../../../docs_src/openapi_callbacks/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ For example, you cannot put a Pydantic model in a `JSONResponse` without first c
|
||||
|
||||
For those cases, you can use the `jsonable_encoder` to convert your data before passing it to a response:
|
||||
|
||||
```Python hl_lines="4 6 20 21"
|
||||
```Python hl_lines="6 7 21 22"
|
||||
{!../../../docs_src/response_directly/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ If you need to have two independent FastAPI applications, with their own indepen
|
||||
|
||||
## Mounting a **FastAPI** application
|
||||
|
||||
"Mounting" means adding a completely "independent" application in a specific path, that then takes care of handling all everything under that path, with the _path operations_ declared in that sub-application.
|
||||
"Mounting" means adding a completely "independent" application in a specific path, that then takes care of handling everything under that path, with the _path operations_ declared in that sub-application.
|
||||
|
||||
### Top-level application
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ To override a dependency for testing, you put as a key the original dependency (
|
||||
|
||||
And then **FastAPI** will call that override instead of the original dependency.
|
||||
|
||||
```Python hl_lines="24 25 28"
|
||||
```Python hl_lines="26 27 30"
|
||||
{!../../../docs_src/dependency_testing/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ In WebSocket endpoints you can import from `fastapi` and use:
|
||||
|
||||
They work the same way as for other FastAPI endpoints/*path operations*:
|
||||
|
||||
```Python hl_lines="56 57 58 59 60 61 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79"
|
||||
```Python hl_lines="58 59 60 61 62 63 64 65 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83"
|
||||
{!../../../docs_src/websockets/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Including WSGI - Flask, Django, others
|
||||
|
||||
You can mount WSGI applications as you saw with [Sub Applications - Behind a Proxy, Mounts](./sub-applications-proxy.md){.internal-link target=_blank}.
|
||||
You can mount WSGI applications as you saw with [Sub Applications - Mounts](./sub-applications.md){.internal-link target=_blank}, [Behind a Proxy](./behind-a-proxy.md){.internal-link target=_blank}.
|
||||
|
||||
For that, you can use the `WSGIMiddleware` and use it to wrap your WSGI application, for example, Flask, Django, etc.
|
||||
|
||||
|
||||
@@ -161,6 +161,8 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
* Create a `main.py` file with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -172,7 +174,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -131,6 +131,8 @@ $ pip install uvicorn
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -142,7 +144,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -151,7 +153,9 @@ def read_item(item_id: int, q: str = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -163,7 +167,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -241,7 +245,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -251,7 +257,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -260,7 +266,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,21 @@
|
||||
|
||||
## Latest changes
|
||||
|
||||
## 0.58.1
|
||||
|
||||
* Add link in docs to Pydantic data types. PR [#1612](https://github.com/tiangolo/fastapi/pull/1612) by [@tayoogunbiyi](https://github.com/tayoogunbiyi).
|
||||
* Fix link in warning logs for `openapi_prefix`. PR [#1611](https://github.com/tiangolo/fastapi/pull/1611) by [@bavaria95](https://github.com/bavaria95).
|
||||
* Fix bad link in docs. PR [#1603](https://github.com/tiangolo/fastapi/pull/1603) by [@molto0504](https://github.com/molto0504).
|
||||
* Add Vim temporary files to `.gitignore` for contributors using Vim. PR [#1590](https://github.com/tiangolo/fastapi/pull/1590) by [@asheux](https://github.com/asheux).
|
||||
* Fix typo in docs for sub-applications. PR [#1578](https://github.com/tiangolo/fastapi/pull/1578) by [@schlpbch](https://github.com/schlpbch).
|
||||
* Use `Optional` in all the examples in the docs. Original PR [#1574](https://github.com/tiangolo/fastapi/pull/1574) by [@chrisngyn](https://github.com/chrisngyn), [@kx-chen](https://github.com/kx-chen), [@YKo20010](https://github.com/YKo20010). Updated and merged PR [#1644](https://github.com/tiangolo/fastapi/pull/1644).
|
||||
* Update tests and handling of `response_model_by_alias`. PR [#1642](https://github.com/tiangolo/fastapi/pull/1642).
|
||||
* Add translation to Chinese for [Body - Fields - 请求体 - 字段](https://fastapi.tiangolo.com/zh/tutorial/body-fields/). PR [#1569](https://github.com/tiangolo/fastapi/pull/1569) by [@waynerv](https://github.com/waynerv).
|
||||
* Update Chinese translation of main page. PR [#1564](https://github.com/tiangolo/fastapi/pull/1564) by [@waynerv](https://github.com/waynerv).
|
||||
* Add translation to Chinese for [Body - Multiple Parameters - 请求体 - 多个参数](https://fastapi.tiangolo.com/zh/tutorial/body-multiple-params/). PR [#1532](https://github.com/tiangolo/fastapi/pull/1532) by [@waynerv](https://github.com/waynerv).
|
||||
* Add translation to Chinese for [Path Parameters and Numeric Validations - 路径参数和数值校验](https://fastapi.tiangolo.com/zh/tutorial/path-params-numeric-validations/). PR [#1506](https://github.com/tiangolo/fastapi/pull/1506) by [@waynerv](https://github.com/waynerv).
|
||||
* Add GitHub action to auto-label approved PRs (mainly for translations). PR [#1638](https://github.com/tiangolo/fastapi/pull/1638).
|
||||
|
||||
## 0.58.0
|
||||
|
||||
* Deep merge OpenAPI responses to preserve all the additional metadata. PR [#1577](https://github.com/tiangolo/fastapi/pull/1577).
|
||||
|
||||
@@ -57,7 +57,7 @@ Using `BackgroundTasks` also works with the dependency injection system, you can
|
||||
|
||||
**FastAPI** knows what to do in each case and how to re-use the same object, so that all the background tasks are merged together and are run in the background afterwards:
|
||||
|
||||
```Python hl_lines="11 14 20 23"
|
||||
```Python hl_lines="13 15 22 25"
|
||||
{!../../../docs_src/background_tasks/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ The same way you can declare additional validation and metadata in *path operati
|
||||
|
||||
First, you have to import it:
|
||||
|
||||
```Python hl_lines="2"
|
||||
```Python hl_lines="4"
|
||||
{!../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ First, you have to import it:
|
||||
|
||||
You can then use `Field` with model attributes:
|
||||
|
||||
```Python hl_lines="9 10"
|
||||
```Python hl_lines="11 12 13 14"
|
||||
{!../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ First, of course, you can mix `Path`, `Query` and request body parameter declara
|
||||
|
||||
And you can also declare body parameters as optional, by setting the default to `None`:
|
||||
|
||||
```Python hl_lines="17 18 19"
|
||||
```Python hl_lines="19 20 21"
|
||||
{!../../../docs_src/body_multiple_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -30,7 +30,7 @@ In the previous example, the *path operations* would expect a JSON body with the
|
||||
|
||||
But you can also declare multiple body parameters, e.g. `item` and `user`:
|
||||
|
||||
```Python hl_lines="20"
|
||||
```Python hl_lines="22"
|
||||
{!../../../docs_src/body_multiple_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -72,7 +72,7 @@ If you declare it as is, because it is a singular value, **FastAPI** will assume
|
||||
But you can instruct **FastAPI** to treat it as another body key using `Body`:
|
||||
|
||||
|
||||
```Python hl_lines="21"
|
||||
```Python hl_lines="23"
|
||||
{!../../../docs_src/body_multiple_params/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -104,12 +104,12 @@ Of course, you can also declare additional query parameters whenever you need, a
|
||||
As, by default, singular values are interpreted as query parameters, you don't have to explicitly add a `Query`, you can just do:
|
||||
|
||||
```Python
|
||||
q: str = None
|
||||
q: Optional[str] = None
|
||||
```
|
||||
|
||||
as in:
|
||||
|
||||
```Python hl_lines="25"
|
||||
```Python hl_lines="27"
|
||||
{!../../../docs_src/body_multiple_params/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -131,7 +131,7 @@ item: Item = Body(..., embed=True)
|
||||
|
||||
as in:
|
||||
|
||||
```Python hl_lines="15"
|
||||
```Python hl_lines="17"
|
||||
{!../../../docs_src/body_multiple_params/tutorial005.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,15 +6,15 @@ With **FastAPI**, you can define, validate, document, and use arbitrarily deeply
|
||||
|
||||
You can define an attribute to be a subtype. For example, a Python `list`:
|
||||
|
||||
```Python hl_lines="12"
|
||||
```Python hl_lines="14"
|
||||
{!../../../docs_src/body_nested_models/tutorial001.py!}
|
||||
```
|
||||
|
||||
This will make `tags` be a list of items. Although it doesn't declare the type of each of the items.
|
||||
|
||||
## List fields with subtype
|
||||
## List fields with type parameter
|
||||
|
||||
But Python has a specific way to declare lists with subtypes:
|
||||
But Python has a specific way to declare lists with internal types, or "type parameters":
|
||||
|
||||
### Import typing's `List`
|
||||
|
||||
@@ -24,12 +24,12 @@ First, import `List` from standard Python's `typing` module:
|
||||
{!../../../docs_src/body_nested_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
### Declare a `List` with a subtype
|
||||
### Declare a `List` with a type parameter
|
||||
|
||||
To declare types that have subtypes, like `list`, `dict`, `tuple`:
|
||||
To declare types that have type parameters (internal types), like `list`, `dict`, `tuple`:
|
||||
|
||||
* Import them from the `typing` module
|
||||
* Pass the subtype(s) as "type arguments" using square brackets: `[` and `]`
|
||||
* Pass the internal type(s) as "type parameters" using square brackets: `[` and `]`
|
||||
|
||||
```Python
|
||||
from typing import List
|
||||
@@ -39,7 +39,7 @@ my_list: List[str]
|
||||
|
||||
That's all standard Python syntax for type declarations.
|
||||
|
||||
Use that same standard syntax for model attributes with subtypes.
|
||||
Use that same standard syntax for model attributes with internal types.
|
||||
|
||||
So, in our example, we can make `tags` be specifically a "list of strings":
|
||||
|
||||
@@ -71,7 +71,7 @@ Each attribute of a Pydantic model has a type.
|
||||
|
||||
But that type can itself be another Pydantic model.
|
||||
|
||||
So, you can declare deeply nested JSON `object`s with specific attribute names, types and validations.
|
||||
So, you can declare deeply nested JSON "objects" with specific attribute names, types and validations.
|
||||
|
||||
All that, arbitrarily nested.
|
||||
|
||||
@@ -174,7 +174,7 @@ You can define arbitrarily deeply nested models:
|
||||
```
|
||||
|
||||
!!! info
|
||||
Notice how `Offer` as a list of `Item`s, which in turn have an optional list of `Image`s
|
||||
Notice how `Offer` has a list of `Item`s, which in turn have an optional list of `Image`s
|
||||
|
||||
## Bodies of pure lists
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ To declare a **request** body, you use <a href="https://pydantic-docs.helpmanual
|
||||
|
||||
First, you need to import `BaseModel` from `pydantic`:
|
||||
|
||||
```Python hl_lines="2"
|
||||
```Python hl_lines="4"
|
||||
{!../../../docs_src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -27,7 +27,7 @@ Then you declare your data model as a class that inherits from `BaseModel`.
|
||||
|
||||
Use standard Python types for all the attributes:
|
||||
|
||||
```Python hl_lines="5 6 7 8 9"
|
||||
```Python hl_lines="7 8 9 10 11"
|
||||
{!../../../docs_src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -57,7 +57,7 @@ For example, this model above declares a JSON "`object`" (or Python `dict`) like
|
||||
|
||||
To add it to your *path operation*, declare it the same way you declared path and query parameters:
|
||||
|
||||
```Python hl_lines="16"
|
||||
```Python hl_lines="18"
|
||||
{!../../../docs_src/body/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -123,7 +123,7 @@ But you would get the same editor support with <a href="https://www.jetbrains.co
|
||||
|
||||
Inside of the function, you can access all the attributes of the model object directly:
|
||||
|
||||
```Python hl_lines="19"
|
||||
```Python hl_lines="21"
|
||||
{!../../../docs_src/body/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -133,7 +133,7 @@ You can declare path parameters and body requests at the same time.
|
||||
|
||||
**FastAPI** will recognize that the function parameters that match path parameters should be **taken from the path**, and that function parameters that are declared to be Pydantic models should be **taken from the request body**.
|
||||
|
||||
```Python hl_lines="15 16"
|
||||
```Python hl_lines="17 18"
|
||||
{!../../../docs_src/body/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -143,7 +143,7 @@ You can also declare **body**, **path** and **query** parameters, all at the sam
|
||||
|
||||
**FastAPI** will recognize each of them and take the data from the correct place.
|
||||
|
||||
```Python hl_lines="16"
|
||||
```Python hl_lines="18"
|
||||
{!../../../docs_src/body/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -153,6 +153,11 @@ The function parameters will be recognized as follows:
|
||||
* If the parameter is of a **singular type** (like `int`, `float`, `str`, `bool`, etc) it will be interpreted as a **query** parameter.
|
||||
* If the parameter is declared to be of the type of a **Pydantic model**, it will be interpreted as a request **body**.
|
||||
|
||||
!!! note
|
||||
FastAPI will know that the value of `q` is not required because of the default value `= None`.
|
||||
|
||||
The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
|
||||
|
||||
## Without Pydantic
|
||||
|
||||
If you don't want to use Pydantic models, you can also use **Body** parameters. See the docs for [Body - Multiple Parameters: Singular values in body](body-multiple-params.md#singular-values-in-body){.internal-link target=_blank}.
|
||||
|
||||
@@ -6,7 +6,7 @@ You can define Cookie parameters the same way you define `Query` and `Path` para
|
||||
|
||||
First import `Cookie`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/cookie_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ Then declare the cookie parameters using the same structure as with `Path` and `
|
||||
|
||||
The first value is the default value, you can pass all the extra validation or annotation parameters:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/cookie_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Before diving deeper into the **Dependency Injection** system, let's upgrade the
|
||||
|
||||
In the previous example, we were returning a `dict` from our dependency ("dependable"):
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -71,19 +71,19 @@ That also applies to callables with no parameters at all. The same as it would b
|
||||
|
||||
Then, we can change the dependency "dependable" `common_parameters` from above to the class `CommonQueryParameters`:
|
||||
|
||||
```Python hl_lines="9 10 11 12 13"
|
||||
```Python hl_lines="11 12 13 14 15"
|
||||
{!../../../docs_src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
Pay attention to the `__init__` method used to create the instance of the class:
|
||||
|
||||
```Python hl_lines="10"
|
||||
```Python hl_lines="12"
|
||||
{!../../../docs_src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
...it has the same parameters as our previous `common_parameters`:
|
||||
|
||||
```Python hl_lines="6"
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -103,7 +103,7 @@ Now you can declare your dependency using this class.
|
||||
|
||||
And as when **FastAPI** calls that class the value that will be passed as `commons` to your function will be an "instance" of the class, you can declare that parameter `commons` to be of type of the class, `CommonQueryParams`.
|
||||
|
||||
```Python hl_lines="17"
|
||||
```Python hl_lines="19"
|
||||
{!../../../docs_src/dependencies/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -143,7 +143,7 @@ commons = Depends(CommonQueryParams)
|
||||
|
||||
..as in:
|
||||
|
||||
```Python hl_lines="17"
|
||||
```Python hl_lines="19"
|
||||
{!../../../docs_src/dependencies/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -179,7 +179,7 @@ So, you can declare the dependency as the type of the variable, and use `Depends
|
||||
|
||||
So, the same example would look like:
|
||||
|
||||
```Python hl_lines="17"
|
||||
```Python hl_lines="19"
|
||||
{!../../../docs_src/dependencies/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ Let's first focus on the dependency.
|
||||
|
||||
It is just a function that can take all the same parameters that a *path operation function* can take:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
```Python hl_lines="8 9"
|
||||
{!../../../docs_src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -55,7 +55,7 @@ And then it just returns a `dict` containing those values.
|
||||
|
||||
### Import `Depends`
|
||||
|
||||
```Python hl_lines="1"
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -63,7 +63,7 @@ And then it just returns a `dict` containing those values.
|
||||
|
||||
The same way you use `Body`, `Query`, etc. with your *path operation function* parameters, use `Depends` with a new parameter:
|
||||
|
||||
```Python hl_lines="11 16"
|
||||
```Python hl_lines="13 18"
|
||||
{!../../../docs_src/dependencies/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ They can be as **deep** as you need them to be.
|
||||
|
||||
You could create a first dependency ("dependable") like:
|
||||
|
||||
```Python hl_lines="6 7"
|
||||
```Python hl_lines="8 9"
|
||||
{!../../../docs_src/dependencies/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -22,7 +22,7 @@ This is quite simple (not very useful), but will help us focus on how the sub-de
|
||||
|
||||
Then you can create another dependency function (a "dependable") that at the same time declares a dependency of its own (so it is a "dependant" too):
|
||||
|
||||
```Python hl_lines="11"
|
||||
```Python hl_lines="13"
|
||||
{!../../../docs_src/dependencies/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -37,7 +37,7 @@ Let's focus on the parameters declared:
|
||||
|
||||
Then we can use the dependency with:
|
||||
|
||||
```Python hl_lines="19"
|
||||
```Python hl_lines="21"
|
||||
{!../../../docs_src/dependencies/tutorial005.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ You can use `jsonable_encoder` for that.
|
||||
|
||||
It receives an object, like a Pydantic model, and returns a JSON compatible version:
|
||||
|
||||
```Python hl_lines="4 21"
|
||||
```Python hl_lines="5 22"
|
||||
{!../../../docs_src/encoder/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -49,17 +49,18 @@ Here are some of the additional data types you can use:
|
||||
* `Decimal`:
|
||||
* Standard Python `Decimal`.
|
||||
* In requests and responses, handled the same as a `float`.
|
||||
* You can check all the valid pydantic data types here: <a href="https://pydantic-docs.helpmanual.io/usage/types" class="external-link" target="_blank">Pydantic data types</a>.
|
||||
|
||||
## Example
|
||||
|
||||
Here's an example *path operation* with parameters using some of the above types.
|
||||
|
||||
```Python hl_lines="1 2 11 12 13 14 15"
|
||||
```Python hl_lines="1 3 12 13 14 15 16"
|
||||
{!../../../docs_src/extra_data_types/tutorial001.py!}
|
||||
```
|
||||
|
||||
Note that the parameters inside the function have their natural data type, and you can, for example, perform normal date manipulations, like:
|
||||
|
||||
```Python hl_lines="17 18"
|
||||
```Python hl_lines="18 19"
|
||||
{!../../../docs_src/extra_data_types/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ This is especially the case for user models, because:
|
||||
|
||||
Here's a general idea of how the models could look like with their password fields and the places where they are used:
|
||||
|
||||
```Python hl_lines="7 9 14 20 22 27 28 31 32 33 38 39"
|
||||
```Python hl_lines="9 11 16 22 24 29 30 33 34 35 40 41"
|
||||
{!../../../docs_src/extra_models/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -150,7 +150,7 @@ All the data conversion, validation, documentation, etc. will still work as norm
|
||||
|
||||
That way, we can declare just the differences between the models (with plaintext `password`, with `hashed_password` and without password):
|
||||
|
||||
```Python hl_lines="7 13 14 17 18 21 22"
|
||||
```Python hl_lines="9 15 16 19 20 23 24"
|
||||
{!../../../docs_src/extra_models/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ Now try sending an invalid item like:
|
||||
|
||||
You will receive a response telling you that the data is invalid containing the received body:
|
||||
|
||||
```JSON hl_lines="13 14 15 16"
|
||||
```JSON hl_lines="12 13 14 15"
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
|
||||
@@ -6,7 +6,7 @@ You can define Header parameters the same way you define `Query`, `Path` and `Co
|
||||
|
||||
First import `Header`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/header_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ Then declare the header parameters using the same structure as with `Path`, `Que
|
||||
|
||||
The first value is the default value, you can pass all the extra validation or annotation parameters:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/header_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -44,7 +44,7 @@ So, you can use `user_agent` as you normally would in Python code, instead of ne
|
||||
|
||||
If for some reason you need to disable automatic conversion of underscores to hyphens, set the parameter `convert_underscores` of `Header` to `False`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="10"
|
||||
{!../../../docs_src/header_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ The same way you can declare more validations and metadata for query parameters
|
||||
|
||||
First, import `Path` from `fastapi`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -16,7 +16,7 @@ You can declare all the same parameters as for `Query`.
|
||||
|
||||
For example, to declare a `title` metadata value for the path parameter `item_id` you can type:
|
||||
|
||||
```Python hl_lines="8"
|
||||
```Python hl_lines="10"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -4,11 +4,16 @@
|
||||
|
||||
Let's take this application as example:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
The query parameter `q` is of type `str`, and by default is `None`, so it is optional.
|
||||
The query parameter `q` is of type `Optional[str]`, that means that it's of type `str` but could also be `None`, and indeed, the default value is `None`, so FastAPI will know it's not required.
|
||||
|
||||
!!! note
|
||||
FastAPI will know that the value of `q` is not required because of the default value `= None`.
|
||||
|
||||
The `Optional` in `Optional[str]` is not used by FastAPI, but will allow your editor to give you better support and detect errors.
|
||||
|
||||
## Additional validation
|
||||
|
||||
@@ -18,7 +23,7 @@ We are going to enforce that even though `q` is optional, whenever it is provide
|
||||
|
||||
To achieve that, first import `Query` from `fastapi`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
```Python hl_lines="3"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -26,7 +31,7 @@ To achieve that, first import `Query` from `fastapi`:
|
||||
|
||||
And now use it as the default value of your parameter, setting the parameter `max_length` to 50:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -35,18 +40,35 @@ As we have to replace the default value `None` with `Query(None)`, the first par
|
||||
So:
|
||||
|
||||
```Python
|
||||
q: str = Query(None)
|
||||
q: Optional[str] = Query(None)
|
||||
```
|
||||
|
||||
...makes the parameter optional, the same as:
|
||||
|
||||
```Python
|
||||
q: str = None
|
||||
q: Optional[str] = None
|
||||
```
|
||||
|
||||
But it declares it explicitly as being a query parameter.
|
||||
|
||||
And then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:
|
||||
!!! info
|
||||
Have in mind that FastAPI cares about the part:
|
||||
|
||||
```Python
|
||||
= None
|
||||
```
|
||||
|
||||
or the:
|
||||
|
||||
```Python
|
||||
= Query(None)
|
||||
```
|
||||
|
||||
and will use that `None` to detect that the query parameter is not required.
|
||||
|
||||
The `Optional` part is only to allow your editor to provide better support.
|
||||
|
||||
Then, we can pass more parameters to `Query`. In this case, the `max_length` parameter that applies to strings:
|
||||
|
||||
```Python
|
||||
q: str = Query(None, max_length=50)
|
||||
@@ -58,7 +80,7 @@ This will validate the data, show a clear error when the data is not valid, and
|
||||
|
||||
You can also add a parameter `min_length`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -66,7 +88,7 @@ You can also add a parameter `min_length`:
|
||||
|
||||
You can define a <abbr title="A regular expression, regex or regexp is a sequence of characters that define a search pattern for strings.">regular expression</abbr> that the parameter should match:
|
||||
|
||||
```Python hl_lines="8"
|
||||
```Python hl_lines="10"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -104,13 +126,13 @@ q: str
|
||||
instead of:
|
||||
|
||||
```Python
|
||||
q: str = None
|
||||
q: Optional[str] = None
|
||||
```
|
||||
|
||||
But we are now declaring it with `Query`, for example like:
|
||||
|
||||
```Python
|
||||
q: str = Query(None, min_length=3)
|
||||
q: Optional[str] = Query(None, min_length=3)
|
||||
```
|
||||
|
||||
So, when you need to declare a value as required while using `Query`, you can use `...` as the first argument:
|
||||
@@ -211,13 +233,13 @@ That information will be included in the generated OpenAPI and used by the docum
|
||||
|
||||
You can add a `title`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="10"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial007.py!}
|
||||
```
|
||||
|
||||
And a `description`:
|
||||
|
||||
```Python hl_lines="11"
|
||||
```Python hl_lines="13"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial008.py!}
|
||||
```
|
||||
|
||||
@@ -239,7 +261,7 @@ But you still need it to be exactly `item-query`...
|
||||
|
||||
Then you can declare an `alias`, and that alias is what will be used to find the parameter value:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial009.py!}
|
||||
```
|
||||
|
||||
@@ -251,7 +273,7 @@ You have to leave it there a while because there are clients using it, but you w
|
||||
|
||||
Then pass the parameter `deprecated=True` to `Query`:
|
||||
|
||||
```Python hl_lines="16"
|
||||
```Python hl_lines="18"
|
||||
{!../../../docs_src/query_params_str_validations/tutorial010.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ The parameter values in your function will be:
|
||||
|
||||
The same way, you can declare optional query parameters, by setting their default to `None`:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -72,11 +72,16 @@ In this case, the function parameter `q` will be optional, and will be `None` by
|
||||
!!! check
|
||||
Also notice that **FastAPI** is smart enough to notice that the path parameter `item_id` is a path parameter and `q` is not, so, it's a query parameter.
|
||||
|
||||
!!! note
|
||||
FastAPI will know that `q` is optional because of the `= None`.
|
||||
|
||||
The `Optional` in `Optional[str]` is not used by FastAPI (FastAPI will only use the `str` part), but the `Optional[str]` will let your editor help you finding errors in your code.
|
||||
|
||||
## Query parameter type conversion
|
||||
|
||||
You can also declare `bool` types, and they will be converted:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -121,7 +126,7 @@ And you don't have to declare them in any specific order.
|
||||
|
||||
They will be detected by name:
|
||||
|
||||
```Python hl_lines="6 8"
|
||||
```Python hl_lines="8 10"
|
||||
{!../../../docs_src/query_params/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -179,7 +184,7 @@ http://127.0.0.1:8000/items/foo-item?needy=sooooneedy
|
||||
|
||||
And of course, you can define some parameters as required, some as having a default value, and some entirely optional:
|
||||
|
||||
```Python hl_lines="7"
|
||||
```Python hl_lines="10"
|
||||
{!../../../docs_src/query_params/tutorial006.py!}
|
||||
```
|
||||
|
||||
@@ -191,36 +196,3 @@ In this case, there are 3 query parameters:
|
||||
|
||||
!!! tip
|
||||
You could also use `Enum`s the same way as with [Path Parameters](path-params.md#predefined-values){.internal-link target=_blank}.
|
||||
|
||||
## Optional type declarations
|
||||
|
||||
!!! warning
|
||||
This might be an advanced use case.
|
||||
|
||||
You might want to skip it.
|
||||
|
||||
If you are using `mypy` it could complain with type declarations like:
|
||||
|
||||
```Python
|
||||
limit: int = None
|
||||
```
|
||||
|
||||
With an error like:
|
||||
|
||||
```
|
||||
Incompatible types in assignment (expression has type "None", variable has type "int")
|
||||
```
|
||||
|
||||
In those cases you can use `Optional` to tell `mypy` that the value could be `None`, like:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
limit: Optional[int] = None
|
||||
```
|
||||
|
||||
In a *path operation* that could look like:
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/query_params/tutorial007.py!}
|
||||
```
|
||||
|
||||
@@ -35,13 +35,13 @@ But most importantly:
|
||||
|
||||
Here we are declaring a `UserIn` model, it will contain a plaintext password:
|
||||
|
||||
```Python hl_lines="7 9"
|
||||
```Python hl_lines="9 11"
|
||||
{!../../../docs_src/response_model/tutorial002.py!}
|
||||
```
|
||||
|
||||
And we are using this model to declare our input and the same model to declare our output:
|
||||
|
||||
```Python hl_lines="15 16"
|
||||
```Python hl_lines="17 18"
|
||||
{!../../../docs_src/response_model/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -58,19 +58,19 @@ But if we use the same model for another *path operation*, we could be sending o
|
||||
|
||||
We can instead create an input model with the plaintext password and an output model without it:
|
||||
|
||||
```Python hl_lines="7 9 14"
|
||||
```Python hl_lines="9 11 16"
|
||||
{!../../../docs_src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
Here, even though our *path operation function* is returning the same input user that contains the password:
|
||||
|
||||
```Python hl_lines="22"
|
||||
```Python hl_lines="24"
|
||||
{!../../../docs_src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
...we declared the `response_model` to be our model `UserOut`, that doesn't include the password:
|
||||
|
||||
```Python hl_lines="20"
|
||||
```Python hl_lines="22"
|
||||
{!../../../docs_src/response_model/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -94,9 +94,9 @@ Your response model could have default values, like:
|
||||
{!../../../docs_src/response_model/tutorial004.py!}
|
||||
```
|
||||
|
||||
* `description: str = None` has a default of `None`.
|
||||
* `description: Optional[str] = None` has a default of `None`.
|
||||
* `tax: float = 10.5` has a default of `10.5`.
|
||||
* `tags: List[str] = []` has a default of an empty list: `[]`.
|
||||
* `tags: List[str] = []` as a default of an empty list: `[]`.
|
||||
|
||||
but you might want to omit them from the result if they were not actually stored.
|
||||
|
||||
@@ -183,7 +183,9 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan
|
||||
|
||||
This is because the JSON Schema generated in your app's OpenAPI (and the docs) will still be the one for the complete model, even if you use `response_model_include` or `response_model_exclude` to omit some attributes.
|
||||
|
||||
```Python hl_lines="29 35"
|
||||
This also applies to `response_model_by_alias` that works similarly.
|
||||
|
||||
```Python hl_lines="31 37"
|
||||
{!../../../docs_src/response_model/tutorial005.py!}
|
||||
```
|
||||
|
||||
@@ -196,7 +198,7 @@ This can be used as a quick shortcut if you have only one Pydantic model and wan
|
||||
|
||||
If you forget to use a `set` and use a `list` or `tuple` instead, FastAPI will still convert it to a `set` and it will work correctly:
|
||||
|
||||
```Python hl_lines="29 35"
|
||||
```Python hl_lines="31 37"
|
||||
{!../../../docs_src/response_model/tutorial006.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ There are several ways you can declare extra JSON Schema information.
|
||||
|
||||
You can declare an example for a Pydantic model using `Config` and `schema_extra`, as described in <a href="https://pydantic-docs.helpmanual.io/usage/schema/#schema-customization" class="external-link" target="_blank">Pydantic's docs: Schema customization</a>:
|
||||
|
||||
```Python hl_lines="13 14 15 16 17 18 19 20 21"
|
||||
```Python hl_lines="15 16 17 18 19 20 21 22 23"
|
||||
{!../../../docs_src/schema_extra_example/tutorial001.py!}
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ That extra info will be added as-is to the output JSON Schema.
|
||||
|
||||
In `Field`, `Path`, `Query`, `Body` and others you'll see later, you can also declare extra info for the JSON Schema by passing any other arbitrary arguments to the function, for example, to add an `example`:
|
||||
|
||||
```Python hl_lines="2 8 9 10 11"
|
||||
```Python hl_lines="4 10 11 12 13"
|
||||
{!../../../docs_src/schema_extra_example/tutorial002.py!}
|
||||
```
|
||||
|
||||
@@ -33,7 +33,7 @@ The same way you can pass extra info to `Field`, you can do the same with `Path`
|
||||
|
||||
For example, you can pass an `example` for a body request to `Body`:
|
||||
|
||||
```Python hl_lines="19 20 21 22 23 24"
|
||||
```Python hl_lines="21 22 23 24 25 26"
|
||||
{!../../../docs_src/schema_extra_example/tutorial003.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ And another utility to verify if a received password matches the hash stored.
|
||||
|
||||
And another one to authenticate and return a user.
|
||||
|
||||
```Python hl_lines="7 48 55 56 59 60 69 70 71 72 73 74 75"
|
||||
```Python hl_lines="8 49 56 57 60 61 70 71 72 73 74 75 76"
|
||||
{!../../../docs_src/security/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -135,7 +135,7 @@ Define a Pydantic Model that will be used in the token endpoint for the response
|
||||
|
||||
Create a utility function to generate a new access token.
|
||||
|
||||
```Python hl_lines="3 6 12 13 14 28 29 30 78 79 80 81 82 83 84 85 86"
|
||||
```Python hl_lines="4 7 13 14 15 29 30 31 79 80 81 82 83 84 85 86 87"
|
||||
{!../../../docs_src/security/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -147,7 +147,7 @@ Decode the received token, verify it, and return the current user.
|
||||
|
||||
If the token is invalid, return an HTTP error right away.
|
||||
|
||||
```Python hl_lines="89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106"
|
||||
```Python hl_lines="90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107"
|
||||
{!../../../docs_src/security/tutorial004.py!}
|
||||
```
|
||||
|
||||
@@ -157,7 +157,7 @@ Create a `timedelta` with the expiration time of the token.
|
||||
|
||||
Create a real JWT access token and return it.
|
||||
|
||||
```Python hl_lines="115 116 117 118 119 120 121 122 123 124 125 126 127 128"
|
||||
```Python hl_lines="116 117 118 119 120 121 122 123 124 125 126 127 128 129"
|
||||
{!../../../docs_src/security/tutorial004.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ Now let's use the utilities provided by **FastAPI** to handle this.
|
||||
|
||||
First, import `OAuth2PasswordRequestForm`, and use it as a dependency with `Depends` for the path `/token`:
|
||||
|
||||
```Python hl_lines="2 74"
|
||||
```Python hl_lines="4 76"
|
||||
{!../../../docs_src/security/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -90,7 +90,7 @@ If there is no such user, we return an error saying "incorrect username or passw
|
||||
|
||||
For the error, we use the exception `HTTPException`:
|
||||
|
||||
```Python hl_lines="1 75 76 77"
|
||||
```Python hl_lines="3 77 78 79"
|
||||
{!../../../docs_src/security/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -118,7 +118,7 @@ If your database is stolen, the thief won't have your users' plaintext passwords
|
||||
|
||||
So, the thief won't be able to try to use those same passwords in another system (as many users use the same password everywhere, this would be dangerous).
|
||||
|
||||
```Python hl_lines="78 79 80 81"
|
||||
```Python hl_lines="80 81 82 83"
|
||||
{!../../../docs_src/security/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -156,7 +156,7 @@ For this simple example, we are going to just be completely insecure and return
|
||||
|
||||
But for now, let's focus on the specific details we need.
|
||||
|
||||
```Python hl_lines="83"
|
||||
```Python hl_lines="85"
|
||||
{!../../../docs_src/security/tutorial003.py!}
|
||||
```
|
||||
|
||||
@@ -181,7 +181,7 @@ Both of these dependencies will just return an HTTP error if the user doesn't ex
|
||||
|
||||
So, in our endpoint, we will only get a user if the user exists, was correctly authenticated, and is active:
|
||||
|
||||
```Python hl_lines="56 57 58 59 60 61 62 63 64 65 67 68 69 70 88"
|
||||
```Python hl_lines="58 59 60 61 62 63 64 65 66 67 69 70 71 72 90"
|
||||
{!../../../docs_src/security/tutorial003.py!}
|
||||
```
|
||||
|
||||
|
||||
@@ -131,6 +131,7 @@ $ pip install uvicorn
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -141,7 +142,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -152,6 +153,7 @@ Si tu código usa `async` / `await`, usa `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -162,7 +164,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -243,6 +245,7 @@ Declara el body usando las declaraciones de tipo estándares de Python gracias a
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -250,7 +253,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -259,7 +262,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -136,6 +136,7 @@ $ pip install uvicorn
|
||||
|
||||
```Python
|
||||
from fastapi import FastAPI
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -146,7 +147,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: str = Optional[None]):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -157,6 +158,7 @@ If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -167,7 +169,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -248,6 +250,7 @@ Declare the body using standard Python types, thanks to Pydantic.
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -255,7 +258,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: bool = Optional[None]
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -264,7 +267,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -124,6 +124,8 @@ $ pip install uvicorn
|
||||
* Crie um arquivo `main.py` com:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -135,7 +137,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -144,7 +146,9 @@ def read_item(item_id: int, q: str = None):
|
||||
|
||||
Se seu código utiliza `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -156,7 +160,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -234,7 +238,7 @@ Agora modifique o arquivo `main.py` para receber um corpo para uma requisição
|
||||
|
||||
Declare o corpo utilizando tipos padrão Python, graças ao Pydantic.
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -244,7 +248,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -253,7 +257,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -135,6 +135,8 @@ $ pip install uvicorn
|
||||
* Create a file `main.py` with:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -146,7 +148,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -155,7 +157,9 @@ def read_item(item_id: int, q: str = None):
|
||||
|
||||
If your code uses `async` / `await`, use `async def`:
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -167,7 +171,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -245,7 +249,9 @@ Now modify the file `main.py` to receive a body from a `PUT` request.
|
||||
|
||||
Declare the body using standard Python types, thanks to Pydantic.
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -255,7 +261,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -264,7 +270,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
|
||||
@@ -162,6 +162,8 @@ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "80"]
|
||||
* 创建一个 `main.py` 文件,内容如下:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -173,7 +175,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<a href="https://fastapi.tiangolo.com"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" alt="FastAPI"></a>
|
||||
</p>
|
||||
<p align="center">
|
||||
<em>FastAPI framework, high performance, easy to learn, fast to code, ready for production</em>
|
||||
<em>FastAPI 框架,高性能,易于学习,高效编码,生产可用</em>
|
||||
</p>
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.com/tiangolo/fastapi" target="_blank">
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
---
|
||||
|
||||
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用基于类型提示的 Python 3.6 及更高版本。
|
||||
FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框架,使用 Python 3.6+ 并基于标准的 Python 类型提示。
|
||||
|
||||
关键特性:
|
||||
|
||||
@@ -36,54 +36,60 @@ FastAPI 是一个用于构建 API 的现代、快速(高性能)的 web 框
|
||||
* **高效编码**:提高功能开发速度约 200% 至 300%。*
|
||||
* **更少 bug**:减少约 40% 的人为(开发者)导致错误。*
|
||||
* **智能**:极佳的编辑器支持。处处皆可<abbr title="也被称为自动完成、智能感知">自动补全</abbr>,减少调试时间。
|
||||
* **简单**:设计的易于使用和学习,减少阅读文档时间。
|
||||
* **简短**:减少代码重复。通过不同的参数声明实现丰富功能。bug 更少。
|
||||
* **健壮**:生产可用级别的代码。以及自动生成的交互式文档。
|
||||
* **标准化**:基于 API 的相关开放标准并完全兼容:<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (以前被称为 Swagger) 和 <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>。
|
||||
* **简单**:设计的易于使用和学习,阅读文档的时间更短。
|
||||
* **简短**:使代码重复最小化。通过不同的参数声明实现丰富功能。bug 更少。
|
||||
* **健壮**:生产可用级别的代码。还有自动生成的交互式文档。
|
||||
* **标准化**:基于(并完全兼容)API 的相关开放标准:<a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank">OpenAPI</a> (以前被称为 Swagger) 和 <a href="http://json-schema.org/" class="external-link" target="_blank">JSON Schema</a>。
|
||||
|
||||
<small>* 根据对某个构建线上应用的内部开发团队所进行的测试估算得出。</small>
|
||||
|
||||
## 评价
|
||||
|
||||
"*[...] 最近我一直在使用 **FastAPI**。[...] 实际上我正在计划将其用于我所在的微软团队的所有**机器学习服务**。其中一些服务正被集成进 **Windows** 核心产品和一些 **Office** 产品。*"
|
||||
「_[...] 最近我一直在使用 **FastAPI**。[...] 实际上我正在计划将其用于我所在的**微软**团队的所有**机器学习服务**。其中一些服务正被集成进核心 **Windows** 产品和一些 **Office** 产品。_」
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kabir Khan - <strong>微软</strong> <a href="https://github.com/tiangolo/fastapi/pull/26" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"***FastAPI** 让我兴奋的欣喜若狂。它太棒了!*"
|
||||
「_我们选择了 **FastAPI** 来创建用于获取**预测结果**的 **REST** 服务。[用于 Ludwig]_」
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino,Yaroslav Dudin 和 Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
「_**Netflix** 非常高兴地宣布,正式开源我们的**危机管理**编排框架:**Dispatch**![使用 **FastAPI** 构建]_」
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Kevin Glisson,Marc Vilanova,Forest Monsen - <strong>Netflix</strong> <a href="https://netflixtechblog.com/introducing-dispatch-da4b8a2a8072" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
「_**FastAPI** 让我兴奋的欣喜若狂。它太棒了!_」
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Brian Okken - <strong><a href="https://pythonbytes.fm/episodes/show/123/time-to-right-the-py-wrongs?time_in_sec=855" target="_blank">Python Bytes</a> 播客主持人</strong> <a href="https://twitter.com/brianokken/status/1112220079972728832" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"*老实说,你的作品看起来非常可靠和优美。在很多方面,这就是我想让 **Hug** 成为的样子 - 看到有人实现了它真的很鼓舞人心。*"
|
||||
「_老实说,你的作品看起来非常可靠和优美。在很多方面,这就是我想让 **Hug** 成为的样子 - 看到有人实现了它真的很鼓舞人心。_」
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Timothy Crosley - <strong><a href="http://www.hug.rest/" target="_blank">Hug</a> 作者</strong> <a href="https://news.ycombinator.com/item?id=19455465" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"*如果你正打算学习一个**现代框架**用来构建 REST API,来看下 **FastAPI** [...] 它快速、易用且易于学习 [...]*"
|
||||
「_如果你正打算学习一个**现代框架**用来构建 REST API,来看下 **FastAPI** [...] 它快速、易用且易于学习 [...]_」
|
||||
|
||||
"*我们已经将 **API** 服务切换到了 **FastAPI** [...] 我认为你会喜欢它的 [...]*"
|
||||
「_我们已经将 **API** 服务切换到了 **FastAPI** [...] 我认为你会喜欢它的 [...]_」
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Ines Montani - Matthew Honnibal - <strong><a href="https://explosion.ai" target="_blank">Explosion AI</a> 创始人 - <a href="https://spacy.io" target="_blank">spaCy</a> 作者</strong> <a href="https://twitter.com/_inesmontani/status/1144173225322143744" target="_blank"><small>(ref)</small></a> - <a href="https://twitter.com/honnibal/status/1144031421859655680" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
"*我们采用了 **FastAPI** 来创建用于获取**预测结果**的 **REST** 服务。[用于 Ludwig]*"
|
||||
|
||||
<div style="text-align: right; margin-right: 10%;">Piero Molino, Yaroslav Dudin 和 Sai Sumanth Miryala - <strong>Uber</strong> <a href="https://eng.uber.com/ludwig-v0-2/" target="_blank"><small>(ref)</small></a></div>
|
||||
|
||||
---
|
||||
|
||||
## **Typer**,命令行中的 Fast API
|
||||
## **Typer**,命令行中的 FastAPI
|
||||
|
||||
<a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
|
||||
|
||||
如果你正在开发一个在终端中运行的<abbr title="Command Line Interface">命令行</abbr>应用而不是 web API,不妨试下 <a href="https://typer.tiangolo.com/" class="external-link" target="_blank">**Typer**</a>。
|
||||
|
||||
**Typer** 是 FastAPI 的小伙伴。它打算成为**命令行中的 FastAPI**。 ⌨️ 🚀
|
||||
**Typer** 是 FastAPI 的小同胞。它想要成为**命令行中的 FastAPI**。 ⌨️ 🚀
|
||||
|
||||
## 依赖
|
||||
|
||||
@@ -91,8 +97,8 @@ Python 3.6 及更高版本
|
||||
|
||||
FastAPI 站在以下巨人的肩膀之上:
|
||||
|
||||
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a>负责 web 部分。
|
||||
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a>负责数据部分。
|
||||
* <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> 负责 web 部分。
|
||||
* <a href="https://pydantic-docs.helpmanual.io/" class="external-link" target="_blank">Pydantic</a> 负责数据部分。
|
||||
|
||||
## 安装
|
||||
|
||||
@@ -106,7 +112,7 @@ $ pip install fastapi
|
||||
|
||||
</div>
|
||||
|
||||
你还需要一个 ASGI 服务器,生产环境可以使用 <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> 或者 <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>。
|
||||
你还会需要一个 ASGI 服务器,生产环境可以使用 <a href="http://www.uvicorn.org" class="external-link" target="_blank">Uvicorn</a> 或者 <a href="https://gitlab.com/pgjones/hypercorn" class="external-link" target="_blank">Hypercorn</a>。
|
||||
|
||||
<div class="termy">
|
||||
|
||||
@@ -125,6 +131,8 @@ $ pip install uvicorn
|
||||
* 创建一个 `main.py` 文件并写入以下内容:
|
||||
|
||||
```Python
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -136,16 +144,18 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
<details markdown="1">
|
||||
<summary>或者使用 <code>async def</code>...</summary>
|
||||
|
||||
如果你的代码里会出现 `async` / `await`,应使用 `async def`:
|
||||
如果你的代码里会出现 `async` / `await`,请使用 `async def`:
|
||||
|
||||
```Python hl_lines="9 14"
|
||||
from typing import Optional
|
||||
|
||||
```Python hl_lines="7 12"
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -157,7 +167,7 @@ async def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: int, q: str = None):
|
||||
async def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
```
|
||||
|
||||
@@ -176,11 +186,11 @@ async def read_item(item_id: int, q: str = None):
|
||||
```console
|
||||
$ uvicorn main:app --reload
|
||||
|
||||
<span style="color: green;">INFO</span>: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
<span style="color: green;">INFO</span>: Started reloader process [28720]
|
||||
<span style="color: green;">INFO</span>: Started server process [28722]
|
||||
<span style="color: green;">INFO</span>: Waiting for application startup.
|
||||
<span style="color: green;">INFO</span>: Application startup complete.
|
||||
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
|
||||
INFO: Started reloader process [28720]
|
||||
INFO: Started server process [28722]
|
||||
INFO: Waiting for application startup.
|
||||
INFO: Application startup complete.
|
||||
```
|
||||
|
||||
</div>
|
||||
@@ -221,21 +231,23 @@ $ uvicorn main:app --reload
|
||||
|
||||

|
||||
|
||||
### 备选 API 文档
|
||||
### 可选的 API 文档
|
||||
|
||||
访问 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>。
|
||||
|
||||
你会看到另一个自动生成的文档(由 <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a>)生成:
|
||||
你会看到另一个自动生成的文档(由 <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank">ReDoc</a> 生成):
|
||||
|
||||

|
||||
|
||||
## 升级示例
|
||||
## 示例升级
|
||||
|
||||
修改 `main.py` 文件来从 `PUT` 请求中接收请求体。
|
||||
现在修改 `main.py` 文件来从 `PUT` 请求中接收请求体。
|
||||
|
||||
我们借助 Pydantic 来使用标准的 Python 类型声明请求体。
|
||||
|
||||
```Python hl_lines="2 7 8 9 10 23 24 25"
|
||||
```Python hl_lines="4 9 10 11 12 25 26 27"
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -245,7 +257,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
price: float
|
||||
is_offer: bool = None
|
||||
is_offer: Optional[bool] = None
|
||||
|
||||
|
||||
@app.get("/")
|
||||
@@ -254,7 +266,7 @@ def read_root():
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
def read_item(item_id: int, q: str = None):
|
||||
def read_item(item_id: int, q: Optional[str] = None):
|
||||
return {"item_id": item_id, "q": q}
|
||||
|
||||
|
||||
@@ -265,7 +277,7 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||
服务器将会自动重载(因为在上面的步骤中你向 `uvicorn` 命令添加了 `--reload` 选项)。
|
||||
|
||||
### 升级交互式 API 文档
|
||||
### 交互式 API 文档升级
|
||||
|
||||
访问 <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>。
|
||||
|
||||
@@ -273,23 +285,23 @@ def update_item(item_id: int, item: Item):
|
||||
|
||||

|
||||
|
||||
* 点击 "Try it out" 按钮,之后你可以填写参数并直接调用 API:
|
||||
* 点击「Try it out」按钮,之后你可以填写参数并直接调用 API:
|
||||
|
||||

|
||||
|
||||
* 然后点击 "Execute" 按钮,用户界面将会和 API 进行通信,发送参数,获取结果并在屏幕上展示:
|
||||
* 然后点击「Execute」按钮,用户界面将会和 API 进行通信,发送参数,获取结果并在屏幕上展示:
|
||||
|
||||

|
||||
|
||||
### 升级备选文档
|
||||
### 可选文档升级
|
||||
|
||||
访问 <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>。
|
||||
|
||||
* 备选文档同样会体现新加入的请求参数和请求体:
|
||||
* 可选文档同样会体现新加入的请求参数和请求体:
|
||||
|
||||

|
||||
|
||||
### 回顾
|
||||
### 总结
|
||||
|
||||
总的来说,你就像声明函数的参数类型一样只声明了**一次**请求参数、请求体等的类型。
|
||||
|
||||
@@ -403,7 +415,6 @@ item: Item
|
||||
|
||||
## 性能
|
||||
|
||||
|
||||
独立机构 TechEmpower 所作的基准测试结果显示,基于 Uvicorn 运行的 **FastAPI** 程序是 <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">最快的 Python web 框架之一</a>,仅次于 Starlette 和 Uvicorn 本身(FastAPI 内部使用了它们)。(*)
|
||||
|
||||
想了解更多,请查阅 <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">基准测试</a> 章节。
|
||||
@@ -412,7 +423,7 @@ item: Item
|
||||
|
||||
用于 Pydantic:
|
||||
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 更快的 JSON <abbr title="将来自 HTTP 请求中的字符串转换为 Python 数据类型">"解析"</abbr>。
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 更快的 JSON <abbr title="将来自 HTTP 请求中的字符串转换为 Python 数据类型">「解析」</abbr>。
|
||||
* <a href="https://github.com/JoshData/python-email-validator" target="_blank"><code>email_validator</code></a> - 用于 email 校验。
|
||||
|
||||
用于 Starlette:
|
||||
@@ -420,15 +431,15 @@ item: Item
|
||||
* <a href="http://docs.python-requests.org" target="_blank"><code>requests</code></a> - 使用 `TestClient` 时安装。
|
||||
* <a href="https://github.com/Tinche/aiofiles" target="_blank"><code>aiofiles</code></a> - 使用 `FileResponse` 或 `StaticFiles` 时安装。
|
||||
* <a href="http://jinja.pocoo.org" target="_blank"><code>jinja2</code></a> - 使用默认模板配置时安装。
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - 需要通过 `request.form()` 对表单进行<abbr title="将来自 HTTP 请求中的字符串转换为 Python 数据类型">"解析"</abbr>时安装。
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - 提供 `SessionMiddleware` 支持。
|
||||
* <a href="https://andrew-d.github.io/python-multipart/" target="_blank"><code>python-multipart</code></a> - 需要通过 `request.form()` 对表单进行<abbr title="将来自 HTTP 请求中的字符串转换为 Python 数据类型">「解析」</abbr>时安装。
|
||||
* <a href="https://pythonhosted.org/itsdangerous/" target="_blank"><code>itsdangerous</code></a> - 需要 `SessionMiddleware` 支持时安装。
|
||||
* <a href="https://pyyaml.org/wiki/PyYAMLDocumentation" target="_blank"><code>pyyaml</code></a> - 使用 Starlette 提供的 `SchemaGenerator` 时安装(有 FastAPI 你可能并不需要它)。
|
||||
* <a href="https://graphene-python.org/" target="_blank"><code>graphene</code></a> - 需要 `GraphQLApp` 支持时安装。
|
||||
* <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - 使用 `UJSONResponse` 时安装。
|
||||
|
||||
用于 FastAPI / Starlette:
|
||||
|
||||
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - 用于加载和服务你的应用程序的服务器。
|
||||
* <a href="http://www.uvicorn.org" target="_blank"><code>uvicorn</code></a> - 用于加载和运行你的应用程序的服务器。
|
||||
* <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - 使用 `ORJSONResponse` 时安装。
|
||||
|
||||
你可以通过 `pip install fastapi[all]` 命令来安装以上所有依赖。
|
||||
|
||||
48
docs/zh/docs/tutorial/body-fields.md
Normal file
48
docs/zh/docs/tutorial/body-fields.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 请求体 - 字段
|
||||
|
||||
与使用 `Query`、`Path` 和 `Body` 在*路径操作函数*中声明额外的校验和元数据的方式相同,你可以使用 Pydantic 的 `Field` 在 Pydantic 模型内部声明校验和元数据。
|
||||
|
||||
## 导入 `Field`
|
||||
|
||||
首先,你必须导入它:
|
||||
|
||||
```Python hl_lines="2"
|
||||
{!../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! warning
|
||||
注意,`Field` 是直接从 `pydantic` 导入的,而不是像其他的(`Query`,`Path`,`Body` 等)都从 `fastapi` 导入。
|
||||
|
||||
## 声明模型属性
|
||||
|
||||
然后,你可以对模型属性使用 `Field`:
|
||||
|
||||
```Python hl_lines="9 10"
|
||||
{!../../../docs_src/body_fields/tutorial001.py!}
|
||||
```
|
||||
|
||||
`Field` 的工作方式和 `Query`、`Path` 和 `Body` 相同,包括它们的参数等等也完全相同。
|
||||
|
||||
!!! note "技术细节"
|
||||
实际上,`Query`、`Path` 和其他你将在之后看到的类,创建的是由一个共同的 `Params` 类派生的子类的对象,该共同类本身又是 Pydantic 的 `FieldInfo` 类的子类。
|
||||
|
||||
Pydantic 的 `Field` 也会返回一个 `FieldInfo` 的实例。
|
||||
|
||||
`Body` 也直接返回 `FieldInfo` 的一个子类的对象。还有其他一些你之后会看到的类是 `Body` 类的子类。
|
||||
|
||||
请记住当你从 `fastapi` 导入 `Query`、`Path` 等对象时,他们实际上是返回特殊类的函数。
|
||||
|
||||
!!! tip
|
||||
注意每个模型属性如何使用类型、默认值和 `Field` 在代码结构上和*路径操作函数*的参数是相同的,区别是用 `Field` 替换`Path`、`Query` 和 `Body`。
|
||||
|
||||
## 添加额外信息
|
||||
|
||||
你可以在 `Field`、`Query`、`Body` 中声明额外的信息。这些信息将包含在生成的 JSON Schema 中。
|
||||
|
||||
你将在文档的后面部分学习声明示例时,了解到更多有关添加额外信息的知识。
|
||||
|
||||
## 总结
|
||||
|
||||
你可以使用 Pydantic 的 `Field` 为模型属性声明额外的校验和元数据。
|
||||
|
||||
你还可以使用额外的关键字参数来传递额外的 JSON Schema 元数据。
|
||||
170
docs/zh/docs/tutorial/body-multiple-params.md
Normal file
170
docs/zh/docs/tutorial/body-multiple-params.md
Normal file
@@ -0,0 +1,170 @@
|
||||
# 请求体 - 多个参数
|
||||
|
||||
既然我们已经知道了如何使用 `Path` 和 `Query`,下面让我们来了解一下请求体声明的更高级用法。
|
||||
|
||||
## 混合使用 `Path`、`Query` 和请求体参数
|
||||
|
||||
首先,毫无疑问地,你可以随意地混合使用 `Path`、`Query` 和请求体参数声明,**FastAPI** 会知道该如何处理。
|
||||
|
||||
你还可以通过将默认值设置为 `None` 来将请求体参数声明为可选参数:
|
||||
|
||||
```Python hl_lines="17 18 19"
|
||||
{!../../../docs_src/body_multiple_params/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
请注意,在这种情况下,将从请求体获取的 `item` 是可选的。因为它的默认值为 `None`。
|
||||
|
||||
## 多个请求体参数
|
||||
|
||||
在上面的示例中,*路径操作*将期望一个具有 `Item` 的属性的 JSON 请求体,就像:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
}
|
||||
```
|
||||
|
||||
但是你也可以声明多个请求体参数,例如 `item` 和 `user`:
|
||||
|
||||
```Python hl_lines="20"
|
||||
{!../../../docs_src/body_multiple_params/tutorial002.py!}
|
||||
```
|
||||
|
||||
在这种情况下,**FastAPI** 将注意到该函数中有多个请求体参数(两个 Pydantic 模型参数)。
|
||||
|
||||
因此,它将使用参数名称作为请求体中的键(字段名称),并期望一个类似于以下内容的请求体:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": {
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
},
|
||||
"user": {
|
||||
"username": "dave",
|
||||
"full_name": "Dave Grohl"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
!!! note
|
||||
请注意,即使 `item` 的声明方式与之前相同,但现在它被期望通过 `item` 键内嵌在请求体中。
|
||||
|
||||
|
||||
**FastAPI** 将自动对请求中的数据进行转换,因此 `item` 参数将接收指定的内容,`user` 参数也是如此。
|
||||
|
||||
它将执行对复合数据的校验,并且像现在这样为 OpenAPI 模式和自动化文档对其进行记录。
|
||||
|
||||
## 请求体中的单一值
|
||||
|
||||
与使用 `Query` 和 `Path` 为查询参数和路径参数定义额外数据的方式相同,**FastAPI** 提供了一个同等的 `Body`。
|
||||
|
||||
例如,为了扩展先前的模型,你可能决定除了 `item` 和 `user` 之外,还想在同一请求体中具有另一个键 `importance`。
|
||||
|
||||
如果你就按原样声明它,因为它是一个单一值,**FastAPI** 将假定它是一个查询参数。
|
||||
|
||||
但是你可以使用 `Body` 指示 **FastAPI** 将其作为请求体的另一个键进行处理。
|
||||
|
||||
|
||||
```Python hl_lines="21"
|
||||
{!../../../docs_src/body_multiple_params/tutorial003.py!}
|
||||
```
|
||||
|
||||
在这种情况下,**FastAPI** 将期望像这样的请求体:
|
||||
|
||||
|
||||
```JSON
|
||||
{
|
||||
"item": {
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
},
|
||||
"user": {
|
||||
"username": "dave",
|
||||
"full_name": "Dave Grohl"
|
||||
},
|
||||
"importance": 5
|
||||
}
|
||||
```
|
||||
|
||||
同样的,它将转换数据类型,校验,生成文档等。
|
||||
|
||||
## 多个请求体参数和查询参数
|
||||
|
||||
当然,除了请求体参数外,你还可以在任何需要的时候声明额外的查询参数。
|
||||
|
||||
由于默认情况下单一值被解释为查询参数,因此你不必显式地添加 `Query`,你可以仅执行以下操作:
|
||||
|
||||
```Python
|
||||
q: str = None
|
||||
```
|
||||
|
||||
比如:
|
||||
|
||||
```Python hl_lines="25"
|
||||
{!../../../docs_src/body_multiple_params/tutorial004.py!}
|
||||
```
|
||||
|
||||
!!! info
|
||||
`Body` 同样具有与 `Query`、`Path` 以及其他后面将看到的类完全相同的额外校验和元数据参数。
|
||||
|
||||
|
||||
## 嵌入单个请求体参数
|
||||
|
||||
假设你只有一个来自 Pydantic 模型 `Item` 的请求体参数 `item`。
|
||||
|
||||
默认情况下,**FastAPI** 将直接期望这样的请求体。
|
||||
|
||||
但是,如果你希望它期望一个拥有 `item` 键并在值中包含模型内容的 JSON,就像在声明额外的请求体参数时所做的那样,则可以使用一个特殊的 `Body` 参数 `embed`:
|
||||
|
||||
```Python
|
||||
item: Item = Body(..., embed=True)
|
||||
```
|
||||
|
||||
比如:
|
||||
|
||||
```Python hl_lines="15"
|
||||
{!../../../docs_src/body_multiple_params/tutorial005.py!}
|
||||
```
|
||||
|
||||
在这种情况下,**FastAPI** 将期望像这样的请求体:
|
||||
|
||||
```JSON hl_lines="2"
|
||||
{
|
||||
"item": {
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
而不是:
|
||||
|
||||
```JSON
|
||||
{
|
||||
"name": "Foo",
|
||||
"description": "The pretender",
|
||||
"price": 42.0,
|
||||
"tax": 3.2
|
||||
}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
你可以添加多个请求体参数到*路径操作函数*中,即使一个请求只能有一个请求体。
|
||||
|
||||
但是 **FastAPI** 会处理它,在函数中为你提供正确的数据,并在*路径操作*中校验并记录正确的模式。
|
||||
|
||||
你还可以声明将作为请求体的一部分所接收的单一值。
|
||||
|
||||
你还可以指示 **FastAPI** 在仅声明了一个请求体参数的情况下,将原本的请求体嵌入到一个键中。
|
||||
122
docs/zh/docs/tutorial/path-params-numeric-validations.md
Normal file
122
docs/zh/docs/tutorial/path-params-numeric-validations.md
Normal file
@@ -0,0 +1,122 @@
|
||||
# 路径参数和数值校验
|
||||
|
||||
与使用 `Query` 为查询参数声明更多的校验和元数据的方式相同,你也可以使用 `Path` 为路径参数声明相同类型的校验和元数据。
|
||||
|
||||
## 导入 Path
|
||||
|
||||
首先,从 `fastapi` 导入 `Path`:
|
||||
|
||||
```Python hl_lines="1"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
## 声明元数据
|
||||
|
||||
你可以声明与 `Query` 相同的所有参数。
|
||||
|
||||
例如,要声明路径参数 `item_id`的 `title` 元数据值,你可以输入:
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial001.py!}
|
||||
```
|
||||
|
||||
!!! note
|
||||
路径参数总是必需的,因为它必须是路径的一部分。
|
||||
|
||||
所以,你应该在声明时使用 `...` 将其标记为必需参数。
|
||||
|
||||
然而,即使你使用 `None` 声明路径参数或设置一个其他默认值也不会有任何影响,它依然会是必需参数。
|
||||
|
||||
## 按需对参数排序
|
||||
|
||||
假设你想要声明一个必需的 `str` 类型查询参数 `q`。
|
||||
|
||||
而且你不需要为该参数声明任何其他内容,所以实际上你并不需要使用 `Query`。
|
||||
|
||||
但是你仍然需要使用 `Path` 来声明路径参数 `item_id`。
|
||||
|
||||
如果你将带有「默认值」的参数放在没有「默认值」的参数之前,Python 将会报错。
|
||||
|
||||
但是你可以对其重新排序,并将不带默认值的值(查询参数 `q`)放到最前面。
|
||||
|
||||
对 **FastAPI** 来说这无关紧要。它将通过参数的名称、类型和默认值声明(`Query`、`Path` 等)来检测参数,而不在乎参数的顺序。
|
||||
|
||||
因此,你可以将函数声明为:
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial002.py!}
|
||||
```
|
||||
|
||||
## 按需对参数排序的技巧
|
||||
|
||||
如果你想不使用 `Query` 声明没有默认值的查询参数 `q`,同时使用 `Path` 声明路径参数 `item_id`,并使它们的顺序与上面不同,Python 对此有一些特殊的语法。
|
||||
|
||||
传递 `*` 作为函数的第一个参数。
|
||||
|
||||
Python 不会对该 `*` 做任何事情,但是它将知道之后的所有参数都应作为关键字参数(键值对),也被称为 <abbr title="来自:K-ey W-ord Arg-uments"><code>kwargs</code></abbr>,来调用。即使它们没有默认值。
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial003.py!}
|
||||
```
|
||||
|
||||
## 数值校验:大于等于
|
||||
|
||||
使用 `Query` 和 `Path`(以及你将在后面看到的其他类)可以声明字符串约束,但也可以声明数值约束。
|
||||
|
||||
像下面这样,添加 `ge=1` 后,`item_id` 将必须是一个大于(`g`reater than)或等于(`e`qual)`1` 的整数。
|
||||
|
||||
```Python hl_lines="8"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial004.py!}
|
||||
```
|
||||
|
||||
## 数值校验:大于和小于等于
|
||||
|
||||
同样的规则适用于:
|
||||
|
||||
* `gt`:大于(`g`reater `t`han)
|
||||
* `le`:小于等于(`l`ess than or `e`qual)
|
||||
|
||||
```Python hl_lines="9"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial005.py!}
|
||||
```
|
||||
|
||||
## 数值校验:浮点数、大于和小于
|
||||
|
||||
数值校验同样适用于 `float` 值。
|
||||
|
||||
能够声明 <abbr title="大于"><code>gt</code></abbr> 而不仅仅是 <abbr title="大于等于"><code>ge</code></abbr> 在这个前提下变得重要起来。例如,你可以要求一个值必须大于 `0`,即使它小于 `1`。
|
||||
|
||||
因此,`0.5` 将是有效值。但是 `0.0`或 `0` 不是。
|
||||
|
||||
对于 <abbr title="less than"><code>lt</code></abbr> 也是一样的。
|
||||
|
||||
```Python hl_lines="11"
|
||||
{!../../../docs_src/path_params_numeric_validations/tutorial006.py!}
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
你能够以与 [查询参数和字符串校验](query-params-str-validations.md){.internal-link target=_blank} 相同的方式使用 `Query`、`Path`(以及其他你还没见过的类)声明元数据和字符串校验。
|
||||
|
||||
而且你还可以声明数值校验:
|
||||
|
||||
* `gt`:大于(`g`reater `t`han)
|
||||
* `ge`:大于等于(`g`reater than or `e`qual)
|
||||
* `lt`:小于(`l`ess `t`han)
|
||||
* `le`:小于等于(`l`ess than or `e`qual)
|
||||
|
||||
!!! info
|
||||
`Query`、`Path` 以及你后面会看到的其他类继承自一个共同的 `Param` 类(不需要直接使用它)。
|
||||
|
||||
而且它们都共享相同的所有你已看到并用于添加额外校验和元数据的参数。
|
||||
|
||||
!!! note "技术细节"
|
||||
当你从 `fastapi` 导入 `Query`、`Path` 和其他同类对象时,它们实际上是函数。
|
||||
|
||||
当被调用时,它们返回同名类的实例。
|
||||
|
||||
如此,你导入 `Query` 这个函数。当你调用它时,它将返回一个同样命名为 `Query` 的类的实例。
|
||||
|
||||
因为使用了这些函数(而不是直接使用类),所以你的编辑器不会标记有关其类型的错误。
|
||||
|
||||
这样,你可以使用常规的编辑器和编码工具,而不必添加自定义配置来忽略这些错误。
|
||||
@@ -35,6 +35,9 @@ nav:
|
||||
- tutorial/query-params.md
|
||||
- tutorial/body.md
|
||||
- tutorial/query-params-str-validations.md
|
||||
- tutorial/path-params-numeric-validations.md
|
||||
- tutorial/body-multiple-params.md
|
||||
- tutorial/body-fields.md
|
||||
- deployment.md
|
||||
- contributing.md
|
||||
- help-fastapi.md
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
@@ -21,7 +23,7 @@ app = FastAPI()
|
||||
}
|
||||
},
|
||||
)
|
||||
async def read_item(item_id: str, img: bool = None):
|
||||
async def read_item(item_id: str, img: Optional[bool] = None):
|
||||
if img:
|
||||
return FileResponse("image.png", media_type="image/png")
|
||||
else:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import FileResponse
|
||||
from pydantic import BaseModel
|
||||
@@ -23,7 +25,7 @@ app = FastAPI()
|
||||
response_model=Item,
|
||||
responses={**responses, 200: {"content": {"image/png": {}}}},
|
||||
)
|
||||
async def read_item(item_id: str, img: bool = None):
|
||||
async def read_item(item_id: str, img: Optional[bool] = None):
|
||||
if img:
|
||||
return FileResponse("image.png", media_type="image/png")
|
||||
else:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Body, FastAPI, status
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
@@ -7,7 +9,9 @@ items = {"foo": {"name": "Fighters", "size": 6}, "bar": {"name": "Tenders", "siz
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def upsert_item(item_id: str, name: str = Body(None), size: int = Body(None)):
|
||||
async def upsert_item(
|
||||
item_id: str, name: Optional[str] = Body(None), size: Optional[int] = Body(None)
|
||||
):
|
||||
if item_id in items:
|
||||
item = items[item_id]
|
||||
item["name"] = name
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Header, HTTPException
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -14,7 +16,7 @@ app = FastAPI()
|
||||
class Item(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
|
||||
|
||||
@app.get("/items/{item_id}", response_model=Item)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import BackgroundTasks, Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -8,7 +10,7 @@ def write_log(message: str):
|
||||
log.write(message)
|
||||
|
||||
|
||||
def get_query(background_tasks: BackgroundTasks, q: str = None):
|
||||
def get_query(background_tasks: BackgroundTasks, q: Optional[str] = None):
|
||||
if q:
|
||||
message = f"found query: {q}\n"
|
||||
background_tasks.add_task(write_log, message)
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def create_item(item_id: int, item: Item, q: str = None):
|
||||
async def create_item(item_id: int, item: Item, q: Optional[str] = None):
|
||||
result = {"item_id": item_id, **item.dict()}
|
||||
if q:
|
||||
result.update({"q": q})
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
@@ -6,9 +8,11 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = Field(None, title="The description of the item", max_length=300)
|
||||
description: Optional[str] = Field(
|
||||
None, title="The description of the item", max_length=300
|
||||
)
|
||||
price: float = Field(..., gt=0, description="The price must be greater than zero")
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Path
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -6,17 +8,17 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
async def update_item(
|
||||
*,
|
||||
item_id: int = Path(..., title="The ID of the item to get", ge=0, le=1000),
|
||||
q: str = None,
|
||||
item: Item = None,
|
||||
q: Optional[str] = None,
|
||||
item: Optional[Item] = None,
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -6,14 +8,14 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -6,14 +8,14 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -6,14 +8,14 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
class User(BaseModel):
|
||||
username: str
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
@@ -23,7 +25,7 @@ async def update_item(
|
||||
item: Item,
|
||||
user: User,
|
||||
importance: int = Body(..., gt=0),
|
||||
q: str = None
|
||||
q: Optional[str] = None
|
||||
):
|
||||
results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
|
||||
if q:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Body, FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -6,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -6,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: list = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: List[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = set()
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -13,11 +13,11 @@ class Image(BaseModel):
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
image: Image = None
|
||||
image: Optional[Image] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
@@ -13,11 +13,11 @@ class Image(BaseModel):
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
image: Image = None
|
||||
image: Optional[Image] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List, Set
|
||||
from typing import List, Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
@@ -13,11 +13,11 @@ class Image(BaseModel):
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
images: List[Image] = None
|
||||
images: Optional[List[Image]] = None
|
||||
|
||||
|
||||
@app.put("/items/{item_id}")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List, Set
|
||||
from typing import List, Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
@@ -13,16 +13,16 @@ class Image(BaseModel):
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
images: List[Image] = None
|
||||
images: Optional[List[Image]] = None
|
||||
|
||||
|
||||
class Offer(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
items: List[Item]
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str = None
|
||||
description: str = None
|
||||
price: float = None
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
price: Optional[float] = None
|
||||
tax: float = 10.5
|
||||
tags: List[str] = []
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str = None
|
||||
description: str = None
|
||||
price: float = None
|
||||
name: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
price: Optional[float] = None
|
||||
tax: float = 10.5
|
||||
tags: List[str] = []
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Cookie, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(ads_id: str = Cookie(None)):
|
||||
async def read_items(ads_id: Optional[str] = Cookie(None)):
|
||||
return {"ads_id": ads_id}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
|
||||
async def common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 100):
|
||||
return {"q": q, "skip": skip, "limit": limit}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -7,7 +9,7 @@ fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"
|
||||
|
||||
|
||||
class CommonQueryParams:
|
||||
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
|
||||
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
|
||||
self.q = q
|
||||
self.skip = skip
|
||||
self.limit = limit
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -7,7 +9,7 @@ fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"
|
||||
|
||||
|
||||
class CommonQueryParams:
|
||||
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
|
||||
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
|
||||
self.q = q
|
||||
self.skip = skip
|
||||
self.limit = limit
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -7,7 +9,7 @@ fake_items_db = [{"item_name": "Foo"}, {"item_name": "Bar"}, {"item_name": "Baz"
|
||||
|
||||
|
||||
class CommonQueryParams:
|
||||
def __init__(self, q: str = None, skip: int = 0, limit: int = 100):
|
||||
def __init__(self, q: Optional[str] = None, skip: int = 0, limit: int = 100):
|
||||
self.q = q
|
||||
self.skip = skip
|
||||
self.limit = limit
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Cookie, Depends, FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
def query_extractor(q: str = None):
|
||||
def query_extractor(q: Optional[str] = None):
|
||||
return q
|
||||
|
||||
|
||||
def query_or_cookie_extractor(
|
||||
q: str = Depends(query_extractor), last_query: str = Cookie(None)
|
||||
q: str = Depends(query_extractor), last_query: Optional[str] = Cookie(None)
|
||||
):
|
||||
if not q:
|
||||
return last_query
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import Depends, FastAPI
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
async def common_parameters(q: str = None, skip: int = 0, limit: int = 100):
|
||||
async def common_parameters(q: Optional[str] = None, skip: int = 0, limit: int = 100):
|
||||
return {"q": q, "skip": skip, "limit": limit}
|
||||
|
||||
|
||||
@@ -21,7 +23,7 @@ async def read_users(commons: dict = Depends(common_parameters)):
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
async def override_dependency(q: str = None):
|
||||
async def override_dependency(q: Optional[str] = None):
|
||||
return {"q": q, "skip": 5, "limit": 10}
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.encoders import jsonable_encoder
|
||||
@@ -10,7 +11,7 @@ fake_db = {}
|
||||
class Item(BaseModel):
|
||||
title: str
|
||||
timestamp: datetime
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from datetime import datetime, time, timedelta
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Body, FastAPI
|
||||
@@ -9,10 +10,10 @@ app = FastAPI()
|
||||
@app.put("/items/{item_id}")
|
||||
async def read_items(
|
||||
item_id: UUID,
|
||||
start_datetime: datetime = Body(None),
|
||||
end_datetime: datetime = Body(None),
|
||||
repeat_at: time = Body(None),
|
||||
process_after: timedelta = Body(None),
|
||||
start_datetime: Optional[datetime] = Body(None),
|
||||
end_datetime: Optional[datetime] = Body(None),
|
||||
repeat_at: Optional[time] = Body(None),
|
||||
process_after: Optional[timedelta] = Body(None),
|
||||
):
|
||||
start_process = start_datetime + process_after
|
||||
duration = end_datetime - start_process
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
@@ -8,20 +10,20 @@ class UserIn(BaseModel):
|
||||
username: str
|
||||
password: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
class UserOut(BaseModel):
|
||||
username: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
class UserInDB(BaseModel):
|
||||
username: str
|
||||
hashed_password: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
def fake_password_hasher(raw_password: str):
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel, EmailStr
|
||||
|
||||
@@ -7,7 +9,7 @@ app = FastAPI()
|
||||
class UserBase(BaseModel):
|
||||
username: str
|
||||
email: EmailStr
|
||||
full_name: str = None
|
||||
full_name: Optional[str] = None
|
||||
|
||||
|
||||
class UserIn(UserBase):
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Header
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(user_agent: str = Header(None)):
|
||||
async def read_items(user_agent: Optional[str] = Header(None)):
|
||||
return {"User-Agent": user_agent}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Header
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(strange_header: str = Header(None, convert_underscores=False)):
|
||||
async def read_items(
|
||||
strange_header: Optional[str] = Header(None, convert_underscores=False)
|
||||
):
|
||||
return {"strange_header": strange_header}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from fastapi import FastAPI, Header
|
||||
|
||||
@@ -6,5 +6,5 @@ app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(x_token: List[str] = Header(None)):
|
||||
async def read_items(x_token: Optional[List[str]] = Header(None)):
|
||||
return {"X-Token values": x_token}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi.responses import JSONResponse
|
||||
from pydantic import BaseModel, HttpUrl
|
||||
@@ -7,7 +9,7 @@ app = FastAPI()
|
||||
|
||||
class Invoice(BaseModel):
|
||||
id: str
|
||||
title: str = None
|
||||
title: Optional[str] = None
|
||||
customer: str
|
||||
total: float
|
||||
|
||||
@@ -32,7 +34,7 @@ def invoice_notification(body: InvoiceEvent):
|
||||
|
||||
|
||||
@app.post("/invoices/", callbacks=invoices_callback_router.routes)
|
||||
def create_invoice(invoice: Invoice, callback_url: HttpUrl = None):
|
||||
def create_invoice(invoice: Invoice, callback_url: Optional[HttpUrl] = None):
|
||||
"""
|
||||
Create an invoice.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI, status
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Set
|
||||
from typing import Optional, Set
|
||||
|
||||
from fastapi import FastAPI
|
||||
from pydantic import BaseModel
|
||||
@@ -8,9 +8,9 @@ app = FastAPI()
|
||||
|
||||
class Item(BaseModel):
|
||||
name: str
|
||||
description: str = None
|
||||
description: Optional[str] = None
|
||||
price: float
|
||||
tax: float = None
|
||||
tax: Optional[float] = None
|
||||
tags: Set[str] = []
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Path, Query
|
||||
|
||||
app = FastAPI()
|
||||
@@ -6,7 +8,7 @@ app = FastAPI()
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_items(
|
||||
item_id: int = Path(..., title="The ID of the item to get"),
|
||||
q: str = Query(None, alias="item-query"),
|
||||
q: Optional[str] = Query(None, alias="item-query"),
|
||||
):
|
||||
results = {"item_id": item_id}
|
||||
if q:
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: str, q: str = None):
|
||||
async def read_item(item_id: str, q: Optional[str] = None):
|
||||
if q:
|
||||
return {"item_id": item_id, "q": q}
|
||||
return {"item_id": item_id}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_item(item_id: str, q: str = None, short: bool = False):
|
||||
async def read_item(item_id: str, q: Optional[str] = None, short: bool = False):
|
||||
item = {"item_id": item_id}
|
||||
if q:
|
||||
item.update({"q": q})
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
@@ -5,7 +7,7 @@ app = FastAPI()
|
||||
|
||||
@app.get("/users/{user_id}/items/{item_id}")
|
||||
async def read_user_item(
|
||||
user_id: int, item_id: str, q: str = None, short: bool = False
|
||||
user_id: int, item_id: str, q: Optional[str] = None, short: bool = False
|
||||
):
|
||||
item = {"item_id": item_id, "owner_id": user_id}
|
||||
if q:
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_user_item(item_id: str, needy: str, skip: int = 0, limit: int = None):
|
||||
async def read_user_item(
|
||||
item_id: str, needy: str, skip: int = 0, limit: Optional[int] = None
|
||||
):
|
||||
item = {"item_id": item_id, "needy": needy, "skip": skip, "limit": limit}
|
||||
return item
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/{item_id}")
|
||||
async def read_user_item(item_id: str, limit: Optional[int] = None):
|
||||
item = {"item_id": item_id, "limit": limit}
|
||||
return item
|
||||
@@ -1,10 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(q: str = None):
|
||||
async def read_items(q: Optional[str] = None):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(q: str = Query(None, max_length=50)):
|
||||
async def read_items(q: Optional[str] = Query(None, max_length=50)):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(q: str = Query(None, min_length=3, max_length=50)):
|
||||
async def read_items(q: Optional[str] = Query(None, min_length=3, max_length=50)):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
results.update({"q": q})
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import FastAPI, Query
|
||||
|
||||
app = FastAPI()
|
||||
@@ -5,7 +7,7 @@ app = FastAPI()
|
||||
|
||||
@app.get("/items/")
|
||||
async def read_items(
|
||||
q: str = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
|
||||
q: Optional[str] = Query(None, min_length=3, max_length=50, regex="^fixedquery$")
|
||||
):
|
||||
results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
|
||||
if q:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user