065.django之多表查询

一 创建模型

(一) 模型创建

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格式数据)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值