Browse Source

Merge branch 'master' into fix/response_model_default_factory

pull/9704/head
Peanut 2 years ago
committed by GitHub
parent
commit
c575414a16
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      docs/en/docs/advanced/testing-database.md
  2. 10
      docs/en/docs/release-notes.md
  3. 2
      docs/en/docs/tutorial/query-params-str-validations.md
  4. 200
      docs/pl/docs/features.md
  5. 1
      docs/pl/mkdocs.yml
  6. 382
      docs/ru/docs/tutorial/body-nested-models.md
  7. 84
      docs/ru/docs/tutorial/cors.md
  8. 252
      docs/ru/docs/tutorial/extra-models.md
  9. 3
      docs/ru/mkdocs.yml
  10. 7
      docs_src/sql_databases/sql_app/tests/test_sql_app.py
  11. 2
      fastapi/applications.py
  12. 3
      pyproject.toml
  13. 4
      tests/test_param_include_in_schema.py
  14. 40
      tests/test_router_redirect_slashes.py
  15. 12
      tests/test_schema_extra_examples.py

2
docs/en/docs/advanced/testing-database.md

@ -44,7 +44,7 @@ So the new file structure looks like:
First, we create a new database session with the new database.
For the tests we'll use a file `test.db` instead of `sql_app.db`.
We'll use an in-memory database that persists during the tests instead of the local file `sql_app.db`.
But the rest of the session code is more or less the same, we just copy it.

10
docs/en/docs/release-notes.md

