В предыдущей статье мы реализовали простой CRUD. Но из запросов данные не поступают, как планировалось. Например, мы хотим, чтобы имя нашего ученика было строковым, а не целочисленным или плавающим.
Для этой цели мы используем пакет Python с именем Pydantic.
pip install pydantic
После установки pydantic import BaseModel.
from pydantic import BaseModel
Теперь нам нужно создать нашу модель Pydantic для студентов, наследующих BaseModel.
class Student(BaseModel): name: str grade: str roll: int email: str phone: int subjects: List[str] friends: List[str]
Теперь мы создаем экземпляр Student [это только для демонстрационных целей].
student = Student( name=in_memory_student_db[0]["name"], grade=in_memory_student_db[0]["grade"], roll=in_memory_student_db[0]["roll"], email=in_memory_student_db[0]["email"], phone=in_memory_student_db[0]["phone"], subjects=in_memory_student_db[0]["subjects"], friends=in_memory_student_db[0]["friends"] ) or student = Student(**in_memory_student_db[0])
Оба способа мы можем создавать объекты Student.
Что делает класс pydantic?
- Класс pydantic позволяет определять пользовательские типы данных, или мы можем расширить валидацию с помощью методов на модели, украшенной декоратором валидатора.
- Здесь тип данных имени, оценки, списка, электронной почты, телефона, субъектов, друзей должен быть таким, как указано в классе pydantic, иначе это вызовет ошибку (ошибка проверки pydantic)
Но если вы передадите roll = «16», то он не будет показывать никаких ошибок, так как он преобразуется в целое число.
Теперь, поскольку мы создали класс Student, мы можем создать модель Student, а затем работать с этой моделью, поскольку она проверяет данные в нашей системе так, как мы хотим.
Чтобы получить сообщение об ошибке в формате JSON:
app.config.FALLBACK_ERROR_FORMAT = "json"
Поскольку объект Student не является сериализуемым JSON, мы используем метод dict и делаем объект Student JSON сериализуемым.
- Поскольку мы не хотим сохранять объекты Student в нашей реальной базе данных, скорее мы хотим отображать и вставлять данные в строки в случае SQL или как объекты JSON в NoSQL, поэтому мы конвертируем объект Student в словарь Python.
Зачем делать объект Student JSON сериализуемым?
- В Python «сериализация» не делает ничего, кроме преобразования заданной структуры данных (например,
dict
) в ее действительный объект JSON. JSON - это формат, который кодирует объекты в строку. Сериализация означает преобразование объекта в эту строку, а десериализация - это обратная операция (преобразование строки - ›объект). - При передаче ученика в файле, ученик должен быть байтовыми строками, но объекты Pydntic (здесь Student) редко бывают в этом формате. Сериализация может преобразовывать эти объекты Pydantic в байтовые строки для такого использования. После того, как байтовые строки будут переданы, получатель должен будет восстановить исходный объект из байтовой строки. Ref
- Нам нужны сериализуемые объекты JSON для предоставления HTTP-ответа.
Теперь мы модифицируем наш код в соответствии с объектом Student.
Для метода POST
@app.post("/") async def post_student(request): student = Student(**request.json) in_memory_student_db.append(student.dict()) return response.json("message":"inserted","data":student.dict())
- Мы запросим данные в формате JSON и передадим их классу Student, который вернет объект Student и сохранит его в переменной student.
- перед тем, как вставить объект Student в БД, мы преобразовали объект Student в словарь Python, а затем вставили его в базу данных.
- для только что вставленного ответа мы снова преобразовали объект Student в словарь Python.
Для метода PUT:
@app.put("/<id_:int>") async def update_student(request, id_): student = Student(**request.json) if id_ in range(len(in_memory_student_db)): in_memory_student_db[id_] = student.dict() return response.json({"message":"updated Successfully"}) return response.json({"error": "No Student with given id"})
- Мы передаем id и упоминаем, что id_ имеет целочисленный тип,
- Мы запросим обновление данных в формате JSON и передадим данные классу Student, который вернет объект Student и сохранит его в переменной student.
- перед тем, как вставить объекты учеников в БД, мы проверяем, существует ли указанный идентификатор.
- если id_ существует, мы преобразовали объект Student в словарь Python, а затем вставили его в базу данных и предоставили сообщение Success.
- в противном случае мы сообщаем об ошибке.
Для метода GET:
Поскольку получение данных из базы данных не требует проверки, но данные, которые должны быть вставлены в базу данных, должны быть проверены, поэтому мы не будем использовать модель ученика при извлечении данных.
@app.get("/") async def get_student(request): id_ = int(request.args.get("id", -1)) if id_ != -1: if id_ in range(len(in_memory_student_db)): return response.json(in_memory_student_db[id_]) else: return response.json( { "status": "error", "message": f"data with id {id_} not found. Try with different id!!!", }) return response.json(in_memory_student_db)
- Мы передаем идентификатор параметра запроса, чтобы получить данные определенного идентификатора. если параметру запроса не передается значение по умолчанию, если id_ равно -1
- если значение if id_ не равно -1, мы проверяем, существует ли id_ в базе данных, если существует, мы предоставляем ответ этих данных, иначе мы предоставляем данные с заданным идентификатором, который не найден.
- иначе мы предоставляем все данные, которые есть в базе данных. т.е. если значение id равно -1 (по умолчанию)
Теперь вы получите такой ответ:
Для метода DELETE
@app.delete("/<id_:int>") async def delete_student(request, id_): if id_ in range(len(in_memory_student_db)): del in_memory_student_db[id_] return response.json({"message": "Deleted student successfully"}) return response.json({"error": "No Student with given id"})
- Мы передаем id и упоминаем, что id_ имеет целочисленный тип,
- мы проверяем, существует ли id_ в базе данных, если существует, удаляем данные и даем ответ, что данные удалены
- в противном случае мы сообщаем об ошибке.
Таким образом, мы можем проверить наши данные, мы также можем использовать настраиваемые валидаторы в модели pydantic, например, если нам требуется принять имя, которое должно содержать пробел, тогда вы можете указать валидатор для этого,
from pydantic import validator @validator("name") def name_must_contain_space(cls, name): if " " not in name: raise ValueError("must contain a space") return name.title()
На этом операции CRUD завершены, и мы научились проверять данные с помощью пидантических моделей. В следующей серии вместо использования базы данных в памяти мы будем использовать СУБД для хранения наших данных.
Больше контента на plainenglish.io