MongoEngine
uMongo
pip install mongoengine
方式一,使用默认配置:connect('students')
方式二,指定主机地址和端口
# 连接方式1
connect('students', host='*', port=27017)
# 连接方式2
connect('students', host='mongodb://localhost/students')
连接到多个数据库
connect(alias='db1', db='test')
connect(alias='db2', db='test-temp')
disconnect(alias='db1')
示例代码
from mongoengine import Document
class User(Document):
email = StringField(required=True)
first_name = StringField(max_length=50)
last_name = StringField(max_length=50)
类属性,其配置项为python的dict(字典)
示例代码
class User(Document):
username = StringField()
meta = {}
常见配置项
文档的嵌套场景
情况一,数组-简单数据类型:{'grades': [76, 51, 84]}
模型解决方案
from mongoengine import ListField, IntField, Document
class Student(Document):
grades = ListField(IntField())
情况二,数组-文档:{'grades': [{'score': 76}, {'score': 51}]}
from mongoengine import Document, EmbeddedDocument, EmbeddedDocumentField,IntField,ListField
# 自定义类型
class CourseGrade(EmbeddedDocument):
score = IntField()
class Student(Document):
grades = ListField(EmbeddedDocumentField(CourseGrade))
情况三,单个文档:{'grade': {'course_name': '语文', 'score': 76}}
from mongoengine import (
Document, EmbeddedDocument, EmbeddedDocumentField,
IntField, StringField
)
# 自定义类型
class CourseGrade(EmbeddedDocument):
course_name = StringField()
score = IntField()
class Student(Document):
grades = EmbeddedDocumentField(CourseGrade)
示例
from enum import Enum
from mongoengine import (
Document, connect, StringField,
EnumField, IntField, EmbeddedDocument,
EmbeddedDocumentField, ListField
)
# 连接到test数据库
connect('test', host='localhost', port=27017)
class SexEnum(Enum):
MAN = '男'
WOMEN = '女'
class CourseGrade(EmbeddedDocument):
"""成绩信息(科目、老师、成绩)-被嵌套的文档"""
course_name = StringField(max_length=64, required=True, verbose_name='科目')
teacher = StringField(max_length=16, verbose_name='老师')
score = IntField(min_value=0, max_value=150, required=True, verbose_name='成绩')
def __repr__(self):
return f'CourseGrade({self.course_name}, {self.score})'
def __str__(self):
return self.__repr__()
class Student(Document):
"""学生信息"""
# verbose_name 自定义参数,用于显示定义域的名称
stu_no = IntField(required=True, unique=True, verbose_name="学号")
stu_name = StringField(required=True, max_length=16, verbose_name='姓名')
sex = EnumField(enum=SexEnum, verbose_name='性别')
class_name = StringField(max_length=10, verbose_name='班级')
address = StringField(max_length=255, verbose_name='家庭住址')
phone_no = StringField(max_length=11, verbose_name='电话号码')
age = IntField(min_value=0, max_value=150, verbose_name='年龄')
grades = ListField(EmbeddedDocumentField(CourseGrade), verbose_name='成绩数组')
meta = {
# 指定文档的集合
'collection': 'students',
# 指定排序,可以指定多个域。例如:'age':根据年龄升序,'-age':根据年龄倒叙
'ordering': ['-age']
}
def __repr__(self):
return f'Student({self.stu_no}, {self.stu_name})'
def __str__(self):
return self.__repr__()
class Grade(Document):
"""学生成绩"""
# verbose_name 自定义参数,用于显示定义域的名称
stu_no = IntField(required=True, verbose_name="学号")
stu_name = StringField(required=True, max_length=16, verbose_name='姓名')
sex = EnumField(enum=SexEnum, verbose_name='性别')
class_name = StringField(max_length=10, verbose_name='班级')
address = StringField(max_length=255, verbose_name='家庭住址')
phone_no = StringField(max_length=11, verbose_name='电话号码')
age = IntField(min_value=0, max_value=150, verbose_name='年龄')
grade = EmbeddedDocumentField(CourseGrade, verbose_name='成绩')
meta = {
# 指定文档的集合
'collection': 'grades',
# 指定排序,可以指定多个域。例如:'age':根据年龄升序,'-age':根据年龄倒叙
'ordering': ['-age']
}
def __repr__(self):
return f'Grade({self.stu_no}, {self.stu_name})'
def __str__(self):
return self.__repr__()
结果集QuerySet的获取:User.objects
,User是模型对象
结果集上的常用方法
User.objects.first()
示例
from learn_odm.school_models import Student
class LearnMongoDBEngine:
def get_one_student(self):
"""查询一个学生信息"""
return Student.objects.first()
def get_student_by_id(self, pk: str):
"""根据学生的id查询"""
return Student.objects.get(id=pk)
在MongoEngine中使用双下划线(__)分割。比如:age__gt=12
,表示年龄大于12的学生信息。
MongoEngine中的字符串查询
Q函数的使用:from mongoengine.queryset.visitor import Q
多个条件同时满足:Student.objects.filter(Q(key1=value1) & Q(key2=value2))
多个条件部分满足:Student.objects.filter(Q(key1=value1) | Q(key2=value2))
示例
from learn_odm.school_models import Student, Grade,SexEnum
from mongoengine.queryset.visitor import Q
class LearnMongoDBEngine:
def get_student_all(self):
"""获取所有学生信息"""
# result = Student.objects()
result = Student.objects.all()
return result
def get_student_01(self):
"""获取大于12岁的学生信息"""
return Student.objects.filter(age__gt=12)
def get_grade_01(self):
"""查询大于等于60分的学生成绩信息"""
return Grade.objects.filter(grade__score__gte=60)
def get_student_02(self):
"""获取所有姓李的学生"""
return Student.objects.filter(stu_name__startswith='李')
def get_student_03(self):
"""查询年龄在9~12之间(含)的学生信息"""
# SELECT * FROM school_student_info WHERE age BETWEEN 9 AND 12;
# db.students.find({'age': {'$gte': 9, '$lte': 12}})
# 写法1
return Student.objects.filter(age__gte=9, age__lte=12)
# 写法2
# return Student.objects.filter(Q(age__gte=9) & Q(age__lte=12))
def get_student_04(self):
"""查询所有12岁以上的男生和9岁以下的女生"""
return Student.objects.filter(Q(age__gt=12, sex=SexEnum.MAN) | Q(age__lt=9, sex=SexEnum.WOMEN))
User.objects.count()
,所有的结果集都可以使用User.objects.filter().sum(field) / User.objects.filter().average(field)
示例
class LearnMongoDBEngine:
def get_student_05(self):
"""查询所有12岁以上的男生和9岁以下的女生总数"""
return Student.objects.filter(Q(age__gt=12, sex=SexEnum.MAN) | Q(age__lt=9, sex=SexEnum.WOMEN)).count()
def get_grade_02(self):
"""统计语文成绩的平均分,张三的语数英成绩总分"""
queryset = Grade.objects.filter(grade__course_name='语文')
avg_score = queryset.average('grade.score')
sum_score = Grade.objects.filter(stu_name='张三').sum('grade.score')
return avg_score, sum_score
排序规则
Student.objects().order_by('field1', '-field2')
class LearnMongoDBEngine:
def get_grade_03(self):
"""统计语文成绩的最高分和最低分"""
queryset = Grade.objects.filter(grade__course_name='语文')
max_score = queryset.order_by('-grade.score').first().grade.score
min_score = queryset.order_by('grade.score').first().grade.score
return max_score, min_score
User.objects.all()[10:15]
User.objects.skip(10).limit(5)
class LearnMongoDBEngine:
def paginate(self, page: int = 1, page_size: int = 5):
"""
分页处理
:param page: 当前第几页
:param page_size: 每页多少条数据
:return:
"""
# 方式1
start = (page - 1) * page_size
end = start + page_size
queryset = Student.objects.all()[start:end]
# 方式2
queryset1 = Student.objects.skip(start).limit(page_size)
return queryset, queryset1
步骤
user=User(username='cjw')
user.validate()
user.save()
模型中的验证器
内置的验证器,如max_length, min_value
自定义验证器
import re
from mongoengine import StringField
from mongoengine.errors import ValidationError
def phone_required(value):
pattern = r'^1[0-9][10]$'
if not re.search(pattern, value):
raise ValidationError('请输入正确的手机号')
phone_no = StringField(validation=phone_required)
使用create()方法
User.objects.create(**kwargs)
示例
class LearnMongoDBEngine:
def add_one_student(self):
"""新增一个学生信息"""
student = Student(
stu_no=random.randint(3000, 9999999),
stu_name=self.gd.name(),
sex=random.choice([SexEnum.MAN, SexEnum.WOMEN]),
class_name='三年级四班',
address=self.gd.address(),
phone_no=self.gd.phone(),
age=random.randint(1, 20),
grades=[
CourseGrade(course_name='语文', teacher=self.gd.name(), score=random.randint(1, 100)),
CourseGrade(course_name='数学', teacher=self.gd.name(), score=random.randint(1, 100)),
CourseGrade(course_name='英语', teacher=self.gd.name(), score=random.randint(1, 100)),
]
)
print(student, student.grades)
result = student.save()
return result
def add_one_student_create(self):
"""使用create方法,新增一个学生信息"""
result = Student.objects.create(
stu_no=random.randint(3000, 9999999),
stu_name=self.gd.name(),
sex=random.choice([SexEnum.MAN, SexEnum.WOMEN]),
class_name='三年级四班',
address=self.gd.address(),
phone_no=self.gd.phone(),
age=random.randint(1, 20),
grades=[
CourseGrade(course_name='语文', teacher=self.gd.name(), score=random.randint(1, 100)),
CourseGrade(course_name='数学', teacher=self.gd.name(), score=random.randint(1, 100)),
CourseGrade(course_name='英语', teacher=self.gd.name(), score=random.randint(1, 100)),
]
)
return result
一般先过滤数据,再修改
User.objects.filter().update_one()
User.objects.filter().update()
User.objects.filter().delete()
示例
class LearnMongoDBEngine:
def update_one(self):
"""修改一条数据"""
queryset = Student.objects.filter(stu_no=5219980)
# result = queryset.update_one(stu_name=self.gd.name(), phone_no=self.gd.phone())
result = queryset.update_one(stu_name=self.gd.name(), unset__phone_no=True)
return
def update_one_1(self):
"""修改一条数据"""
stu = Student.objects.filter(stu_no=5219980).first()
if stu:
stu.stu_name = self.gd.name()
result = stu.save()
print(result)
def update_many(self):
"""9岁的学生年龄+1"""
queryset = Student.objects.filter(age=9)
queryset.update(inc__age=1)
def delete_data(self):
"""删除学号大于3000的学号"""
queryset = Student.objects.filter(stu_no__gte=3000)
print(f'删除的学生人数:{queryset.count()}')
res = queryset.delete()
print(f'删除的结果:{res}')