ORM
(1)什么是ORM
- ORM是一种将对象与关系型数据库之间的映射的技术,主要实现了以下三个方面的功能:
- 数据库中的表映射为Python中的类
- 数据库中的字段映射为Python中的属性
- 数据库中的记录映射为Python中的实例
- ORM的主要优点是可以减少开发人员编写重复的SQL语句的时间和工作量,并且可以减少由于SQL语句的调整和更改所带来的错误。
(2)定义模型表
| from django.db import models |
| class User(models.Model): |
| username = models.CharField(max_length=20) |
| password = models.CharField(max_length=20) |
| age = models.IntegerField() |
| register_time = models.DateField() |
| register_time1 = models.DateTimeField() |
(1)允许为空
| class User(models.Model): |
| name = models.CharField(max_length=50, null=True) |
(2)指定默认值
| class MyModel(models.Model): |
| age = models.IntegerField(default=18) |
(3)DateField两个重要参数
auto_now
每次操作数据的时候 该字段会自动将当前时间更新
auto_now_add
在创建数据的时候会自动将当前时间记录下来 之后只要不人为的修改 数据会一直保存
| from django.db import models |
| class User(models.Model): |
| register_time = models.DateField(auto_now = True ) |
| register_time1 = models.DateTimeField(auto_now_add = True ) |
(4)外键
| FK = models.ForeignKey(to='表名',on_delete=models.CASCADE) |
| MTM = models.ManyToManyField(to='表名') |
| OTO = models.OneToOneField(to='表名',on_delete=models.CASCADE) |
(5)总结
- 字段类型:
CharField
: 字符串字段
TextField
: 文本字段
IntegerField
: 整数字段
FloatField
: 浮点数字段
DecimalField
: 十进制数字段
- (max_digits= , decimal_places= )
BooleanField
: 布尔字段
DateField
: 日期字段
DateTimeField
: 日期时间字段
TimeField
: 时间字段
EmailField
: 邮箱字段
FileField
: 文件上传字段
ImageField
: 图片上传字段
ForeignKey
: 外键字段
ManyToManyField
: 多对多关系字段
OneToOneField
: 一对一关系字段
- 字段选项:
verbose_name
: 显示字段的名称
help_text
:显示字段的说明
on_delete
:级联更新级联删除
- (on_delete=models.CASCADE)
max_length
: 字符串字段的最大长度
default
: 默认值
null
: 数据库中字段是否可以为NULL
auto_now
: 每次保存对象时自动更新为当前时间
auto_now_add
: 创建对象时自动设置为当前时间
(4)数据库迁移
| python manage.py makemigrations |
(5)ORM数据操作 单表查询
- QuerySet对象索引取值或者循环取值
- object对象可以用.取值
(1)增加 create
| 模型表名.objects.create(字段名=字段值) |
| User.objects.create( |
| name="heart", |
| age=18, |
| email="ssrheart@outlook.com" |
| ) |
(2)查询 all
filter
get
| |
| 模型表名.objects.get(筛选字段名=筛选字段值) |
| |
| |
| |
| 模型表名.objects.filter(筛选字段名=筛选字段值) |
| |
| |
| |
| 模型表名.objects.filter(筛选字段名=筛选字段值).first() |
| |
| 模型表名.objects.exclude(筛选字段名=筛选字段值) |
| |
| user = User.objects.all() |
| |
| |
| res = User.objects.get(name="heart") |
| |
| |
| res = User.objects.filter(name="heart").first() |
| |
| |
| |
| exclude_res = User.objects.exclude(age=18) |
| |
| user_obj = models.User.objects.values("name") |
| |
- 获取到多个字段的数据
values_list
列表套元组
| user_obj = models.User.objects.values_list("name","age") |
| print(user_obj) |
| |
| user_obj = models.User.objects.values('name', 'age').distinct() |
| print(user_obj) |
| |
| user_obj = models.User.objects.order_by('age') |
| user_obj = models.User.objects.order_by('-age') |
| user_obj = models.User.objects.order_by('age').reverse() |
| user_obj = models.User.objects.count() |
| user_obj = models.User.objects.filter(name="heart").exists() |
(3)更改 update
| 模型表名.objects.filter(筛选字段名=筛选字段值).update(修改字段名=修改字段值) |
| User.objects.filter(age=18).update(age=24) |
| obj = 模型表名.objects.get(筛选字段名=筛选字段值) |
| obj.修改字段名=修改字段值 |
| obj.save() |
| |
| res = User.objects.get(name="张三") |
| res.age = 26 |
| res.save() |
(4)删除 delete
| 模型表名.objects.filter(筛选字段名=筛选字段值).delete() |
| User.objects.filter(username=username).delete() |
| res = User.objects.get(筛选字段名=筛选字段值) |
| res.delete() |
(6)测试脚本&查看内部sql语句
| from django.test import TestCase |
| import os |
| |
| if __name__ == "__main__": |
| os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day07.settings") |
| |
| import django |
| django.setup() |
| |
| |
| LOGGING = { |
| 'version': 1, |
| 'disable_existing_loggers': False, |
| 'handlers': { |
| 'console':{ |
| 'level':'DEBUG', |
| 'class':'logging.StreamHandler', |
| }, |
| }, |
| 'loggers': { |
| 'django.db.backends': { |
| 'handlers': ['console'], |
| 'propagate': True, |
| 'level':'DEBUG', |
| }, |
| } |
| } |
(7)必知必会十三条
| |
| |
| .create(字段名=字段值) |
| |
| .all() |
| |
| .filter(筛选字段名=筛选字段值) |
| |
| .filter(筛选字段名=筛选字段值).first() |
| |
| .filter(筛选字段名=筛选字段值).last() |
| |
| .filter(筛选字段名=筛选字段值).update(字段名=字段值) |
| |
| .filter(筛选字段名=筛选字段值).delete() |
| |
| .get(筛选字段名=筛选字段值) |
| |
| .values(字段名) |
| |
| .value_list(字段名1,字段名2) |
| |
| .values(字段名1,字段名2).distinct() |
| |
| |
| .order_by(字段名) |
| |
| .order_by(-字段名) |
| |
| .order_by(字段名).reverse() |
| |
| .count() |
| |
| .exclude(字段名=字段值) |
| |
| .filter(筛选字段名=筛选字段值).exists() |
| |
| |
| |
| .query |
(8)双下划线查询
(1)条件大于__gt
| res = models.User.objects.filter(age__gt=35) |
| print(res) |
(2)条件小于__lt
| res = models.User.objects.filter(age__lt=35) |
| print(res) |
(3)条件大于等于__gte
| res = models.User.objects.filter(age__gte=35) |
| print(res) |
(4)条件小于等于__lte
| res = models.User.objects.filter(age__lte=35) |
| print(res) |
(5)或条件__in
| res = models.User.objects.filter(age__in=(18, 32, 40)) |
| print(res) |
(6)两个条件之间__range
| res = models.User.objects.filter(age__range=(18, 40)) |
| print(res) |
(7)模糊查询__contains
| res = models.User.objects.filter(name__contains='n') |
| print(res) |
| res = models.User.objects.filter(name__contains='N') |
| print(res) |
| res = models.User.objects.filter(name__icontains='N') |
| print(res) |
(8)以指定条件开头/结尾
| res = models.User.objects.filter(name__startswith='d') |
| print(res) |
| res = models.User.objects.filter(name__endswith='m') |
| print(res) |
(9)查询时间日期
- 查询出注册时间是2020年1月份的数据/年/月/日
| res = models.User.objects.filter(register_time__month='1') |
| print(res) |
| res = models.User.objects.filter(register_time__year='2020') |
| print(res) |
| res = models.User.objects.filter(register_time__day='28') |
| print(res) |
(9)ORM数据操作 多表查询
| from django.db import models |
| |
| |
| |
| class Book(models.Model): |
| title = models.CharField(max_length=32) |
| price = models.DecimalField(max_digits=5, decimal_places=2) |
| publish_date = models.DateField(auto_now_add=True) |
| |
| |
| publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE) |
| |
| authors = models.ManyToManyField(to='Author') |
| |
| class Publish(models.Model): |
| name = models.CharField(max_length=32) |
| addr = models.CharField(max_length=64) |
| email = models.EmailField() |
| |
| class Author(models.Model): |
| name = models.CharField(max_length=32) |
| age = models.IntegerField() |
| |
| |
| author_detail = models.OneToOneField(to='Author_Detail',on_delete=models.CASCADE) |
| |
| class Author_Detail(models.Model): |
| phone = models.BigIntegerField() |
| addr = models.CharField(max_length=40) |
| python manage.py makemigrations |
| python manage.py migrate |
(1)一对多外键增删改
(1)增 create
| models.Book.objects.create(title='黑色柳丁', price=99.99, publish_id=1) |
| publish_obj = models.Publish.objects.filter(pk=2).first() |
| models.Book.objects.create(title='蝴蝶', price=999.99,publish=publish_obj) |
(2)删 delete
| models.Book.objects.filter(pk=6).delete() |
(3)修改 update
| models.Book.objects.filter(pk=2).update(publish_id=2) |
| publish_obj = models.Publish.objects.filter(pk=2).first() |
| models.Book.objects.filter(pk=2).update(publish=publish_obj) |
(2)多对多外键删改
(1)增 add
| book_obj = models.Book.objects.filter(pk=8).first() |
| book_obj.authors.add(1,2) |
| |
| |
| book_obj = models.Book.objects.filter(pk=2).first() |
| author_obj = models.Author.objects.filter(pk=1).first() |
| author_obj1 = models.Author.objects.filter(pk=2).first() |
| author_obj2 = models.Author.objects.filter(pk=3).first() |
| book_obj.authors.add(author_obj) |
| book_obj.authors.add(author_obj1,author_obj2) |
| |

