数据库和ORMS:使用 Motor 跟 MongoDB 通信

文章目录

    • 1. 安装
    • 2. 创建models
    • 3. 连接数据库
    • 4. 插入文档
    • 5. 查询
    • 6. 更新、删除
    • 7. 嵌套文档

learn from 《Building Data Science Applications with FastAPI》

面向文档的数据库(如MongoDB)不需要预先配置模式

Motor,这是一个用于与 MongoDB 异步通信的库,由MongoDB组织官方支持

1. 安装

pip install motor
Successfully installed motor-2.5.1 pymongo-3.12.3

2. 创建models

  • MongoDB 会为每个文件创建 _id 属性作为唯一标识符,但是 _ 开头的变量被 Pydantic 认为是私有的,不会作为数据字段
  • _id 是二进制对象,不被 Pydantic 支持
# _*_ coding: utf-8 _*_
# @Time : 2022/3/23 14:37
# @Author : Michael
# @File : models.py
# @desc :from datetime import datetime
from typing import Optional
from bson import ObjectId  # A MongoDB ObjectId
from pydantic import BaseModel, Fieldclass PyObjectId(ObjectId):@classmethoddef __get_validators__(cls):yield cls.validate@classmethoddef validate(cls, v):if not ObjectId.is_valid(v):raise ValueError("Invalid objectid")return ObjectId(v)@classmethoddef __modify_schema__(cls, field_schema):field_schema.update(type="string")class MongoBaseModel(BaseModel):# PyObjectId 类的作用是 使得 ObjectId 成为 Pydantic 兼容的类型id: PyObjectId = Field(default_factory=PyObjectId, alias="_id")# alias 是一个 pydantic选项,在调用 dict 方法时,会转换为 _id 名,这是MongoDB需要的class Config:json_encoders = {ObjectId: str}# json序列化时,采用的映射方法,ObjectId自己实现了__str__,可以被映射为 strclass PostBase(MongoBaseModel):title: strcontent: strpublication_date: datetime = Field(default_factory=datetime.now)class PostPartialUpdate(BaseModel):title: Optional[str] = Nonecontent: Optional[str] = Noneclass PostCreate(PostBase):passclass PostDB(PostBase):pass

3. 连接数据库

https://docs.mongodb.com/manual/
reference/connection-string/

# _*_ coding: utf-8 _*_
# @Time : 2022/3/23 14:37
# @Author : Michael
# @File : app.py.py
# @desc :from typing import List, Tuple
from bson import ObjectId, errors  # BSON (Binary JSON) encoding and decoding
from fastapi import Depends, FastAPI, HTTPException, Query, status
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorDatabasefrom web_python_dev.mongo_motor.models import PostDB, PostCreate, PostPartialUpdateapp = FastAPI()
motor_client = AsyncIOMotorClient("mongodb://localhost:27017"
)
database = motor_client["cp6_mongodb"]  # 单个数据库实例def get_database() -> AsyncIOMotorDatabase:return database

4. 插入文档

async def pagination(skip: int = Query(0, ge=0),limit: int = Query(10, ge=0)) -> Tuple[int, int]:capped_limit = min(100, limit)return (skip, capped_limit)async def get_object_id(id: str) -> ObjectId:try:return ObjectId(id)except (errors.InvalidId, TypeError):raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)async def get_post_or_404(id: ObjectId = Depends(get_object_id),database: AsyncIOMotorDatabase = Depends(get_database)
) -> PostDB:raw_post = await database['posts'].find_one({"_id": id})if raw_post is None:raise HTTPException(status_code=status.HTTP_404_NOT_FOUND)return PostDB(**raw_post)
@app.post("/posts", response_model=PostDB, status_code=status.HTTP_201_CREATED)
async def create_post(post: PostCreate, database: AsyncIOMotorDatabase = Depends(get_database)
) -> PostDB:post_db = PostDB(**post.dict())await database["posts"].insert_one(post_db.dict(by_alias=True))# by_alias=True 使用 _id 来序列化post_db = await get_post_or_404(post_db.id, database)return post_db

测试之前需要 docker 开启服务

docker run -d --name fastapi-mongo -p 27017:27017 mongo:4.4

在这里插入图片描述

5. 查询

@app.get("/posts")
async def list_posts(pagination: Tuple[int, int] = Depends(pagination),database: AsyncIOMotorDatabase = Depends(get_database)
) -> List[PostDB]:skip, limit = paginationquery = database['posts'].find({}, skip=skip, limit=limit)# find 第一个参数 是过滤用的,我们要获取所有的,所以留空result = [PostDB(**raw_post) async for raw_post in query]# async 列表推导return result

