Продолжим работать над нашим CRUD проектом, а именно добавим модели. И посмотрим на их преимущества и особенности. Как выглядит наш код на этом этапе вы можете посмотреть по этой ссылке на GitHub.
Продолжим работать с нашим кодом, первым делом добавим модели:
from pydantic import BaseModel
class Message(BaseModel):
id: int
text: str
По аналогии, как и раньше, наши записи содержат поля ID и текста. Ранее в функции, отвечающей за POST запрос, мы принимали параметр message: str = Body(), и далее увеличивали значение ID и записывали в словарь данные. Но так как использовать вложенный словарь в словаре в качестве БД тут будет не совсем уместно, первым делом переделаем нашу БД в виде списка:
messages_db = []
В результате чего, мы будем иметь следующую структуру нашей БД (списка)
[
{
"id": 0,
"text": "string"
},
{
"id": 1,
"text": "string"
},
{
"id": 2,
"text": "string"
}
]
Перейдем непосредственно к функции create_message и внесем следующие изменения:
@app.post("/message", status_code=status.HTTP_201_CREATED)
async def create_message(message: Message) -> str:
if len(messages_db) == 0:
message.id = 0
else:
message.id = max([i.dict()['id'] for i in messages_db]) + 1
messages_db.append(message)
return f"Message created!"
Теперь мы принимаем в переменную message модель Message, которая содержит поля: message.id и message.text. Мы также увеличиваем значение ID исходя из максимального значения ID записи, прибавляем 1 и записываем модель в нашу БД(список), выводя сообщение об успешной записи. Если БД(список) пуст, то message.id будет равно 0.
Запустим приложение через команду uvicorn crud:app --port 8000 --reload и проверим работу. Зайдем в документацию, и перейдем в функцию, отвечающую за POST запросы.
И мы встречаем самое первое изменение, у нас теперь нет параметров запроса. То есть все параметры теперь всегда будут находиться внутри содержимого тела запроса. Второе изменение, это то, что теперь у нас есть пример содержимого тела запроса.
На данном этапе пока не будем ничего отправлять в запросе, перейдем дальше к изменениям функциям отвечающим за GET запросы.
В функции get_all_messages мы изменим вывод всех записей, а именно изменим вывод данных. А в функции get_message мы теперь получаем message_id как тип данных int, и далее с помощью индексов списка возвращаем запись.
from typing import List
@app.get("/")
async def get_all_messages() -> dict:
return {'Messages': messages_db}
@app.get(path="/message/{message_id}")
async def get_message(message_id: int):
return messages_db[message_id]
Перейдем к тестированию GET и POST запросов нашего приложения. Перейдя в POST запросы, мы не будем менять содержимое полей, и просто несколько раз нажмем кнопку Execute
Мы также видим что содержимое находится внутри тела запроса.
curl -X 'POST' \
'http://127.0.0.1:8000/message' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"id": 0,
"text": "string"
}'
Далее перейдем GET запрос вывода всех записей и получим все содержимое нашей БД (списка):
Мы видим что ID записи все также динамически изменяется, теперь попробуем получить запись с ID=2:
Мы видим что наш CRUD проект успешно работает через модели Pydantic. В следующем шаге мы продолжим дорабатывать эти функции, но и переделаем остальные функции нашего приложения.
@app.post("/message", status_code=status.HTTP_201_CREATED) async def create_message(message: Message) -> str: message.id = len(messages_db) messages_db.append(message) return f"Message created!"При такой реализации ID в конце списка могут дублироваться, если был удалён элемент из середины списка@Anonymous_38661511, согласен, совсем не подумал об этом. Поправил код в этом модуле, добавив проверку.