总结:
add给第三张关系表添加数据
括号内既可以传id也可以传对象 并且都支持多个
(2)删 remove
| book_obj = models.Book.objects.filter(pk=2).first() |
| book_obj.authors.remove(2) |
| |
| |
| author_obj = models.Author.objects.filter(pk=1).first() |
| author_obj1 = models.Author.objects.filter(pk=2).first() |
| book_obj.authors.remove(author_obj,author_obj1) |
总结:
remove给第三张关系表删除数据
括号内既可以传id也可以传对象 并且都支持多个
(3)修改 set
| book_obj = models.Book.objects.filter(pk=8).first() |
| book_obj.authors.set([1,2]) |
| |
| |
| author_obj = models.Author.objects.filter(pk=1).first() |
| author_obj1 = models.Author.objects.filter(pk=2).first() |
| book_obj.authors.set([author_obj,author_obj1]) |
总结:
set括号内必须传一个可迭代对象,该对象内既可以传id也可以传对象 并且都支持多个
(4)清空 clear
| book_obj = models.Book.objects.filter(pk=2).first() |
| book_obj.authors.clear() |
| |
总结:
clear括号内不要加任何参数
(3)正反向的概念
(1)正向
| |
| book >>> publish (外键字段在书里面)就是正向 |
(2)反向
| |
| publish >>> book (外键字段在书里面)就是反向 |
正向查询按字段
反向查询按表名小写 _set
(4)多表查询
(1)子查询(基于对象的跨表查询)
| book_obj = models.Book.objects.filter(pk=2).first() |
| res = book_obj.publish |
| print(res.name) |
- 查询书籍主键为8的作者
- 这个地方如果查询出来如果有多个结果,一定要使用
all()
- 不然会出现
booksystem01.Author.None
这种情况
- 然后使用for循环遍历结果取出想要的值
| book_obj = models.Book.objects.filter(pk=8).first() |
| |
| res = book_obj.authors.all() |
| print(res) |
| author_obj = models.Author.objects.filter(name='heart').first() |
| res = author_obj.author_detail |
| print(res.phone) |
- 查询出版社是东方出版社出版的书
- 出版社查书是反向
表名小写加_set
| publish_obj = models.Publish.objects.filter(name='东方出版社').first() |
| res = publish_obj.book_set.all() |
| print(res) |
| author_obj = models.Author.objects.filter(name='heart').first() |
| res = author_obj.book_set.all() |
| |
| res = author_detail_obj.author |
| |
反向查询的时候:
当查询结果有多个的时候 就必须加_set.all()
当查询结果只有一个的时候 不需要加_set.all()
(2)联表查询(基于下划线的跨表查询)
| res = models.Author.objects.filter(name='heart').values('author_detail__phone') |
| print(res) |
| |
| |
| res = models.Author_Detail.objects.filter(author__name='heart').values('phone','author__name') |
| print(res) |
| res = models.Book.objects.filter(pk=2).values('publish__name','title') |
| print(res) |
| |
| |
| res = models.Publish.objects.filter(book__id=2).values('name', 'book__title') |
| print(res) |
| res = models.Book.objects.filter(pk=2).values('authors__name') |
| print(res) |
| |
| |
| res = models.Author.objects.filter(book__id=2).values('name') |
| print(res) |
| res = models.Book.objects.filter(pk=2).values('authors__author_detail__phone') |
| print(res) |
(5)聚合查询 aggregate
- 只要是跟数据库相关的模块 基本都在django.db.models里面
- 如果上述没有那么应该在django.db里面
from django.db.models import Max,Min,Count,Sum,Avg
| from django.db.models import Max,Min,Count,Sum,Avg |
| from django.db.models import Max,Min,Count,Sum,Avg |
| res = models.Book.objects.aggregate(Avg('price')) |
| print(res) # {'price__avg': Decimal('16959.253333')} |
| res = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Sum('price')) |
| print(res) |
(6)分组查询 annotate
-
需要搭配聚合查询使用
from django.db.models import Max,Min,Count,Sum,Avg
-
models后面点什么,就是按什么分组
-
统计每一本书的作者个数
| from django.db.models import Max,Min,Count,Sum,Avg |
| res = models.Book.objects.annotate(author_num=Count('authors')).values('title','author_num') |
| print(res) |
| from django.db.models import Max,Min,Count,Sum,Avg |
| res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') |
| print(res) |
| res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1) |
| print(res) |
| res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price') |
| print(res) |
(7)F查询
| from django.db.models import F |
| res = models.Book.objects.filter(maichu__gt=F('kucun')) |
| print(res) |
| models.Book.objects.update=(price=F('price') + 500) |
- 将所有书的名字后面加上爆款两个字
- 在操作字符类型的数据的时候 F不能够直接做到字符串的拼接 需要借助Concat 和 Value
| from django.db.models.functions import Concat |
| from django.db.models import Value |
| models.Book.objects.update(title=Concat(F('title'), Value('爆款'))) |
(8)Q查询
| filter括号内多个参数是and关系 |
| res = models.Book.objects.filter(maichu__gt=100,price__lt=600) |
| |
| res = models.Book.objects.filter(Q(maichu__gt=100), Q(price__lt=600)) |
| res = models.Book.objects.filter(Q(maichu__gt=100) | Q(price__lt=600)) |
| res = models.Book.objects.filter(~Q(maichu__gt=100) | Q(price__lt=600)) |
(1)Q的高阶用法
- 能够将查询条件的左边也变成字符串的形式
- 查询卖出数大于100或者价格小于600的书籍
| q = Q() |
| q.connector = 'or' |
| q.children.append(('maichu__gt', 100)) |
| q.children.append(('price__lt', 600)) |
| res = models.Book.objects.filter(q) |
| print(res) |
(9)事务
| from django.db import transaction |
| with transaction.atomic(): |
| |
| |
| |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通