一、单表操作
# 单表查询操作基本方法 class BookList(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) # 总共8位,小数占2位 publist_date = models.DateField() # DateField年月日,DateTimeField详细时间 #单独测试models.py文件 # 将manage.py中前4行拷贝到一个新的test.py文件中 import os import sys if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day20.settings") import django django.setup() from app01 import models # 插入语句 # book_obj = models.BookList.objects.create(title="三国演义",price=1123.22,publist_date='2019-08-28') # import datetime # ctime = datetime.datetime.today() # book_obj = models.BookList.objects.create(title="红楼梦",price=1666.22,publist_date=ctime) # print(book_obj) # BookList object # 更新数据 # models.BookList.objects.filter(title="三国演义").update(price=1123.22) # queryset方法都是批量更新操作 # 查询 # print(models.BookList.objects.all()) # <QuerySet [<BookList: 三国演义>, <BookList: 红楼梦>]> # print(models.BookList.objects.filter(pk=1)) # <QuerySet [<BookList: 三国演义>]> # 推荐使用 # # get获取到的就是数据对象本身,但是条件不满足的时候会直接报错,不推荐使用 # print(models.BookList.objects.get(pk=3)) # 红楼梦 # 删除 # models.BookList.objects.filter(pk=1).delete() # 更多查询方法 # exclude取反 # print(models.BookList.objects.exclude(pk=1)) # values 拿对应的字段,返回的是列表套字典 # print(models.BookList.objects.values('title','price')) # <QuerySet [{'title': '三国演义', 'price': Decimal('1123.22')}, {'title': '红楼梦', 'price': Decimal('1666.22')}]> # value_list 返回的是列表套元组 # print(models.BookList.objects.values_list('title','price')) # <QuerySet [('三国演义', Decimal('1123.22')), ('红楼梦', Decimal('1666.22'))]> # order by 查询结果排序 默认升序 # print(models.BookList.objects.order_by('price')) # <QuerySet [<BookList: 三国演义>, <BookList: 红楼梦>]> # 降序 # print(models.BookList.objects.order_by('price').reverse()) # 去重:去重的前提是:数据必须是完全一样的 # print(models.BookList.objects.filter(title="三国演义").values('title','price').distinct()) # <QuerySet [{'title': '三国演义', 'price': Decimal('1123.22')}]> # count() # print(models.BookList.objects.all().count()) # first/last # print(models.BookList.objects.first()) # print(models.BookList.objects.last()) # exists # print(models.BookList.objects.filter(pk=2).exists())
# 13个必须会的操作 # 返回QuerySet对象的方法有 all() 查询所有结果 filter() 它包含了与所给筛选条件相匹配的对象 exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象 order_by() reverse(): 对查询结果反向排序,请注意reverse()通常只能在具有已定义顺序的QuerySet上调用(在model类的Meta中指定ordering或调用order_by()方法) distinct(): 从返回结果中剔除重复纪录(如果你查询跨越多个表,可能在计算QuerySet时得到重复的结果。此时可以使用distinct(),注意只有在PostgreSQL中支持按字段去重 # 特殊的QuerySet values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列 values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 # 返回具体对象的 get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误 first() : 第一条记录 last() : 最后一条记录 # 返回布尔值的方法有 exists(): 如果QuerySet包含数据,就返回True,否则返回False # 返回数字的方法有 count(): 返回数据库中匹配查询(QuerySet)的对象数量
二、单表查询之双下划线操作
models.Tb1.objects.filter(id__lte=10, id__gt=1) # 获取id大于1 且 小于等于10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11、22、33的数据 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven") # 获取name字段包含"ven"的 models.Tb1.objects.filter(name__icontains="ven") # icontains大小写不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,等价于SQL的bettwen and 类似的还有:startswith,istartswith, endswith, iendswith
date字段还可以:
models.Class.objects.filter(datetime__year=2017)
date字段可以通过在其后加__year,__month,__day等来获取date的特点部分数据
# date # # Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1)) # Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1)) # year # # Entry.objects.filter(pub_date__year=2005) # Entry.objects.filter(pub_date__year__gte=2005) # month # # Entry.objects.filter(pub_date__month=12) # Entry.objects.filter(pub_date__month__gte=6) # day # # Entry.objects.filter(pub_date__day=3) # Entry.objects.filter(pub_date__day__gte=3) # week_day # # Entry.objects.filter(pub_date__week_day=2) # Entry.objects.filter(pub_date__week_day__gte=2) # 需要注意的是在表示一年的时间的时候,我们通常用52周来表示,因为天数是不确定的
三、图书管理系统表设计
表关系
一对一
一对多
多对多
ps:站在两边判断是否可以同时有多个对方
如果都可以 那么就是多对多
如果是单向的一对多 那么就是一对多
如果都不是 要么没有任何关系 要么就是一对一
Book 书籍
Publish 出版社
Author 作者
AuthorDetail 作者详情
书和出版社 就是一个一对多
书和作者 多对多
作者和作者详情 一对一
# models.py 表结构 """ 一对多 :外键字段 通常建在多的一方 多对多 :外键字段 无论建在哪一方都可以,但是推荐建在查询频率较高的表 一对一 :外键字段 无论建在哪一方都可以,但是推荐建在查询频率较高的表 """ class Book(models.Model): title = models.CharField(max_length=32) price = models.CharField(max_length=32) publish_date = models.DateField(auto_now_add=True) # 出版社外键 publish = models.ForeignKey(to='Publish') # 默认关联的就是Publist表的主键字段 # 作者外键 authors = models.ManyToManyField(to='Author') # 默认关联的就是Author表的主键字段 # 一对多外键字段,在书写的时候,orm会自动加_id后缀 """多对多字段是虚拟字段,不会在表中展示出来 只是用来告诉django orm 自动 创建书籍和作者的第三张表 还可以跨表查询的时候提供方便 """ class Publish(models.Model): name = models.CharField(max_length=32) email = models.EmailField addr = models.CharField(max_length=32) class Author(models.Model): name = models.CharField(max_length=32) age = models.CharField(max_length=3) male = models.CharField(max_length=1) # 一对一 # 一对一外键字段,在书写的时候,orm会自动加_id后缀 author_detail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model): phone = models.CharField(max_length=32) addr = models.CharField(max_length=32)
#数据自己伪造就可以 """ ORM 联表操作 """ # 外键字段的增 # models.Book.objects.create(title='三国演义',price='98.5',publish_id=1) # models.Book.objects.create(title='红楼梦',price='128.88',publish_id=1) # models.Book.objects.create(title='密卷',price='58',publish_id=4) # publish_obj = models.Publish.objects.filter(pk=2).first() # models.Book.objects.create(title='西游记',price='90',publish=publish_obj) # 改 # models.Book.objects.filter(pk=1).update(publish_id=3) # 虚拟对象直接传字段 # publish_obj = models.Publish.objects.filter(pk=2).first() # models.Book.objects.filter(pk=1).update(publist=publish_obj) # 作者和书籍绑定关系 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.add(1) # 在第三张表book_authors中,添加书籍和作者的关系,也可以添加2条add(1,2),2本书是这个作者写的 # author_obj1 = models.Author.objects.filter(pk=1).first() # author_obj2 = models.Author.objects.filter(pk=2).first() # book_obj.authors.add(author_obj1,author_obj2) """ add既支持传数字,也支持传对象,两者也都可以是多个 """ # 改 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.set([2,]) """ set既支持传数字,也支持传对象,两者也都可以是多个 注意:传入的格式必须是可迭代对象 """ # 删 # book_obj = models.Book.objects.filter(pk=1).first() # book_obj.authors.remove(2) """ remove既支持传数字,也支持传对象,两者都可以是多个 """ # 清空 book_obj = models.Book.objects.filter(pk=1).first() book_obj.authors.clear() # 清空当前数据所有的关联信息 """ clear()内不需要传任何参数 """
四、Django终端打印SQL语句
# settings.py文件中,加了这段话后,会将django执行的sql语句都打印出来 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } } # SELECT `app01_book`.`title` FROM `app01_publish` INNER JOIN `app01_book` ON (`app01_publish`.`id` = `app01_book`.`publish_id`)
WHERE (`app01_publish`.`name` = '南方出版社' AND `app01_book`.`price` > '19') LIMIT 21; args=('南方出版社', '19')
五、ORM多表查询
# 正向与反向的概念解释 正向查询按字段(字典建表时的关联字段) 反向查询按表名小写... # 一对一 # 正向:author---关联字段在author表里--->authordetail 按字段 # 反向:authordetail---关联字段在author表里--->author 按表名小写 # 查询jason作者的手机号 正向查询 # 查询地址是 :山东 的作者名字 反向查询 # 一对多 # 正向:book---关联字段在book表里--->publish 按字段 # 反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书 # 多对多 # 正向:book---关联字段在book表里--->author 按字段 # 反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书
5.1 基于对象的跨表查询:子查询
# 基于对象的跨表查询 # 查询书籍id为1的出版社名称(正向) # book_obj = models.Book.objects.filter(pk=1).first() # print(book_obj.publish) # Publish object # print(book_obj.publish.name) #南方出版社 # 查询南方出版社出版过的书的名字(反向) # publish_obj = models.Publish.objects.filter(name="南方出版社").first() # print(publish_obj.book_set) # app01.Book.None 意味着语句没写全,_set说明有多个结果 # print(publish_obj.book_set.all()) # <QuerySet [<Book: Book object>, <Book: Book object>]> # 查询作者simon的手机号(正向) # author_obj = models.Author.objects.filter(name="simon").first() # print(author_obj.author_detail.phone) # 根据手机号150查作者(反向) # authordetail_obj = models.AuthorDetail.objects.filter(phone=150).first() # print(authordetail_obj.author.name)
# 反向查询:根据作者simon查询手机号
res1 = models.AuthorDetail.objects.filter(author__name='simon').values('phone')
print(res1)
# 反向查询:查询年龄和手机号
res =models.AuthorDetail.objects.filter(author__name='simon').values('author__age','phone')
# 多对多 # 查询书籍ID为1的作者姓名 # book_obj = models.Book.objects.filter(pk=1).first() # print(book_obj.authors.all()) # <QuerySet [<Author: Author object>, <Author: Author object>]> # 查询作者ID为1的写的书(反向) # author_obj = models.Author.objects.filter(pk=1).first() # print(author_obj.book_set.all())
5.2 基于双下划线的多表查询
# 查询书籍id为1的作者的姓名:2张表没有直接关联,需要通过book_authors来关联(正向) res1 = models.Book.objects.filter(id=1).values('authors') print(res1) # <QuerySet [{'authors': 2}, {'authors': 4}]> 查询到作者ID res = models.Book.objects.filter(id=1).values('authors__name') print(res) # 作者名:<QuerySet [{'authors__name': 'jace'}, {'authors__name': 'once'}]> 作者姓名是once写过的书的价格(反向) res = models.Author.objects.filter(name='once').values('book__price','book__title') print(res) # <QuerySet [{'book__price': '98.5', 'book__title': '三国演义'}]> # 查询书籍id为1的出版社addr(正向) res = models.Book.objects.filter(id=1).values('publish__addr') # 这里的publish不是表面小写而是字段 print(res) # <QuerySet [{'publish__addr': '上海'}]> # 通过出版社id=1找出版过的书(反向) res = models.Publish.objects.filter(id=1).values('book__title') print(res) # <QuerySet [{'book__title': '红楼梦'}]> # 查询红楼梦作者的电话号码(正向) res = models.Book.objects.filter(title="红楼梦").values('authors__author_detail__phone') print(res) # <QuerySet [{'authors__author_detail__phone': '150'}]> # 查询作者电话号码是150出版过的书籍(反向) res = models.AuthorDetail.objects.filter(phone=150).values('author__book__title') print(res) # <QuerySet [{'author__book__title': '红楼梦'}, {'author__book__title': '考卷'}]>
5.3 联合查询
# 查询北方出版社出版的的价格大于19的书 res = models.Book.objects.filter(price__gt='19',publish__name="北方出版社") print(res) # <QuerySet [<Book: Book object>]> # 查询南方出版社出版过的书,且价格大于19(反向) res = models.Publish.objects.filter(name="南方出版社",book__price__gt=19).values('book__title') print(res) # <QuerySet [{'book__title': '三国演义'}, {'book__title': '18岁的天空'}]>
5.4 聚合查询与分组查询
from django.db.models import Avg,Sum,Max,Min,Count # 聚合查询 # 请所有书籍的平均价格 res = models.Book.objects.all().aggregate(Avg("price")) print(res) # 分组查询(group_by) # 统计每本书作者的个数 book_list = models.Book.objects.all().annotate(author_num=Count("authors")) for obj in book_list: print(obj.author_num) # 统计每个出版社卖的最便宜的书 res = models.Publish.objects.annotate(min_price=Min("book__price"))
print([i.min_price for i in res ]) # for obj in res: # print(obj.min_price) #第二种方法: res = models.Book.objects.values("publish__name").annotate(min_price=Min("price")) print(res) # <QuerySet [{'publish__name': '工业出版社', 'min_price': '128.88'}, {'publish__name': '北方出版社', 'min_price': '90'}, {'publish__name': '南方出版社', 'min_price': '38'},
# {'publish__name': '武汉出版社', 'min_price': '38'}]> # 统计不只一个作者的书 res = models.Book.objects.annotate(authors_num=Count("authors")).filter(authors_num__gt=1) print(res) # <QuerySet [<Book: Book object>]>
5.5 F 与 Q
# F查询:查询的条件左右两边都来自于数据库而非你自己定义 # F可以帮我们取到表中某个字段对应的值来当作我的筛选条件,而不是我认为自定义常量的条件了,实现了动态比较的效果:F 可以帮我们实现同一表中2个字段进行比较 from django.db.models import F,Q # 查询卖出数大于库存数的书籍 # sell_book和kc_book为字段名 res = models.Book.objects.filter(sell_book__gt=F('kc_book')).values('title') print(res) # 将每个商品的价格提高50元 res2 = models.Book.objects.update(price=F('price') + 50) # Q查询:能够将filter内部默认的and关系,转换成 与或非 # 逗号 默认也是 与 的关系 # 与& 或| 非~ # 查询书籍名字是西游记或价格是140的书籍 res = models.Book.objects.filter(Q(title="西游记")|Q(price=140)).values('title') # res = models.Book.objects.filter(title="西游记",price=140).values('title') print(res) # 非 ~Q # 查询书籍价格不是140的书籍名 res1 = models.Book.objects.filter(~Q(price=140)).values("title") print(res1)
多对多表关系三种创建方式
1.全自动:ManyToManyField()自动创建第三张表 authors = models.ManyToManyField(to='Author') 让django orm自动帮你创建第三张表 好处:不需要自己手动添加 坏处:表字段的扩展性极差 只会帮你建外键字段 其他额外字段一概无法创建 2.纯手动(了解):无法使用跨表查询,必须自己一个表一个表手动查找 class Book(models.Model): name = ... class Author(models.Model): name = ... class Book2Author(models.Model): book_id = models.ForeignKey(to='Book') author_id = models.ForeignKey(to='Author') 3.半自动:可以使用跨表查询,与全自动一样
优点:可以自己加额外的字段 class Book(models.Model): name = ... authors = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('book','author')) class Author(models.Model): name = ...
# 如果外键建在这张表 # books = models.ManyToManyField(to='Author',through='Book2Author',through_fields=('author','book')) class Book2Author(models.Model): book = models.ForeignKey(to='Book') author = models.ForeignKey(to='Author') create_time = ... info = ...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了