在这里插入图片描述

@app.get("/posts/{id}", response_model=PostDB)
async def get_post(post: PostDB = Depends(get_post_or_404)) -> PostDB:return post

在这里插入图片描述

6. 更新、删除

@app.patch("/posts/{id}", response_model=PostDB)
async def update_post(post_update: PostPartialUpdate,post: PostDB = Depends(get_post_or_404),database: AsyncIOMotorDatabase = Depends(get_database),
) -> PostDB:await database["posts"].update_one({"_id": post.id}, {"$set": post_update.dict(exclude_unset=True)})post_db = await get_post_or_404(post.id, database)return post_db

在这里插入图片描述

@app.delete("/posts/{id}", status_code=status.HTTP_204_NO_CONTENT)
async def delete_post(post: PostDB = Depends(get_post_or_404),database: AsyncIOMotorDatabase = Depends(get_database),
):await database["posts"].delete_one({"_id": post.id})

7. 嵌套文档

如果我们想将 post 和 comment 一起存储

在 models.py 中添加

class CommentBase(BaseModel):publication_date: datetime = Field(default_factory=datetime.now)content: strclass CommentCreate(CommentBase):passclass CommentDB(CommentBase):passclass PostDB(PostBase):comments: List[CommentDB] = Field(default_factory=list)

现在我们在查询一下看看,发现 comments 也在结果当中
在这里插入图片描述
那我们要创建 comments 的内容

@app.post("/posts/{id}/comments", response_model=PostDB, status_code=status.HTTP_201_CREATED)
async def create_comment(comment:CommentCreate,post:PostDB=Depends(get_post_or_404),database:AsyncIOMotorDatabase=Depends(get_database))->PostDB:await database['posts'].update_one({'_id': post.id}, {'$push': {'comments': comment.dict()}})# $push操作。这是向列表属性添加元素的有用运算符post_db = await get_post_or_404(post.id, database)return post_db

更多update操作:https://www.mongodb.com/docs/manual/reference/operator/update/

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/471122.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

指令系统——数据寻址(2)(详解)

一、总览 二、偏移寻址 基址寻址:将CPU中基址寄存器(BR)的内容加上指令格式中的形式地址A,而形成操作数的有效地址,即EA(BR)A。 注:基址寄存器是面向操作系统的,其内容由…

十五、MySQL变量(系统变量、自定义变量)相关知识总结

变量: 系统变量: a.全局变量 b.会话变量 自定义变量: a.用户变量 b.局部变量 一、系统变量 说明:变量由系统定义,不是用户定义,属于服务器层面 注意:全局变量需要添加global关键字,会话变量…

LeetCode 2210. 统计数组中峰和谷的数量

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums 。如果两侧距 i 最近的不相等邻居的值均小于 nums[i] ,则下标 i 是 nums 中,某个峰的一部分。 类似地,如果两侧距 i 最近的不相等邻居的值均大于 nums[i] ,…

【项目总结】如何获取地图上的所有POI

1. 地图POI数据是什么,有什么用 关于地图数据123,可以参考一下这篇 https://www.zhihu.com/question/21530085/answer/18728706,回答了很多信息;下图是摘自其中,展示了建立一个地图需要的几个图层数据,从底…

十六、MySQL流程控制结构(顺序、分支、循环)详解 强化练习

流程控制结构:顺序、分支、循环 一、分支结构 case结构作为表达式: case结构作为独立的语句: if函数 语法:if(条件,值1,值2) 功能:实现双分支 应用在begin end中或外面 case结构 语法: 情…

LeetCode 2211. 统计道路上的碰撞次数

文章目录1. 题目2. 解题1. 题目 在一条无限长的公路上有 n 辆汽车正在行驶。汽车按从左到右的顺序按从 0 到 n - 1 编号,每辆车都在一个 独特的 位置。 给你一个下标从 0 开始的字符串 directions ,长度为 n 。 directions[i] 可以是 ‘L’、‘R’ 或 …

服务端的思考

概述 我们思考发布一个web服务需要做的工作,并进行职责的划分。职责的划分 通常我们会先制定抽象的接口,然后根据接口构造实现类。接口和实现类都完成了,再实施发布。所以,服务端的角色可以划分为:服务接口、服务实现、…

IPv6数据报详解

一、为什么有IPv6? 二、IPv6数据报格式 版本:指明了协议版本,总是6。 优先级:区分数据报的类别和优先级。 流标签:“流”是互联网络上从特定源点到特定终点的一系列数据报。所有属于同一个流的数据报都具有同样的流标签…

LeetCode 2212. 射箭比赛中的最大得分(状态枚举)