@ -2,6 +2,16 @@
## Latest Changes
* 🌐 Add Russian translation for `docs/tutorial/extra-models.md`. PR [#9619](https://github.com/tiangolo/fastapi/pull/9619) by [@ivan-abc](https://github.com/ivan-abc).
* 🌐 Add Russian translation for `docs/tutorial/cors.md`. PR [#9608](https://github.com/tiangolo/fastapi/pull/9608) by [@ivan-abc](https://github.com/ivan-abc).
* 🌐 Add Polish translation for `docs/pl/docs/features.md`. PR [#5348](https://github.com/tiangolo/fastapi/pull/5348) by [@mbroton](https://github.com/mbroton).
* 🌐 Add Russian translation for `docs/ru/docs/tutorial/body-nested-models.md`. PR [#9605](https://github.com/tiangolo/fastapi/pull/9605) by [@Alexandrhub](https://github.com/Alexandrhub).
* ✏️ Fix typo `Annotation` -> `Annotated` in `docs/en/docs/tutorial/query-params-str-validations.md`. PR [#9625](https://github.com/tiangolo/fastapi/pull/9625) by [@mccricardo](https://github.com/mccricardo).
* 🔧 Set minimal hatchling version needed to build the package. PR [#9240](https://github.com/tiangolo/fastapi/pull/9240) by [@mgorny](https://github.com/mgorny).
* 📝 Add repo link to PyPI. PR [#9559](https://github.com/tiangolo/fastapi/pull/9559) by [@JacobCoffee](https://github.com/JacobCoffee).
* ✏️ Fix typos in data for tests. PR [#4958](https://github.com/tiangolo/fastapi/pull/4958) by [@ryanrussell](https://github.com/ryanrussell).
* 📝 Use in memory database for testing SQL in docs. PR [#1223](https://github.com/tiangolo/fastapi/pull/1223) by [@HarshaLaxman](https://github.com/HarshaLaxman).
* ✨ Add allow disabling `redirect_slashes` at the FastAPI app level. PR [#3432](https://github.com/tiangolo/fastapi/pull/3432) by [@cyberlis](https://github.com/cyberlis).
* 🔧 Update sponsors, add Flint. PR [#9699](https://github.com/tiangolo/fastapi/pull/9699) by [@tiangolo](https://github.com/tiangolo).
* 👷 Lint in CI only once, only with one version of Python, run tests with all of them. PR [#9686](https://github.com/tiangolo/fastapi/pull/9686) by [@tiangolo](https://github.com/tiangolo).

2
docs/en/docs/tutorial/query-params-str-validations.md

@ -44,7 +44,7 @@ To achieve that, first import:
=== "Python 3.6+"
In versions of Python below Python 3.9 you import `Annotation` from `typing_extensions`.
In versions of Python below Python 3.9 you import `Annotated` from `typing_extensions`.
It will already be installed with FastAPI.

200
docs/pl/docs/features.md

@ -0,0 +1,200 @@
# Cechy
## Cechy FastAPI
**FastAPI** zapewnia Ci następujące korzyści:
### Oparcie o standardy open
* <a href="https://github.com/OAI/OpenAPI-Specification" class="external-link" target="_blank"><strong>OpenAPI</strong></a> do tworzenia API, w tym deklaracji <abbr title="znane również jako: paths, endpoints, routes">ścieżek</abbr> <abbr title="znane również jako metody HTTP, takie jak POST, GET, PUT, DELETE">operacji</abbr>, parametrów, <abbr title="po angielsku: body requests">ciał zapytań</abbr>, bezpieczeństwa, itp.
* Automatyczna dokumentacja modelu danych za pomocą <a href="https://json-schema.org/" class="external-link" target="_blank"><strong>JSON Schema</strong></a> (ponieważ OpenAPI bazuje na JSON Schema).
* Zaprojektowane z myślą o zgodności z powyższymi standardami zamiast dodawania ich obsługi po fakcie.
* Możliwość automatycznego **generowania kodu klienta** w wielu językach.
### Automatyczna dokumentacja
Interaktywna dokumentacja i webowe interfejsy do eksploracji API. Z racji tego, że framework bazuje na OpenAPI, istnieje wiele opcji, z czego 2 są domyślnie dołączone.
* <a href="https://github.com/swagger-api/swagger-ui" class="external-link" target="_blank"><strong>Swagger UI</strong></a>, z interaktywnym interfejsem - odpytuj i testuj swoje API bezpośrednio z przeglądarki.
![Swagger UI interakcja](https://fastapi.tiangolo.com/img/index/index-03-swagger-02.png)
* Alternatywna dokumentacja API z <a href="https://github.com/Rebilly/ReDoc" class="external-link" target="_blank"><strong>ReDoc</strong></a>.
![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
### Nowoczesny Python
Wszystko opiera się na standardowych deklaracjach typu **Python 3.6** (dzięki Pydantic). Brak nowej składni do uczenia. Po prostu standardowy, współczesny Python.
Jeśli potrzebujesz szybkiego przypomnienia jak używać deklaracji typów w Pythonie (nawet jeśli nie używasz FastAPI), sprawdź krótki samouczek: [Python Types](python-types.md){.internal-link target=_blank}.
Wystarczy, że napiszesz standardowe deklaracje typów Pythona:
```Python
from datetime import date
from pydantic import BaseModel
# Zadeklaruj parametr jako str
# i uzyskaj wsparcie edytora wewnątrz funkcji
def main(user_id: str):
return user_id
# Model Pydantic
class User(BaseModel):
id: int
name: str
joined: date
```
A one będą mogły zostać później użyte w następujący sposób:
```Python
my_user: User = User(id=3, name="John Doe", joined="2018-07-19")
second_user_data = {
"id": 4,
"name": "Mary",
"joined": "2018-11-30",
}
my_second_user: User = User(**second_user_data)
```
!!! info
`**second_user_data` oznacza:
Przekaż klucze i wartości słownika `second_user_data` bezpośrednio jako argumenty klucz-wartość, co jest równoznaczne z: `User(id=4, name="Mary", joined="2018-11-30")`
### Wsparcie edytora
Cały framework został zaprojektowany tak, aby był łatwy i intuicyjny w użyciu. Wszystkie pomysły zostały przetestowane na wielu edytorach jeszcze przed rozpoczęciem procesu tworzenia, aby zapewnić najlepsze wrażenia programistyczne.
Ostatnia ankieta <abbr title="coroczna ankieta przeprowadza w środowisku programistów języka Python">Python developer survey</abbr> jasno wskazuje, że <a href="https://www.jetbrains.com/research/python-developers-survey-2017/#tools-and-features" class="external-link" target="_blank">najczęściej używaną funkcjonalnością jest autouzupełnianie w edytorze</a>.
Cała struktura frameworku **FastAPI** jest na tym oparta. Autouzupełnianie działa wszędzie.
Rzadko będziesz musiał wracać do dokumentacji.
Oto, jak twój edytor może Ci pomóc:
* <a href="https://code.visualstudio.com/" class="external-link" target="_blank">Visual Studio Code</a>:
![wsparcie edytora](https://fastapi.tiangolo.com/img/vscode-completion.png)
* <a href="https://www.jetbrains.com/pycharm/" class="external-link" target="_blank">PyCharm</a>:
![wsparcie edytora](https://fastapi.tiangolo.com/img/pycharm-completion.png)
Otrzymasz uzupełnienie nawet w miejscach, w których normalnie uzupełnienia nie ma. Na przykład klucz "price" w treści JSON (który mógł być zagnieżdżony), który pochodzi z zapytania.
Koniec z wpisywaniem błędnych nazw kluczy, przechodzeniem tam i z powrotem w dokumentacji lub przewijaniem w górę i w dół, aby sprawdzić, czy w końcu użyłeś nazwy `username` czy `user_name`.
### Zwięzłość
Wszystko posiada sensowne **domyślne wartości**. Wszędzie znajdziesz opcjonalne konfiguracje. Wszystkie parametry możesz dostroić, aby zrobić to co potrzebujesz do zdefiniowania API.
Ale domyślnie wszystko **"po prostu działa"**.
### Walidacja
* Walidacja większości (lub wszystkich?) **typów danych** Pythona, w tym:
* Obiektów JSON (`dict`).
* Tablic JSON (`list`) ze zdefiniowanym typem elementów.
* Pól tekstowych (`str`) z określeniem minimalnej i maksymalnej długości.
* Liczb (`int`, `float`) z wartościami minimalnymi, maksymalnymi, itp.
* Walidacja bardziej egzotycznych typów danych, takich jak:
* URL.
* Email.
* UUID.
* ...i inne.
Cała walidacja jest obsługiwana przez ugruntowaną i solidną bibliotekę **Pydantic**.
### Bezpieczeństwo i uwierzytelnianie
Bezpieczeństwo i uwierzytelnianie jest zintegrowane. Bez żadnych kompromisów z bazami czy modelami danych.
Wszystkie schematy bezpieczeństwa zdefiniowane w OpenAPI, w tym:
* Podstawowy protokół HTTP.
* **OAuth2** (również z **tokenami JWT**). Sprawdź samouczek [OAuth2 with JWT](tutorial/security/oauth2-jwt.md){.internal-link target=_blank}.
* Klucze API w:
* Nagłówkach.
* Parametrach zapytań.
* Ciasteczkach, itp.
Plus wszystkie funkcje bezpieczeństwa Starlette (włączając w to **<abbr title="po angielsku: session cookies">ciasteczka sesyjne</abbr>**).
Wszystko zbudowane jako narzędzia i komponenty wielokrotnego użytku, które można łatwo zintegrować z systemami, magazynami oraz bazami danych - relacyjnymi, NoSQL, itp.
### Wstrzykiwanie Zależności
FastAPI zawiera niezwykle łatwy w użyciu, ale niezwykle potężny system <abbr title='Po angielsku: Dependency Injection. Znane również jako "components", "resources", "services", "providers"'><strong>Wstrzykiwania Zależności</strong></abbr>.
* Nawet zależności mogą mieć zależności, tworząc hierarchię lub **"graf" zależności**.
* Wszystko jest **obsługiwane automatycznie** przez framework.
* Wszystkie zależności mogą wymagać danych w żądaniach oraz rozszerzać ograniczenia i automatyczną dokumentację **<abbr title="po angielsku: path operations">operacji na ścieżce</abbr>**.
* **Automatyczna walidacja** parametrów *operacji na ścieżce* zdefiniowanych w zależnościach.
* Obsługa złożonych systemów uwierzytelniania użytkowników, **połączeń z bazami danych**, itp.
* Bazy danych, front end, itp. **bez kompromisów**, ale wciąż łatwe do integracji.
### Nieograniczone "wtyczki"
Lub ujmując to inaczej - brak potrzeby wtyczek. Importuj i używaj kod, który potrzebujesz.
Każda integracja została zaprojektowana tak, aby była tak prosta w użyciu (z zależnościami), że możesz utworzyć "wtyczkę" dla swojej aplikacji w 2 liniach kodu, używając tej samej struktury i składni, które są używane w *operacjach na ścieżce*.
### Testy
* 100% <abbr title="Ilość kodu, który jest automatycznie testowany">pokrycia kodu testami</abbr>.
* 100% <abbr title="Deklaracje typów Python - dzięki nim twój edytor i zewnętrzne narzędzia mogą zapewnić Ci lepsze wsparcie ">adnotacji typów</abbr>.
* Używany w aplikacjach produkcyjnych.
## Cechy Starlette
**FastAPI** jest w pełni kompatybilny z (oraz bazuje na) <a href="https://www.starlette.io/" class="external-link" target="_blank"><strong>Starlette</strong></a>. Tak więc każdy dodatkowy kod Starlette, który posiadasz, również będzie działał.
`FastAPI` jest w rzeczywistości podklasą `Starlette`, więc jeśli już znasz lub używasz Starlette, większość funkcji będzie działać w ten sam sposób.
Dzięki **FastAPI** otrzymujesz wszystkie funkcje **Starlette** (ponieważ FastAPI to po prostu Starlette na sterydach):
* Bardzo imponująca wydajność. Jest to <a href="https://github.com/encode/starlette#performance" class="external-link" target="_blank">jeden z najszybszych dostępnych frameworków Pythona, na równi z **NodeJS** i **Go**</a>.
* Wsparcie dla **WebSocket**.
* <abbr title='Zadania wykonywane w tle, bez zatrzymywania żądań, w tym samym procesie. Po angielsku: In-process background tasks'>Zadania w tle</abbr>.
* Eventy startup i shutdown.
* Klient testowy zbudowany na bazie biblioteki `requests`.
* **CORS**, GZip, pliki statyczne, streamy.
* Obsługa **sesji i ciasteczek**.
* 100% pokrycie testami.
* 100% adnotacji typów.
## Cechy Pydantic
**FastAPI** jest w pełni kompatybilny z (oraz bazuje na) <a href="https://pydantic-docs.helpmanual.io" class="external-link" target="_blank"><strong>Pydantic</strong></a>. Tak więc każdy dodatkowy kod Pydantic, który posiadasz, również będzie działał.
Wliczając w to zewnętrzne biblioteki, również oparte o Pydantic, takie jak <abbr title="Mapowanie obiektowo-relacyjne. Po angielsku: Object-Relational Mapper">ORM</abbr>, <abbr title="Object-Document Mapper">ODM</abbr> dla baz danych.
Oznacza to, że w wielu przypadkach możesz przekazać ten sam obiekt, który otrzymasz z żądania **bezpośrednio do bazy danych**, ponieważ wszystko jest walidowane automatycznie.
Działa to również w drugą stronę, w wielu przypadkach możesz po prostu przekazać obiekt otrzymany z bazy danych **bezpośrednio do klienta**.
Dzięki **FastAPI** otrzymujesz wszystkie funkcje **Pydantic** (ponieważ FastAPI bazuje na Pydantic do obsługi wszystkich danych):
* **Bez prania mózgu**:
* Brak nowego mikrojęzyka do definiowania schematu, którego trzeba się nauczyć.
* Jeśli znasz adnotacje typów Pythona to wiesz jak używać Pydantic.
* Dobrze współpracuje z Twoim **<abbr title='Skrót od "Integrated Development Environment", podobne do edytora kodu'>IDE</abbr>/<abbr title="Program, który sprawdza Twój kod pod kątem błędów">linterem</abbr>/mózgiem**:
* Ponieważ struktury danych Pydantic to po prostu instancje klas, które definiujesz; autouzupełnianie, linting, mypy i twoja intuicja powinny działać poprawnie z Twoimi zwalidowanymi danymi.
* **Szybkość**:
* w <a href="https://pydantic-docs.helpmanual.io/benchmarks/" class="external-link" target="_blank">benchmarkach</a> Pydantic jest szybszy niż wszystkie inne testowane biblioteki.
* Walidacja **złożonych struktur**:
* Wykorzystanie hierarchicznych modeli Pydantic, Pythonowego modułu `typing` zawierającego `List`, `Dict`, itp.
* Walidatory umożliwiają jasne i łatwe definiowanie, sprawdzanie złożonych struktur danych oraz dokumentowanie ich jako JSON Schema.
* Możesz mieć głęboko **zagnieżdżone obiekty JSON** i wszystkie je poddać walidacji i adnotować.
* **Rozszerzalność**:
* Pydantic umożliwia zdefiniowanie niestandardowych typów danych lub rozszerzenie walidacji o metody na modelu, na których użyty jest dekorator walidatora.
* 100% pokrycie testami.

1
docs/pl/mkdocs.yml

@ -63,6 +63,7 @@ nav:
- tr: /tr/
- uk: /uk/
- zh: /zh/
- features.md
- Samouczek:
- tutorial/index.md
- tutorial/first-steps.md

382
docs/ru/docs/tutorial/body-nested-models.md

@ -0,0 +1,382 @@
# Body - Вложенные модели
С помощью **FastAPI**, вы можете определять, валидировать, документировать и использовать модели произвольной вложенности (благодаря библиотеке Pydantic).
## Определение полей содержащих списки
Вы можете определять атрибут как подтип. Например, тип `list` в Python:
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial001.py!}
```
Это приведёт к тому, что обьект `tags` преобразуется в список, несмотря на то что тип его элементов не объявлен.
## Определение полей содержащих список с определением типов его элементов
Однако в Python есть способ объявления списков с указанием типов для вложенных элементов:
### Импортируйте `List` из модуля typing
В Python 3.9 и выше вы можете использовать стандартный тип `list` для объявления аннотаций типов, как мы увидим ниже. 💡
Но в версиях Python до 3.9 (начиная с 3.6) сначала вам необходимо импортировать `List` из стандартного модуля `typing` в Python:
```Python hl_lines="1"
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```
### Объявление `list` с указанием типов для вложенных элементов
Объявление типов для элементов (внутренних типов) вложенных в такие типы как `list`, `dict`, `tuple`:
* Если у вас Python версии ниже чем 3.9, импортируйте их аналог из модуля `typing`
* Передайте внутренний(ие) тип(ы) как "параметры типа", используя квадратные скобки: `[` и `]`
В Python версии 3.9 это будет выглядеть так:
```Python
my_list: list[str]
```
В версиях Python до 3.9 это будет выглядеть так:
```Python
from typing import List
my_list: List[str]
```
Это всё стандартный синтаксис Python для объявления типов.
Используйте этот же стандартный синтаксис для атрибутов модели с внутренними типами.
Таким образом, в нашем примере мы можем явно указать тип данных для поля `tags` как "список строк":
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial002_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial002.py!}
```
## Типы множеств
Но затем мы подумали и поняли, что теги не должны повторяться и, вероятно, они должны быть уникальными строками.
И в Python есть специальный тип данных для множеств уникальных элементов - `set`.
Тогда мы может обьявить поле `tags` как множество строк:
=== "Python 3.10+"
```Python hl_lines="12"
{!> ../../../docs_src/body_nested_models/tutorial003_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="14"
{!> ../../../docs_src/body_nested_models/tutorial003_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 14"
{!> ../../../docs_src/body_nested_models/tutorial003.py!}
```
С помощью этого, даже если вы получите запрос с повторяющимися данными, они будут преобразованы в множество уникальных элементов.
И когда вы выводите эти данные, даже если исходный набор содержал дубликаты, они будут выведены в виде множества уникальных элементов.
И они также будут соответствующим образом аннотированы / задокументированы.
## Вложенные Модели
У каждого атрибута Pydantic-модели есть тип.
Но этот тип может сам быть другой моделью Pydantic.
Таким образом вы можете объявлять глубоко вложенные JSON "объекты" с определёнными именами атрибутов, типами и валидацией.
Всё это может быть произвольно вложенным.
### Определение подмодели
Например, мы можем определить модель `Image`:
=== "Python 3.10+"
```Python hl_lines="7-9"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9-11"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```
### Использование вложенной модели в качестве типа
Также мы можем использовать эту модель как тип атрибута:
=== "Python 3.10+"
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial004_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial004.py!}
```
Это означает, что **FastAPI** будет ожидать тело запроса, аналогичное этому:
```JSON
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"tags": ["rock", "metal", "bar"],
"image": {
"url": "http://example.com/baz.jpg",
"name": "The Foo live"
}
}
```
Ещё раз: сделав такое объявление, с помощью **FastAPI** вы получите:
* Поддержку редакторов IDE (автодополнение и т.д), даже для вложенных моделей
* Преобразование данных
* Валидацию данных
* Автоматическую документацию
## Особые типы и валидация
Помимо обычных простых типов, таких как `str`, `int`, `float`, и т.д. Вы можете использовать более сложные базовые типы, которые наследуются от типа `str`.
Чтобы увидеть все варианты, которые у вас есть, ознакомьтесь с документацией <a href="https://pydantic-docs.helpmanual.io/usage/types/" class="external-link" target="_blank">по необычным типам Pydantic</a>. Вы увидите некоторые примеры в следующей главе.
Например, так как в модели `Image` у нас есть поле `url`, то мы можем объявить его как тип `HttpUrl` из модуля Pydantic вместо типа `str`:
=== "Python 3.10+"
```Python hl_lines="2 8"
{!> ../../../docs_src/body_nested_models/tutorial005_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="4 10"
{!> ../../../docs_src/body_nested_models/tutorial005.py!}
```
Строка будет проверена на соответствие допустимому URL-адресу и задокументирована в JSON схему / OpenAPI.
## Атрибуты, содержащие списки подмоделей
Вы также можете использовать модели Pydantic в качестве типов вложенных в `list`, `set` и т.д:
=== "Python 3.10+"
```Python hl_lines="18"
{!> ../../../docs_src/body_nested_models/tutorial006_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="20"
{!> ../../../docs_src/body_nested_models/tutorial006.py!}
```
Такая реализация будет ожидать (конвертировать, валидировать, документировать и т.д) JSON-содержимое в следующем формате:
```JSON hl_lines="11"
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"tags": [
"rock",
"metal",
"bar"
],
"images": [
{
"url": "http://example.com/baz.jpg",
"name": "The Foo live"
},
{
"url": "http://example.com/dave.jpg",
"name": "The Baz"
}
]
}
```
!!! info "Информация"
Заметьте, что теперь у ключа `images` есть список объектов изображений.
## Глубоко вложенные модели
Вы можете определять модели с произвольным уровнем вложенности:
=== "Python 3.10+"
```Python hl_lines="7 12 18 21 25"
{!> ../../../docs_src/body_nested_models/tutorial007_py310.py!}
```
=== "Python 3.9+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 14 20 23 27"
{!> ../../../docs_src/body_nested_models/tutorial007.py!}
```
!!! info "Информация"
Заметьте, что у объекта `Offer` есть список объектов `Item`, которые, в свою очередь, могут содержать необязательный список объектов `Image`
## Тела с чистыми списками элементов
Если верхний уровень значения тела JSON-объекта представляет собой JSON `array` (в Python - `list`), вы можете объявить тип в параметре функции, так же, как в моделях Pydantic:
```Python
images: List[Image]
```
в Python 3.9 и выше:
```Python
images: list[Image]
```
например так:
=== "Python 3.9+"
```Python hl_lines="13"
{!> ../../../docs_src/body_nested_models/tutorial008_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="15"
{!> ../../../docs_src/body_nested_models/tutorial008.py!}
```
## Универсальная поддержка редактора
И вы получаете поддержку редактора везде.
Даже для элементов внутри списков:
<img src="/img/tutorial/body-nested-models/image01.png">
Вы не могли бы получить такую поддержку редактора, если бы работали напрямую с `dict`, а не с моделями Pydantic.
Но вы также не должны беспокоиться об этом, входящие словари автоматически конвертируются, а ваш вывод также автоматически преобразуется в формат JSON.
## Тела запросов с произвольными словарями (`dict` )
Вы также можете объявить тело запроса как `dict` с ключами определенного типа и значениями другого типа данных.
Без необходимости знать заранее, какие значения являются допустимыми для имён полей/атрибутов (как это было бы в случае с моделями Pydantic).
Это было бы полезно, если вы хотите получить ключи, которые вы еще не знаете.
---
Другой полезный случай - когда вы хотите чтобы ключи были другого типа данных, например, `int`.
Именно это мы сейчас и увидим здесь.
В этом случае вы принимаете `dict`, пока у него есть ключи типа `int` со значениями типа `float`:
=== "Python 3.9+"
```Python hl_lines="7"
{!> ../../../docs_src/body_nested_models/tutorial009_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="9"
{!> ../../../docs_src/body_nested_models/tutorial009.py!}
```
!!! tip "Совет"
Имейте в виду, что JSON поддерживает только ключи типа `str`.
Но Pydantic обеспечивает автоматическое преобразование данных.
Это значит, что даже если пользователи вашего API могут отправлять только строки в качестве ключей, при условии, что эти строки содержат целые числа, Pydantic автоматический преобразует и валидирует эти данные.
А `dict`, с именем `weights`, который вы получите в качестве ответа Pydantic, действительно будет иметь ключи типа `int` и значения типа `float`.
## Резюме
С помощью **FastAPI** вы получаете максимальную гибкость, предоставляемую моделями Pydantic, сохраняя при этом простоту, краткость и элегантность вашего кода.
И дополнительно вы получаете:
* Поддержку редактора (автодополнение доступно везде!)
* Преобразование данных (также известно как парсинг / сериализация)
* Валидацию данных
* Документацию схемы данных
* Автоматическую генерацию документации

84
docs/ru/docs/tutorial/cors.md

@ -0,0 +1,84 @@
# CORS (Cross-Origin Resource Sharing)
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Понятие CORS или "Cross-Origin Resource Sharing"</a> относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом "источнике" ("origin").
## Источник
Источник - это совокупность протокола (`http`, `https`), домена (`myapp.com`, `localhost`, `localhost.tiangolo.com`) и порта (`80`, `443`, `8080`).
Поэтому это три разных источника:
* `http://localhost`
* `https://localhost`
* `http://localhost:8080`
Даже если они все расположены в `localhost`, они используют разные протоколы и порты, а значит, являются разными источниками.
## Шаги
Допустим, у вас есть фронтенд, запущенный в браузере по адресу `http://localhost:8080`, и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу `http://localhost` (поскольку мы не указали порт, браузер по умолчанию будет использовать порт `80`).
Затем браузер отправит бэкенду HTTP-запрос `OPTIONS`, и если бэкенд вернёт соответствующие заголовки для авторизации взаимодействия с другим источником (`http://localhost:8080`), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд.
Чтобы это работало, у бэкенда должен быть список "разрешённых источников" ("allowed origins").
В таком случае этот список должен содержать `http://localhost:8080`, чтобы фронтенд работал корректно.
## Подстановочный символ `"*"`
В качестве списка источников можно указать подстановочный символ `"*"` ("wildcard"), чтобы разрешить любые источники.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п.
Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.
## Использование `CORSMiddleware`
Вы можете настроить этот механизм в вашем **FastAPI** приложении, используя `CORSMiddleware`.
* Импортируйте `CORSMiddleware`.
* Создайте список разрешённых источников (в виде строк).
* Добавьте его как "middleware" к вашему **FastAPI** приложению.
Вы также можете указать, разрешает ли ваш бэкенд использование:
* Учётных данных (включая заголовки Authorization, куки и т.п.).
* Отдельных HTTP-методов (`POST`, `PUT`) или всех вместе, используя `"*"`.
* Отдельных HTTP-заголовков или всех вместе, используя `"*"`.
```Python hl_lines="2 6-11 13-19"
{!../../../docs_src/cors/tutorial001.py!}
```
`CORSMiddleware` использует для параметров "запрещающие" значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
Поддерживаются следующие аргументы:
* `allow_origins` - Список источников, на которые разрешено выполнять кросс-доменные запросы. Например, `['https://example.org', 'https://www.example.org']`. Можно использовать `['*']`, чтобы разрешить любые источники.
* `allow_origin_regex` - Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, `'https://.*\.example\.org'`.
* `allow_methods` - Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию равно `['GET']`. Можно использовать `['*']`, чтобы разрешить все стандартные методы.
* `allow_headers` - Список HTTP-заголовков, которые должны поддерживаться при кросс-доменных запросах. По умолчанию равно `[]`. Можно использовать `['*']`, чтобы разрешить все заголовки. Заголовки `Accept`, `Accept-Language`, `Content-Language` и `Content-Type` всегда разрешены для <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests" class="external-link" rel="noopener" target="_blank">простых CORS-запросов</a>.
* `allow_credentials` - указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно `False`. Также, `allow_origins` нельзя присвоить `['*']`, если разрешено использование учётных данных. В таком случае должен быть указан список источников.
* `expose_headers` - Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию равно `[]`.
* `max_age` - Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию равно `600`.
`CORSMiddleware` отвечает на два типа HTTP-запросов...
### CORS-запросы с предварительной проверкой
Это любые `OPTIONS` запросы с заголовками `Origin` и `Access-Control-Request-Method`.
В этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ `200` или `400` в информационных целях.
### Простые запросы
Любые запросы с заголовком `Origin`. В этом случае middleware передаст запрос дальше как обычно, но добавит соответствующие CORS-заголовки к ответу.
## Больше информации
Для получения более подробной информации о <abbr title="Cross-Origin Resource Sharing">CORS</abbr>, обратитесь к <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS" class="external-link" target="_blank">Документации CORS от Mozilla</a>.
!!! note "Технические детали"
Вы также можете использовать `from starlette.middleware.cors import CORSMiddleware`.
**FastAPI** предоставляет несколько middleware в `fastapi.middleware` только для вашего удобства как разработчика. Но большинство доступных middleware взяты напрямую из Starlette.

252
docs/ru/docs/tutorial/extra-models.md

@ -0,0 +1,252 @@
# Дополнительные модели
В продолжение прошлого примера будет уже обычным делом иметь несколько связанных между собой моделей.
Это особенно применимо в случае моделей пользователя, потому что:
* **Модель для ввода** должна иметь возможность содержать пароль.
* **Модель для вывода** не должна содержать пароль.
* **Модель для базы данных**, возможно, должна содержать хэшированный пароль.
!!! danger "Внимание"
Никогда не храните пароли пользователей в чистом виде. Всегда храните "безопасный хэш", который вы затем сможете проверить.
Если вам это не знакомо, вы можете узнать про "хэш пароля" в [главах о безопасности](security/simple-oauth2.md#password-hashing){.internal-link target=_blank}.
## Множественные модели
Ниже изложена основная идея того, как могут выглядеть эти модели с полями для паролей, а также описаны места, где они используются:
=== "Python 3.10+"
```Python hl_lines="7 9 14 20 22 27-28 31-33 38-39"
{!> ../../../docs_src/extra_models/tutorial001_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 11 16 22 24 29-30 33-35 40-41"
{!> ../../../docs_src/extra_models/tutorial001.py!}
```
### Про `**user_in.dict()`
#### `.dict()` из Pydantic
`user_in` - это Pydantic-модель класса `UserIn`.
У Pydantic-моделей есть метод `.dict()`, который возвращает `dict` с данными модели.
Поэтому, если мы создадим Pydantic-объект `user_in` таким способом:
```Python
user_in = UserIn(username="john", password="secret", email="[email protected]")
```
и затем вызовем:
```Python
user_dict = user_in.dict()
```
то теперь у нас есть `dict` с данными модели в переменной `user_dict` (это `dict` вместо объекта Pydantic-модели).
И если мы вызовем:
```Python
print(user_dict)
```
мы можем получить `dict` с такими данными:
```Python
{
'username': 'john',
'password': 'secret',
'email': '[email protected]',
'full_name': None,
}
```
#### Распаковка `dict`
Если мы возьмём `dict` наподобие `user_dict` и передадим его в функцию (или класс), используя `**user_dict`, Python распакует его. Он передаст ключи и значения `user_dict` напрямую как аргументы типа ключ-значение.
Поэтому, продолжая описанный выше пример с `user_dict`, написание такого кода:
```Python
UserInDB(**user_dict)
```
Будет работать так же, как примерно такой код:
```Python
UserInDB(
username="john",
password="secret",
email="[email protected]",
full_name=None,
)
```
Или, если для большей точности мы напрямую используем `user_dict` с любым потенциальным содержимым, то этот пример будет выглядеть так:
```Python
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
)
```
#### Pydantic-модель из содержимого другой модели
Как в примере выше мы получили `user_dict` из `user_in.dict()`, этот код:
```Python
user_dict = user_in.dict()
UserInDB(**user_dict)
```
будет равнозначен такому:
```Python
UserInDB(**user_in.dict())
```
...потому что `user_in.dict()` - это `dict`, и затем мы указываем, чтобы Python его "распаковал", когда передаём его в `UserInDB` и ставим перед ним `**`.
Таким образом мы получаем Pydantic-модель на основе данных из другой Pydantic-модели.
#### Распаковка `dict` и дополнительные именованные аргументы
И затем, если мы добавим дополнительный именованный аргумент `hashed_password=hashed_password` как здесь:
```Python
UserInDB(**user_in.dict(), hashed_password=hashed_password)
```
... то мы получим что-то подобное:
```Python
UserInDB(
username = user_dict["username"],
password = user_dict["password"],
email = user_dict["email"],
full_name = user_dict["full_name"],
hashed_password = hashed_password,
)
```
!!! warning "Предупреждение"
Цель использованных в примере вспомогательных функций - не более чем демонстрация возможных операций с данными, но, конечно, они не обеспечивают настоящую безопасность.
## Сократите дублирование
Сокращение дублирования кода - это одна из главных идей **FastAPI**.
Поскольку дублирование кода повышает риск появления багов, проблем с безопасностью, проблем десинхронизации кода (когда вы обновляете код в одном месте, но не обновляете в другом), и т.д.
А все описанные выше модели используют много общих данных и дублируют названия атрибутов и типов.
Мы можем это улучшить.
Мы можем определить модель `UserBase`, которая будет базовой для остальных моделей. И затем мы можем создать подклассы этой модели, которые будут наследовать её атрибуты (объявления типов, валидацию, и т.п.).
Все операции конвертации, валидации, документации, и т.п. будут по-прежнему работать нормально.
В этом случае мы можем определить только различия между моделями (с `password` в чистом виде, с `hashed_password` и без пароля):
=== "Python 3.10+"
```Python hl_lines="7 13-14 17-18 21-22"
{!> ../../../docs_src/extra_models/tutorial002_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="9 15-16 19-20 23-24"
{!> ../../../docs_src/extra_models/tutorial002.py!}
```
## `Union` или `anyOf`
Вы можете определить ответ как `Union` из двух типов. Это означает, что ответ должен соответствовать одному из них.
Он будет определён в OpenAPI как `anyOf`.
Для этого используйте стандартные аннотации типов в Python <a href="https://docs.python.org/3/library/typing.html#typing.Union" class="external-link" target="_blank">`typing.Union`</a>:
!!! note "Примечание"
При объявлении <a href="https://pydantic-docs.helpmanual.io/usage/types/#unions" class="external-link" target="_blank">`Union`</a>, сначала указывайте наиболее детальные типы, затем менее детальные. В примере ниже более детальный `PlaneItem` стоит перед `CarItem` в `Union[PlaneItem, CarItem]`.
=== "Python 3.10+"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003_py310.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 14-15 18-20 33"
{!> ../../../docs_src/extra_models/tutorial003.py!}
```
### `Union` в Python 3.10
В этом примере мы передаём `Union[PlaneItem, CarItem]` в качестве значения аргумента `response_model`.
Поскольку мы передаём его как **значение аргумента** вместо того, чтобы поместить его в **аннотацию типа**, нам придётся использовать `Union` даже в Python 3.10.
Если оно было бы указано в аннотации типа, то мы могли бы использовать вертикальную черту как в примере:
```Python
some_variable: PlaneItem | CarItem
```
Но если мы помещаем его в `response_model=PlaneItem | CarItem` мы получим ошибку, потому что Python попытается произвести **некорректную операцию** между `PlaneItem` и `CarItem` вместо того, чтобы интерпретировать это как аннотацию типа.
## Список моделей
Таким же образом вы можете определять ответы как списки объектов.
Для этого используйте `typing.List` из стандартной библиотеки Python (или просто `list` в Python 3.9 и выше):
=== "Python 3.9+"
```Python hl_lines="18"
{!> ../../../docs_src/extra_models/tutorial004_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 20"
{!> ../../../docs_src/extra_models/tutorial004.py!}
```
## Ответ с произвольным `dict`
Вы также можете определить ответ, используя произвольный одноуровневый `dict` и определяя только типы ключей и значений без использования Pydantic-моделей.
Это полезно, если вы заранее не знаете корректных названий полей/атрибутов (которые будут нужны при использовании Pydantic-модели).
В этом случае вы можете использовать `typing.Dict` (или просто `dict` в Python 3.9 и выше):
=== "Python 3.9+"
```Python hl_lines="6"
{!> ../../../docs_src/extra_models/tutorial005_py39.py!}
```
=== "Python 3.6+"
```Python hl_lines="1 8"
{!> ../../../docs_src/extra_models/tutorial005.py!}
```
## Резюме
Используйте несколько Pydantic-моделей и свободно применяйте наследование для каждой из них.
Вам не обязательно иметь единственную модель данных для каждой сущности, если эта сущность должна иметь возможность быть в разных "состояниях". Как в случае с "сущностью" пользователя, у которого есть состояния с полями `password`, `password_hash` и без пароля.

3
docs/ru/mkdocs.yml

@ -77,12 +77,15 @@ nav:
- tutorial/extra-data-types.md
- tutorial/cookie-params.md
- tutorial/testing.md
- tutorial/extra-models.md
- tutorial/response-status-code.md
- tutorial/query-params.md
- tutorial/body-multiple-params.md
- tutorial/cors.md
- tutorial/static-files.md
- tutorial/debugging.md
- tutorial/schema-extra-example.md
- tutorial/body-nested-models.md
- async.md
- Развёртывание:
- deployment/index.md

7
docs_src/sql_databases/sql_app/tests/test_sql_app.py

@ -1,14 +1,17 @@
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool
from ..database import Base
from ..main import app, get_db
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
SQLALCHEMY_DATABASE_URL = "sqlite://"
engine = create_engine(
SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}
SQLALCHEMY_DATABASE_URL,
connect_args={"check_same_thread": False},
poolclass=StaticPool,
)
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

2
fastapi/applications.py

@ -62,6 +62,7 @@ class FastAPI(Starlette):
servers: Optional[List[Dict[str, Union[str, Any]]]] = None,
dependencies: Optional[Sequence[Depends]] = None,
default_response_class: Type[Response] = Default(JSONResponse),
redirect_slashes: bool = True,
docs_url: Optional[str] = "/docs",
redoc_url: Optional[str] = "/redoc",
swagger_ui_oauth2_redirect_url: Optional[str] = "/docs/oauth2-redirect",
@ -127,6 +128,7 @@ class FastAPI(Starlette):
self.dependency_overrides: Dict[Callable[..., Any], Callable[..., Any]] = {}
self.router: routing.APIRouter = routing.APIRouter(
routes=routes,
redirect_slashes=redirect_slashes,
dependency_overrides_provider=self,
on_startup=on_startup,
on_shutdown=on_shutdown,

3
pyproject.toml

@ -1,5 +1,5 @@
[build-system]
requires = ["hatchling"]
requires = ["hatchling >= 1.13.0"]
build-backend = "hatchling.build"
[project]
@ -49,6 +49,7 @@ dynamic = ["version"]
[project.urls]
Homepage = "https://github.com/tiangolo/fastapi"
Documentation = "https://fastapi.tiangolo.com/"
Repository = "https://github.com/tiangolo/fastapi"
[project.optional-dependencies]
all = [

4
tests/test_param_include_in_schema.py

@ -33,7 +33,7 @@ async def hidden_query(
return {"hidden_query": hidden_query}
openapi_shema = {
openapi_schema = {
"openapi": "3.0.2",
"info": {"title": "FastAPI", "version": "0.1.0"},
"paths": {
@ -162,7 +162,7 @@ def test_openapi_schema():
client = TestClient(app)
response = client.get("/openapi.json")
assert response.status_code == 200
assert response.json() == openapi_shema
assert response.json() == openapi_schema
@pytest.mark.parametrize(

40
tests/test_router_redirect_slashes.py

@ -0,0 +1,40 @@
from fastapi import APIRouter, FastAPI
from fastapi.testclient import TestClient
def test_redirect_slashes_enabled():
app = FastAPI()
router = APIRouter()
@router.get("/hello/")
def hello_page() -> str:
return "Hello, World!"
app.include_router(router)
client = TestClient(app)
response = client.get("/hello/", follow_redirects=False)
assert response.status_code == 200
response = client.get("/hello", follow_redirects=False)
assert response.status_code == 307
def test_redirect_slashes_disabled():
app = FastAPI(redirect_slashes=False)
router = APIRouter()
@router.get("/hello/")
def hello_page() -> str:
return "Hello, World!"
app.include_router(router)
client = TestClient(app)
response = client.get("/hello/", follow_redirects=False)
assert response.status_code == 200
response = client.get("/hello", follow_redirects=False)
assert response.status_code == 404

12
tests/test_schema_extra_examples.py

@ -42,7 +42,7 @@ def examples(
@app.post("/example_examples/")
def example_examples(
item: Item = Body(
example={"data": "Overriden example"},
example={"data": "Overridden example"},
examples={
"example1": {"value": {"data": "examples example_examples 1"}},
"example2": {"value": {"data": "examples example_examples 2"}},
@ -76,7 +76,7 @@ def example_examples(
# def form_example_examples(
# lastname: str = Form(
# ...,
# example="Doe overriden",
# example="Doe overridden",
# examples={
# "example1": {"summary": "last name summary", "value": "Doe"},
# "example2": {"value": "Doesn't"},
@ -110,7 +110,7 @@ def path_examples(
@app.get("/path_example_examples/{item_id}")
def path_example_examples(
item_id: str = Path(
example="item_overriden",
example="item_overridden",
examples={
"example1": {"summary": "item ID summary", "value": "item_1"},
"example2": {"value": "item_2"},
@ -147,7 +147,7 @@ def query_examples(
def query_example_examples(
data: Union[str, None] = Query(
default=None,
example="query_overriden",
example="query_overridden",
examples={
"example1": {"summary": "Query example 1", "value": "query1"},
"example2": {"value": "query2"},
@ -184,7 +184,7 @@ def header_examples(
def header_example_examples(
data: Union[str, None] = Header(
default=None,
example="header_overriden",
example="header_overridden",
examples={
"example1": {"summary": "Query example 1", "value": "header1"},
"example2": {"value": "header2"},
@ -221,7 +221,7 @@ def cookie_examples(
def cookie_example_examples(
data: Union[str, None] = Cookie(
default=None,
example="cookie_overriden",
example="cookie_overridden",
examples={
"example1": {"summary": "Query example 1", "value": "cookie1"},
"example2": {"value": "cookie2"},

Loading…
Cancel
Save