文章目录
一 创建模型
(一) 模型创建
1) 图书表:book,作者表:author,作者详情表:authordetail,出版社表:publish,(第三张中间表)。
2) 作者跟作者详情:是一对一,关联字段写在哪一方都可以
3) 图书跟出版社:是一对多,【一对多关系一旦确立,关联字段写在多的一方】
4) 图书和作者:是多对多,多对多的关系需要建立第三张表(可以自动生成)
5) models.py中把关系建立出来
from django.db import models
### django: 1.11.1 2.0.7
# Create your models here.
class Publish(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
addr = models.CharField(max_length=128)
phone = models.CharField(max_length=64)
email = models.EmailField()
# admin元数据相关【只有建的表才生效】
class Meta:
verbose_name = '出版社'
verbose_name_plural = '出版社'
# 定制admin中显示的数据【只有建的表才生效】
def __str__(self):
return self.name
"""以下为Book表后添加的字段,添加后做一下数据库迁移"""
# 阅读数
# reat_num=models.IntegerField(default=0)
# 评论数
# commit_num=models.IntegerField(default=0)
class Book(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
price = models.DecimalField(max_digits=5, decimal_places=2)
publish_date = models.DateTimeField(auto_now_add=True)
# to='Publish' 跟Publish表做关联(ForeignKey,一对多)
# to_field='id' 跟哪个字段做关联(字段必须是unique=True), 不写,默认跟主键做关联
# on_delete 表示约束类型,1.x版本默认CASCADE,2.X以上版本必须设置,有三个参数
# publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE) # 级联删除
# publish = models.ForeignKey(to='Publish', on_delete=models.SET_DEFAULT,default=0) # 关联字段删除,被关联字段不删除,设置为0
publish = models.ForeignKey(to='Publish', on_delete=models.SET_NULL, null=True) # 关联字段删除,被关联字段不删除,设置为空
# 自动创建出的第三张表,表示两个表的关联关系
# authors在数据库中不存在该字段,所以没有to_field
# 默认情况:第三张表有id字段,当前Book表的id和Author表的id字段,不可以自定义添加字段
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
age = models.SmallIntegerField()
# 一对一的本质是 ForeignKey+unique
author_detail = models.OneToOneField(to='AuthorDetail', to_field='id', on_delete=models.CASCADE)
# 可以使用ForeignKey+unique来写,但是不推荐这样写,标识性不强
# author_detail=models.ForeignKey(to='AuthorDetail',to_field='id',unique=True)
class AuthorDetail(models.Model):
id = models.AutoField(primary_key=True)
gender = models.SmallIntegerField()
addr = models.CharField(max_length=64)
phone = models.BigIntegerField()
6) 同步到mysql数据库
-配置文件
-pymysql.install_as_mysqldb()
-公司可能用的mysqlclient
-两条命令
7) 2.x版本的django
-外键字段必须加 参数:on_delete
-1.x版本不需要,默认就是级联删除
-举例假设:
删除出版社,该出版社出版的所有图书也都删除,on_delete=models.CASCADE
删除出版社,该出版社出版的图书不删除,设置为空on_delete=models.SET_NULL,null=True
删除出版社,该出版社出版的图书不删除,设置为默认on_delete=models.SET_DEFAULT,default=0 # default必须是数字
# 注意:
1) 便于理解:一对一的本质是 ForeignKey+unique
(二) 外键关系建立问题
1) 关联字段与外键约束没有必然的联系(建关联字段是为了进行查询,建约束是为了不出现脏数据)
2) 默认情况,关联关系建好以后,外键约束就自然建立了
3) 实际工作中,外键约束一般不建(影响效率),都是人为约束(代码约束)
-db_constraint=False
4) 表模型和数据库表的对应,不要直接修改表(这是可以的,但是不建议),要修改表模型,同步到表中
二 添加表记录
(一) 一对多添加记录
# 脚本文件的设置
import os
if __name__ == '__main__':
os.environ.setdefault('DJANGO_SETTINGS_MODULE', '项目名.settings')
import django
django.setup()
from app01 import models
# 基本数据:
# 书 名: 西游记、 红楼梦、 诛仙、 Python从入门到入狱、 三体
# book_id: 1 2 3 4 5
# 作 者: 刘老牛、 小矮根、 萧鼎、 刘老牛、小矮根、 刘慈欣
# 出版社: 北京、 北京、 北京、 沙河、 三体
# 一对多添加记录(出版社和图书)
# 先增加出版社,再增加图书,因为外键约束在图书侧
# 新增北京、沙河、三体出版社
publish_obj1 = models.Publish.objects.create(name='北京出版社',addr='北京',phone='010-66666666',email='bj@qq.com')
publish_obj2 = models.Publish.objects.create(name='沙河出版社',addr='北京',phone='010-88888888',email='sh@qq.com')
publish_obj3 = models.Publish.objects.create(name='三体出版社',addr='三体星',phone='010-77777777',email='st@qq.com')
# 新增 西游记、红楼梦、诛仙、Python从入门到入狱、三体
# publish 与 publish_id : publish=publish_obj【可以等于上面插入数据时的对象】,也可以直接设置publish_id
book_obj1 = models.Book.objects.create(name='西游记', price='21', publish_id=1)
book_obj2 = models.Book(name='红楼梦', price='22.22', publish_id=1)
book_obj2.save()
book_obj3 = models.Book.objects.create(name='诛仙', price='66.66', publish_id=1)
book_obj4 = models.Book.objects.create(name='Python从入门到入狱', price='0.5', publish_id=2)
book_obj5 = models.Book.objects.create(name='三体', price='99.99', publish_id=3)
book = models.Book.objects.get(name='红楼梦')
# print('出版社对象', book.publish) # 出版社对象 Publish object (1)
# print('出版社对象id', book.publish.id) # 出版社对象id 1
# print('出版社id', book.publish_id) # 出版社id 1
# 总结:
1 email可以不传email,本质就是varchar(admin中会判断)
2 新增图书:
-publish=publish
-publish_id=publish.id
3 写在表模型中的publish字段,到数据库中会变成publish_id(ForeignKey)
4 查到book对象以后
-book.publish 对象
-book.publish_id id号,数字
(二) 多对多添加记录
# 多对多,作者和书
# 给 Python从入门到入狱 增加作者刘老牛,小矮根;
# 增加作者及目标id,刘老牛【1】、小矮根【2】、萧鼎【3】、刘慈欣【4】
# 由于一对一关联字段,需要先建立作者详情
author_detail_obj1 = models.AuthorDetail.objects.create(gender=0, addr='北京沙河', phone=15512345678)
author_detail_obj2 = models.AuthorDetail.objects.create(gender=0, addr='北京沙河', phone=15587654321)
author_detail_obj3 = models.AuthorDetail.objects.create(gender=0, addr='福建福州', phone=17767676767)
author_detail_obj4 = models.AuthorDetail(gender=0, addr='山西娘子关', phone=18878787878)
author_detail_obj4.save()
# # 增加作者信息:
author_list = {'刘老牛': [18, 1], '小矮根': [81, 2], '萧鼎': [33, 3], '刘慈欣': [32, 4]}
for a_name, age_id in author_list.items():
models.Author.objects.create(name='%s' % a_name, age=age_id[0], author_detail_id=age_id[1])
# 查改操作:
# 对数据和作者进行关联操作【增删改查】
book_obj1 = models.Book.objects.get(name='西游记')
book_obj2 = models.Book.objects.get(name='红楼梦')
book_obj3 = models.Book.objects.get(name='诛仙')
book_obj4 = models.Book.objects.get(name='Python从入门到入狱')
book_obj5 = models.Book.objects.get(name='三体')
# add()【增加】; remove()【删除】; clear()【清空】; set()【先清空,再add,前提是不存在的作者,已存在的不增加】;
book_obj1.authors.add(1)
book_obj2.authors.add(2)
book_obj3.authors.add(3)
book_obj4.authors.add(1, 2)
book_obj5.authors.add(4)
(三) 多对多关系常用的API
# add()【增加】; remove()【删除】; clear()【清空】; set()【先清空,再add,前提是不存在的作者,已存在的不增加】;
#1) 给 Python从入门到入狱 重新设置作者 为 3,4 set([]),传值用列表 或者 元组
book_obj4.authors.set((3, 4))
#2) 给 Python从入门到入狱 删除作者 4
book_obj4.authors.remove(4)
#3) 给 Python从入门到入狱 清空作者
book_obj4.authors.clear()
#4) 给 Python从入门到入狱 增加作者 1 2
book_obj4.authors.add(1, 2)
三 基于对象的跨表查询
(一) 两种跨表查询方式及正、反向查询
#1) 跨表查询有两种方式
-基于对象的跨表查询:子查询
-基于双下划线的跨表查询:关联查询,连表查询
#2) 正、反向查询:
# 个人理解,正反向取决于最终查数据时,是直接使用字段本身,还是使用(另一个)小写表_字段去取。
# 正向查询:book表内有publish字段 直接对象.字段名
# 反向查询:publish表内没有book字段,出版社对象.Book小写_set.all()
#3) 总结:
# 基于对象的跨表查询,先查对象,通过对象再去查另一个对象(正向:字段名,反向:表名小写【一对一】/表名小写_set.all()【一对多】)
(二) 一对多查询
# ——》》一对多【执行了两次查询】
# 查询主键为1的书籍的出版社所在的城市
book_obj = models.Book.objects.get(id=1) # 第一次查询 # # (0.000) SELECT `app01_book`.`id`, `app01_book`.`name`, `app01_book`.`price`, `app01_book`.`publish_date`, `app01_book`.`publish_id` FROM `app01_book` WHERE `app01_book`.`id` = 1; args=(1,)
# book_obj = models.Book.objects.filter(id=1).first()
publish = book_obj.publish # 内部又执行了第二次查询,根据publish_id查询publish # (0.000) SELECT `app01_publish`.`id`, `app01_publish`.`name`, `app01_publish`.`addr`, `app01_publish`.`phone`, `app01_publish`.`email` FROM `app01_publish` WHERE `app01_publish`.`id` = 1; args=(1,)
print(publish.addr)
addr = models.Book.objects.get(id=1).publish.addr
print(addr)
# # 北京出版社出版的所有书籍
publish = models.Publish.objects.get(name='北京出版社') # 第一次查询了出版社
books = publish.book_set.all() # 表名小写_set ,.all()后得到一个queryset对象 # 第二次,根据出版社id,查询所有书
print(books) # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>, <Book: Book object (3)>]>
(三) 一对一查询
# ——》》一对一
# 查询所有住址在 北京 的作者的姓名
# 反向查询:author_detail 没有author字段,author_detail.表名小写
# author_detail = models.AuthorDetail.objects.get(addr__contains='北京') # app01.models.MultipleObjectsReturned: get() returned more than one AuthorDetail -- it returned 2!
author_detail = models.AuthorDetail.objects.filter(addr__contains='北京')
# 反向查询
for k in author_detail:
print(k.author.name)
# 查询 小矮根 作者的地址
# 正向查询,正常.关联表名小写 .author_detail.addr
author = models.Author.objects.get(name='小矮根')
print(author.author_detail.addr) # 北京沙河
(四) 多对多查询
# ————————》》多对多关系查询
# Python从入门到入狱 所有作者的名字以及手机号
book = models.Book.objects.get(name='Python从入门到入狱')
# 正向查询 book表内有 authors 字段,直接对象.字段名
authors = book.authors.all()
for author in authors:
print(author.name)
print(author.author_detail.phone)
# 反向查询 查询 小矮根 出过的所有书籍的名字
# author 表内没有 book 字段,对象.Book小写_set.all()
author_smallegon = models.Author.objects.get(name='小矮根')
books = author_smallegon.book_set.all()
for book in books:
print(book.name)
# # 地址为 山西娘子关 的作者写的所有书
author_detail = models.AuthorDetail.objects.get(addr='山西娘子关')
author = author_detail.author
books = author.book_set.all()
print(books[0].name)
# # 地址为 山西娘子关 的作者写的所有书的出版社名字
author_detail = models.AuthorDetail.objects.get(addr='山西娘子关')
author = author_detail.author
books = author.book_set.all()
for book in books:
print(book.publish.name)
四 基于双下划线的跨表查询
(一) 一对多查询
# ————————》》基于双下划线的跨表查之 一对多
# 正向: 字段名
# 反向: 表名小写
# filter,values,values_list(写 __ 跨表)
# 练习: 查询 北京出版社 出版过的所有书籍的名字与价格(一对多)
res = models.Publish.objects.filter(name='北京出版社').values('book__name', 'book__price')
print(res) # <QuerySet [{'book__name': '西游记', 'book__price': Decimal('21.00')}, {'book__name': '红楼梦', 'book__price': Decimal('22.22')}, {'book__name': '诛仙', 'book__price': Decimal('66.66')}]>
res = models.Book.objects.filter(publish__name='北京出版社').values('name', 'price')
print(res) # <QuerySet [{'name': '西游记', 'price': Decimal('21.00')}, {'name': '红楼梦', 'price': Decimal('22.22')}, {'name': '诛仙', 'price': Decimal('66.66')}]>
(二) 多对多查询
# ————————》》基于双下划线的跨表查之 多对多
# 练习: 查询 刘老牛 出过的所有书籍的名字,价格(多对多)
# 正向查询
res = models.Book.objects.filter(authors__name='刘老牛').values('name', 'price')
print(res) # <QuerySet [{'name': '西游记', 'price': Decimal('21.00')}, {'name': 'Python从入门到入狱', 'price': Decimal('0.50')}]>
# 反向查询
res = models.Author.objects.filter(name='刘老牛').values('book__name', 'book__price')
print(res)
(三) 一对一查询
# 查询 萧鼎 的手机号
res = models.Author.objects.filter(name='萧鼎').values('author_detail__phone')
print(res)
res = models.AuthorDetail.objects.filter(author__name='萧鼎').values('phone')
print(res)
(四) 进阶之连续跨表查询
# ————————》》连续跨表
# 查询 北京出版社 出版过的所有书籍的名字以及作者的姓名
res = models.Publish.objects.filter(name='北京出版社').values('book__name', 'book__authors__name')
print(res)
res = models.Author.objects.filter(book__publish__name='北京出版社').values('book__name', 'name')
print(res)
res = models.Book.objects.filter(publish__name='北京出版社').values('name', 'authors__name')
print(res)
# 手机号以155开头的作者 出版过的所有 书籍名称 以及 出版社名称
res = models.AuthorDetail.objects.filter(phone__startswith='155').values('author__book__name', 'author__book__publish__name')
print(res)
# (0.000) SELECT `app01_book`.`name`, `app01_publish`.`name` FROM `app01_author` INNER JOIN `app01_authordetail` ON (`app01_author`.`author_detail_id` = `app01_authordetail`.`id`) LEFT OUTER JOIN `app01_book_authors` ON (`app01_author`.`id` = `app01_book_authors`.`author_id`) LEFT OUTER JOIN `app01_book` ON (`app01_book_authors`.`book_id` = `app01_book`.`id`) LEFT OUTER JOIN `app01_publish` ON (`app01_book`.`publish_id` = `app01_publish`.`id`) WHERE `app01_authordetail`.`phone` LIKE BINARY '155%' LIMIT 21;
res = models.Author.objects.filter(author_detail__phone__startswith='155').values('book__name', 'book__publish__name')
print(res) # <QuerySet [{'book__name': '西游记', 'book__publish__name': '北京出版社'}, {'book__name': 'Python从入门到入狱', 'book__publish__name': '沙河出版社'}, {'book__name': '红楼梦', 'book__publish__name': '北京出版社'}, {'book__name': 'Python从入门到入狱', 'book__publish__name': '沙河出版社'}]>
(五) 总结
# 基于双下划线的跨表查询(连表查询)
-filter,values,vlues_list中写 __ 连表
- 正向:字段名
- 反向:表名小写
五 聚合查询与分组查询
(一) 聚合查询
# aggregate(*args, **kwargs)
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的【字典】。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。
# #---->>>> 1 聚合查询(聚合函数:最大,最小,和,平均,总个数)
from django.db.models import Avg, Max, Min, Count, Sum
# 1 计算所有图书的平均价格
# aggregate结束,已经不是queryset对象了
book = models.Book.objects.all().aggregate(Avg('price'))
# # 【起别名】-->> avg=Avg('price')
# book = models.Book.objects.all().aggregate(avg=Avg('price'))
print(book) # {'price__avg': 42.074}
# 2 计算总图书数
book = models.Book.objects.all().aggregate(count=Count('id'))
print(book) # {'count': 5}
# 3 计算最低价格的图书
book = models.Book.objects.all().aggregate(min=Min('price'))
print(book) # {'min': Decimal('0.50')}
# 4 计算最大价格图书
book = models.Book.objects.all().aggregate(max=Max('price'))
print(book) # {'max': Decimal('99.99')}
(二) 分组查询
#1) annotate() 内写聚合函数为调用的QuerySet中每一个对象都生成一个独立的统计值(统计方法用聚合函数)。
### 以下的【在前与在后】,均以annotate()位置为参照!!!!
#2) values在前表示group by的字段
#3) values在后表示取某几个字段【只可以取分组字段和[聚合函数修饰后]的自他表内字段!】
#4) filter在前表示where
#5) filter在后表示having
# 总结 :跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询。
# #---->>>> 2 分组查询--》单表
'''
id name price publish_id
1 西游记 21.00 1
2 红楼梦 22.22 1
3 诛仙 66.66 1
4 Python从入门到入狱 0.50 2
5 三体 99.99 3
'''
from django.db.models import Avg, Max, Min, Count, Sum
# 示例一:查询每一个出版社id,以及出书平均价格
# SELECT publish_id, AVG(price) FROM app01_book GROUP BY publish_id;
ret = models.Book.objects.values('publish_id').annotate(avg=Avg('price')).values('publish_id', 'avg')
print(ret) # <QuerySet [{'publish_id': 1, 'avg': 36.626667}, {'publish_id': 2, 'avg': 0.5}, {'publish_id': 3, 'avg': 99.99}]>
# 查询出版社id大于1的出版社id,以及出书平均价格
# SELECT publish_id, AVG(price) FROM app01_book WHERE publish_id>1 GROUP BY publish_id;
ret = models.Book.objects.filter(publish_id__gt=1).values('publish_id').annotate(avg=Avg('price')).values('publish_id', 'avg')
print(ret) # <QuerySet [{'publish_id': 2, 'avg': 0.5}, {'publish_id': 3, 'avg': 99.99}]>
# 查询出版社id大于1的出版社id,以及出书平均价格大于30的
# SELECT publish_id, AVG(price) AS aaa FROM app01_book WHERE publish_id>1 GROUP BY publish_id HAVING aaa>30;
ret = models.Book.objects.filter(publish_id__gt=1).values('publish_id').annotate(avg=Avg('price')).filter(avg__gt=30).values('publish_id', 'avg')
print(ret) # <QuerySet [{'publish_id': 3, 'avg': 99.99}]>
(三) 多表查询练习
# #---->>>> 2 分组查询--》多表
# 1) 查询每一个出版社出版的书籍个数
# pk 代指主键
# select Count('id') from app01.publish inner join app01.book on
ret = models.Book.objects.get(pk=1)
print(ret) # 西游记
### 方式一:
ret = models.Publish.objects.values('pk').annotate(count=Count('book__id')).values('name', 'count')
print(ret) # <QuerySet [{'name': '北京出版社', 'count': 3}, {'name': '沙河出版社', 'count': 1}, {'name': '三体出版社', 'count': 1}]>
### 另一种方式实现
ret = models.Book.objects.values('publish_id').annotate(count=Count('publish_id')).values('publish__name', 'count')
print(ret) # <QuerySet [{'publish__name': '北京出版社', 'count': 3}, {'publish__name': '沙河出版社', 'count': 1}, {'publish__name': '三体出版社', 'count': 1}]>
# 2) 查询每个作者的名字,以及出版过书籍的最高价格(建议使用分组的表作为基表)
# 如果不用分组的表作为基表,数据不完整可能会出现问题
ret = models.Author.objects.values('pk').annotate(max=Max('book__price')).values('name', 'max')
print(ret) # <QuerySet [{'name': '刘老牛', 'max': Decimal('21.00')}, {'name': '小矮根', 'max': Decimal('22.22')}, {'name': '萧鼎', 'max': Decimal('66.66')}, {'name': '刘慈欣', 'max': Decimal('99.99')}]>
#---->>>> group_by 不写的话,默认使用基表的【主键】字段进行分组(不同版本可能使用的默认字段不同)
ret = models.Author.objects.annotate(max=Max('book__price')).values('name', 'max')
print(ret)
ret = models.Book.objects.values('authors__id').annotate(max=Max('price')).values('authors__name', 'max')
print(ret) # <QuerySet [{'authors__name': '刘老牛', 'max': Decimal('21.00')}, {'authors__name': '小矮根', 'max': Decimal('22.22')}, {'authors__name': '萧鼎', 'max': Decimal('66.66')}, {'authors__name': '刘慈欣', 'max': Decimal('99.99')}]>
# 3) 查询每一个书籍的名称,以及对应的作者个数
ret = models.Book.objects.values('pk').annotate(count=Count('authors__id')).values('name', 'count')
print(ret) # <QuerySet [{'name': '西游记', 'count': 1}, {'name': '红楼梦', 'count': 1}, {'name': '诛仙', 'count': 1}, {'name': 'Python从入门到入狱', 'count': 2}, {'name': '三体', 'count': 1}]>
ret = models.Author.objects.values('book__id').annotate(count=Count('id')).values('book__name', 'count')
print(ret) # <QuerySet [{'book__name': '西游记', 'count': 1}, {'book__name': '红楼梦', 'count': 1}, {'book__name': '诛仙', 'count': 1}, {'book__name': 'Python从入门到入狱', 'count': 2}, {'book__name': '三体', 'count': 1}]>
# 4) 统计不止一个作者的图书
ret = models.Book.objects.values('pk').annotate(count=Count('authors__id')).filter(count__gt=1).values('name', 'count')
print(ret) # <QuerySet [{'name': 'Python从入门到入狱', 'count': 2}]>
ret = models.Author.objects.values('book__id').annotate(count=Count('id')).filter(count__gt=1).values('book__name', 'count')
print(ret) # <QuerySet [{'book__name': 'Python从入门到入狱', 'count': 2}]>
# 5) 统计价格数大于10元,作者的图书
ret = models.Book.objects.filter(price__gt=10).values('pk').annotate(count=Count('authors__id')).values('name', 'count')
print(ret) # <QuerySet [{'name': '西游记', 'count': 1}, {'name': '红楼梦', 'count': 1}, {'name': '诛仙', 'count': 1}, {'name': '三体', 'count': 1}]>
# 6) 统计价格数大于10元,作者个数大于1的图书
ret = models.Book.objects.filter(price__gt=10).values('pk').annotate(count=Count('authors__id')).filter(count__gt=1).values('name', 'count')
print(ret) # <QuerySet []>
六 F查询与Q查询
(一) F查询
# #---->>>> F查询:取出数据库的某个字段的值
from django.db.models import F
# # 1) 把read_num都加1
ret = models.Book.objects.all().update(read_num=F('read_num')+1)
print(ret) # 5
# # 2) 查询评论数大于阅读数的书籍
ret = models.Book.objects.all().filter(commit_num__gt=F('read_num'))
for i in ret:
print(i.name, end='<-->') # 诛仙<-->Python从入门到入狱<-->
# # 3) 查询评论数大于阅读数2倍的书籍
ret = models.Book.objects.all().filter(commit_num__gt=F('read_num')*2)
print(ret) # <QuerySet [<Book: Python从入门到入狱>]>
(二) Q查询
# #---->>>> Q查询:制造 与或非的条件 【Q还可以嵌套】
from django.db.models import Q
# # 1) 查询名字叫 红楼梦 或者价格大于 90 的书
ret = models.Book.objects.filter(Q(name='红楼梦') | Q(price__gt=90))
print(ret) # <QuerySet [<Book: 红楼梦>, <Book: 三体>]>
# # 2) 查询名字叫 红楼梦 或者价格大于 90 的书
ret = models.Book.objects.filter(Q(name='红楼梦') & Q(price__gt=90))
print(ret) # <QuerySet []>
# # 3) 查询名字不为 红楼梦 的书
ret = models.Book.objects.filter(~Q(name='红楼梦'))
print(ret) # <QuerySet [<Book: 西游记>, <Book: 诛仙>, <Book: Python从入门到入狱>, <Book: 三体>]>
# Q 可以嵌套使用
# # 4) Q的嵌套
ret = models.Book.objects.filter((Q(name='红楼梦') & Q(price__gt=90)) | Q(id__gt=3))
print(ret) # <QuerySet [<Book: Python从入门到入狱>, <Book: 三体>]>
七 其他补充
(一) 安装模块相关补充
pip3 install django
# 本质是去https://pypi.python.org/simple,搜这个模块,会根据你的平台下载在一个安装包(windows平台是whl),下载完,再安装
# pip安装失败的情况
# 我们可以绕过它,有了whl文件以后,自己装
# https://www.lfd.uci.edu/~gohlke/pythonlibs/#opencv
pip3 install django.whl
# 官方库没有上传到pypi,官方也不给制作whl文件
#如何安装 包 (setup.py)
到达安装目录,setup.py所在的目录
python setup.py build
python setup.py install
# 配置清华源,豆瓣源,本质是
豆瓣源会把pypi,包拉到自己的服务器上,以后你再下,去它的服务器上下,所以速度快
# 你自己写的包,如何上传到pypi上给别人使用?
(二) 前后端分离和混合开发
1) 模板语言:每个语言的web框架都会有模板语言,django---》dtl
2) 模板语言的渲染,是在后端完成的
3) 用php写前端(html,css,js)(是错误说法)
4) 前后端分离:前后端交互,统一全用json格式
5) 前端只专注于写前端(vue,react:前端工程化),后端只专注于写后端(提供接口,交互json格式数据)