文章目录1. 题目2. 解题1. 题目 Alice 和 Bob 是一场射箭比赛中的对手。比赛规则如下: Alice 先射 numArrows 支箭,然后 Bob 也射 numArrows 支箭。 分数按下述规则计算: 箭靶有若干整数计分区域,范围从 0 到 11 (…

web前端复习系列[1]——标签

<h1>一般用于网站标题。加入强调语气&#xff0c;使用<strong>和<em>标签。<em> 表示强调&#xff0c;<strong> 表示更强烈的强调。并且在浏览器中<em> 默认用斜体表示&#xff0c;<strong> 用粗体表示。两个标签相比&#xff0c;目…

十七、MySQL触发器(创建、删除、查看)详解

触发器 一、介绍 触发器是与表有关的数据库对象&#xff0c;指在 insert/update/delete 之前或之后&#xff0c;触发并执行触发器中定义的SQL语句集合。触发器的这种特性可以协助应用在数据库端确保数据的完整性 , 日志记录 , 数据校验等操作 。 使用别名 OLD 和 NEW 来引用…

LeetCode 2215. 找出两数组的不同(set)

文章目录1. 题目2. 解题1. 题目 给你两个下标从 0 开始的整数数组 nums1 和 nums2 &#xff0c;请你返回一个长度为 2 的列表 answer &#xff0c;其中&#xff1a; answer[0] 是 nums1 中所有 不 存在于 nums2 中的 不同 整数组成的列表。answer[1] 是 nums2 中所有 不 存在…

HDOJ 5071 Chat 模拟

大模拟&#xff1a; 1》saygoodbye要先对 always on top 的人说 2》对没有说过话的不要说good bye 3》用long long Chat Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others) Total Submission(s): 337 Accepted Submission(s): 82Prob…

十八、MySQL之TCL事务控制语言(详解)

TCL &#xff1a; Transaction Control Language 事务控制语言 零、MySQL 中的存储引擎 1、概念&#xff1a;在mysql中的数据用各种不同的技术存储在文件&#xff08;或内存&#xff09;中。 2、通过show engines&#xff1b;来查看mysql支持的存储引擎。 3、 在mysql中用的…

LeetCode 2220. 转换数字的最少位翻转次数(位运算)

文章目录1. 题目2. 解题1. 题目 一次 位翻转 定义为将数字 x 二进制中的一个位进行 翻转 操作&#xff0c;即将 0 变成 1 &#xff0c;或者将 1 变成 0 。 比方说&#xff0c;x 7 &#xff0c;二进制表示为 111 &#xff0c;我们可以选择任意一个位&#xff08;包含没有显示…

LeetCode 2221. 数组的三角和

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的整数数组 nums &#xff0c;其中 nums[i] 是 0 到 9 之间&#xff08;两者都包含&#xff09;的一个数字。 nums 的 三角和 是执行以下操作以后最后剩下元素的值&#xff1a; nums 初始包含 n 个元素。如果 n 1 &…

移动web开发之rem布局(rem基础、媒体查询、 less 基础、rem适配方案)

移动web开发之rem布局 一、rem基础 rem单位 rem (root em)是一个相对单位&#xff0c;类似于em&#xff0c;em是父元素字体大小。 不同的是rem的基准是相对于html元素的字体大小。 比如&#xff0c;根元素&#xff08;html&#xff09;设置font-size12px; 非根元素设置wid…

LeetCode 2222. 选择建筑的方案数

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始的二进制字符串 s &#xff0c;它表示一条街沿途的建筑类型&#xff0c;其中&#xff1a; s[i] 0 表示第 i 栋建筑是一栋办公楼&#xff0c;s[i] 1 表示第 i 栋建筑是一间餐厅。 作为市政厅的官员&#xff0c;你需要随…

LeetCode 2224. 转化时间需要的最少操作数(贪心)

文章目录1. 题目2. 解题1. 题目 给你两个字符串 current 和 correct &#xff0c;表示两个 24 小时制时间 。 24 小时制时间 按 "HH:MM" 进行格式化&#xff0c;其中 HH 在 00 和 23 之间&#xff0c;而 MM 在 00 和 59 之间。 最早的 24 小时制时间为 00:00 &…

移动端WEB开发之响应式布局(响应式开发原理、bootstrap、阿里百秀案例)

移动端WEB开发之响应式布局 1.1 响应式开发原理 就是使用媒体查询针对不同宽度的设备进行布局和样式的设置&#xff0c;从而适配不同设备的目的。 设备的划分情况&#xff1a; <!DOCTYPE html> <html><head><meta charset"utf-8" /><…