1.单表操作和测试环境的准备

我们先对单表查询做一个总结和回顾,并进行进一步的学习和交流。我们在我们的应用的models.py文件下面书写user类。如下所示,然后用数据库迁移,在mysql数据库中生成表。然后进行数据库表的单表查询的操作。

# models.py文件
class User(models.Model):
username = models.CharField(max_length=32, verbose_name='用户名')
password = models.CharField(max_length=32, verbose_name='密码')
age = models.IntegerField(verbose_name='年龄')
info = models.CharField(max_length=256, verbose_name='用户描述')
salary = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='用户的薪水')
register_time = models.DateField(default='2020-8-28',verbose_name='注册时间') '''
这里补充一个知识点:DateField和DateTimeField有两个重要的参数
这两个参数分别是:
auto_now:每次操作数据的时候,该字段会自动将当前时间更新
auto_now_add:在创建数据的时候会自动将当前创建时间记录下来,之后只要不修改,那么时间一直不变。
''' def __str__(self):
return '%s' % self.username

我们之前学了单表操作的知识,在这里我们巩固一下,并且进行更深入一步的学习。我们之前测试我们的models文件是否正常,数据库迁移是否正确,我们都是采用的是前后端交互的技术实现测试的。但是我们知道django的orm语句是比较多的,我们每次对于数据库的操作,orm语句的操作都需要前后端来测试的话,那么这个是十分的麻烦。在这里我们在学习单表操作的同时,也引进了关于测试环境准备的知识点,那么以后我们写好的.py文件的代码,我们可以放到我们的测试环境中,即test.py文件中进行测试。脚本代码无论是写在自己应用下的test.py中,还是自己单独开设.py文件都可以。

测试环境的准备:去manager.py中copy这个文件的前面四行代码,然后自己写两行。测试文件是通用的一个功能,不一定是在应用下的test.py文件,自己也可以新建测试的.py文件,例如mytest.py文件。

在这个代码块下面就可以测试django里面的单个py文件了。所有的代码都要写在测试环境的下面,因为测试环境还没有准备好,我们必须放在测试环境的下面,等待测试环境准备好之后,我们才可以开始测试。所有的代码必须等待环境准备好之后才可以开始书写。

# 测试环境的搭建
import os
def main():
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'model_mysite.settings')
import django
django.setup()
if __name__ == '__main__':
main()

现在我们在我们的测试环境下来测试、使用、学习和扩展我们的单表查询。

 	# 这个导入包的操作必须放在测试环境之后,即django.setup()之后,不然会出现报错。
from app01 import models
# 单表操作--增
# 用create()方法增加
models.User.objects.create(username='zhouqian', password='123456', age=22, info='可甜、可怜、可爱、可傻', salary=12500,register_time='2020-6-26') # 用类的方式增加,save()方法
user_obj = models.User(username='AndreasZhou', password='456789', age=22, info='可骚、可变态、博多、仓老师', salary=22500,register_time='2020-6-28')
user_obj.save() # 单表操作--删
models.User.objects.filter(id=1).delete()
# 查询出某一个数据,然后将这个数据删除,直接调用deldete()方法 # 单表操作--改
# 批量的更新操作。这个其实是所谓的批量的更新的操作,但是因为我们平常用的id值唯一的主键,所以我们这里更新的其实也是一个数据
models.User.objects.filter(id=2).update(username='ZhouQian')
# 单独的更新操作
user_obj = models.User.objects.filter(id=3).first()
user_obj.username = 'ANDREASZHOU'
user_obj.save() # 单表操作--查
res = models.User.objects.filter(id=2) # <QuerySet [<User: User object (2)>]> 类似于列表套对象的形式 <QuerySet [<User: ZhouQian>]>
print(res) user_obj = models.User.objects.filter(id=2).first()
print(user_obj) # User object (2) ZhouQian res = models.User.objects.all()
print(res) # <QuerySet [<User: User object (2)>, <User: User object (3)>]> <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>]> '''
在这里我们需要补充一个知识点就是pk的使用,pk会自动查找到当前表的主键字段,指代的就是当前表的主键字段,用了pk之后,你就不需要指代当前表的主键字段到底叫什么了。uid,pid,sid...。所以我们在平时的使用的时候,我们用pk用的比较的频繁。所以我们后面按照主键查找,我们就按照pk来使用就好了。
'''

2.必知必会13条(重点)

1)all():查询所有

res = models.User.objects.all() # 得到的是一个查询集queryset,类似于列表里面套数据对象
print(res) # <QuerySet [<User: User object (2)>, <User: User object (3)>]> <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>]>

2)filter():带有过滤条件的查询

res = models.User.objects.filter(id=2)  # <QuerySet [<User: User object (2)>]>  类似于列表套对象的形式 <QuerySet [<User: ZhouQian>]>
print(res)# 获取的也是queryset,类似于列表套数据对象 user_obj = models.User.objects.filter(id=2).first()
print(user_obj) # User object (2) ZhouQian 打印出来的直接是一个对象。因为这里显示zhouqian表示的是调用了类中的__str__方法了。

3)get():直接拿数据对象,但是条件不存在那么会直接报错,不推荐使用。

user_obj = models.User.objects.get(id=2)
print(user_obj) # 得到的是User object(2) ZhouQian user_obj = models.User.objects.get(id=4) # app01.models.DoesNotExist: User matching query does not exist. 查询不存在,所以这里报错,其实我们的get方法是不推荐使用的,完全被filter方法给替代了。
print(user_obj) '''
get方法返回的直接就是当前的数据对象,但是该方法不推荐使用,一旦数据不存在该方法会直接报错。
而filter则不会报错,所以我们还是用filter
'''

4)first():拿到queryset里面的第一个元素,即第一个数据对象(queryset是列表套数据对象)

res = models.User.objects.filter(id=2)  # <QuerySet [<User: User object (2)>]>  类似于列表套对象的形式 <QuerySet [<User: ZhouQian>]>
print(res) user_obj = models.User.objects.filter(id=2).first()
print(user_obj) # User object (2) ZhouQian

5)last():拿到queryset里面的最后一个元素,即最后一个数据对象(queryset是列表套数据对象)

res = models.User.objects.filter(id=2)  # <QuerySet [<User: User object (2)>]>  类似于列表套对象的形式 <QuerySet [<User: ZhouQian>]>
print(res) user_obj = models.User.objects.filter(id=2).last()
print(user_obj) # User object (2) ZhouQian user_obj = models.User.objects.all().last()
print(user_obj) # ANDREASZHOU

6)values():可以指定的获取的数据字段 select name,age from ..... 类似于列表套字典

res = models.User.objects.values('name','age')
# 类似于sql语句中的select name,age from User;
print(res)
# 打印出来的结果是一个queryset,这里的queryset我们可以看做是列表套字典的形式,返回结果我们是需要记忆的。记住这是一个返回结果queryset,列表里面套字典的形式,字典的关键字是name和age。
# select username,password from User;
res = models.User.objects.values('username','password')
print(res)

7)values_list():可以指定的获取的数据字段 select name,age from ..... 类似于列表套元组

res = models.User.objects.values('name','age')
print(res)
# 打印出来的结果是一个queryset,这里的queryset我们可以看做是列表套元组的形式,返回结果我们是需要记忆的。记住返回的是一个queryset,里面是列表套元组的形式。
# select username,password from User;
res = models.User.objects.values('username','password')
print(res)
print(res.query)
# 在这里我们补充一个知识点
'''
查看内部封装的sql语句
上述查看sql语句的方式,只能用于QuerySet对象
只有queryset对象才能够点击query查看内部的sql语句
'''

8)distinct():去重

res = models.User.objects.values('username','age').distinct()
print(res)
select distinct username,age from User;
"""
去重一定要是一模一样的数据,如果带有主键那么肯定不一样,你在往后的查询中一定不要忽略主键
"""

9)order_by():排序

res = models.User.objects.order_by('age') # 默认是升序
print(res) res = models.User.objects.order_by('-age') # 现在是降序
print(age) res = models.User.objects.all().order_by('age') # 升序
print(res)

10)reverse():反转,先排序,才可以反转,是建立在排序的基础上的

res = models.User.objects.all()
res1 = models.User.objects.order_by('age').reverse()
print(res,res1)

11)count():统计数量

res = models.User.objects.count()
print(res)

12)exclude():除了什么之外,排除在外。

res = models.User.objects.exclude(name='jason')
print(res)

13)exists():判断是否存在,返回的是布尔值,基本用不到因为数据本身就自带布尔值。

res=models.User.objects.filter(pk=10).exists()
print(res)

3.神器的双下划线查询

1.我们要你帮我查出年龄大于35岁的数据

# 我们写的sql语句是:
select * from user where age >35
res = models.User.objects.filter(age__gt=35)
print(res) # <QuerySet [<User: az>]> 返回的是一个字典,列表里面套数据对象

2.我们要你帮我查出年龄小于35岁的数据

select * from user where age < 35
res = models.User.objects.filter(age__lt=35)
print(res) # <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>]> 返回的是一个字典,列表里面套数据对象。

3.我们要你帮我查出年龄大于等于35岁的数据

select * from user where age >=35;
res = models.User.objects.filter(age__gte=35)----->这里的g是greater,t是than,e是equal
print(res) # <QuerySet [<User: ak>, <User: az>]>。返回的是一个queryset,类似于列表里面套数据对象。

4.我们要你帮我查出年龄小于等于35岁的数据

select * from user where age <=35;
res = models.User.objects.filter(age__lte=35)
print(res) # <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>, <User: ak>]>返回的是一个queryset,类似于列表里面套数据对象。

5.我们要你帮我查出年龄是18或者35或者38

select * from user where age in (18,35,38);
res = models.User.objects.filter(age__in=(18, 35, 38))
print(res) # <QuerySet [<User: ak>, <User: az>]>

6.我们要你帮我查出年龄在18到48岁之间的,首位都要

res = models.User.objects.filter(age__range=[18, 48])
print(res) # <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>, <User: ak>, <User: az>]>返回的是一个queryset,类似于列表里面套数据对象。

7.我们要你帮我查出名字里面含有n的数据,模糊查询,区分大小写

# 默认是区分大小写的
res = models.User.objects.filter(username__contains='n')
print(res) # <QuerySet [<User: ZhouQian>]> 返回的是一个queryset,类似于列表里面套数据对象。

8.我们要你帮我查出名字里面含有n的数据,模糊查询,忽略大小写

 # 忽略大小写
res = models.User.objects.filter(username__icontains='n')
print(res) # <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>]> 返回的是一个queryset,类似于列表里面套数据对象。

9.我们要你帮我查出名字以Z为开头

res = models.User.objects.filter(username__startswith='Z')
print(res) # <QuerySet [<User: ZhouQian>]> 返回的是一个queryset,类似于列表里面套数据对象。

10.我们要你帮我查出名字以U为结尾

res = models.User.objects.filter(username__endswith='U')
print(res) # <QuerySet [<User: ANDREASZHOU>]> 返回的是一个queryset,类似于列表里面套数据对象。

11.我们要你帮我查出注册时间的月

res = models.User.objects.filter(register_time__month=8)
print(res) # <QuerySet [<User: ak>, <User: az>]>

12.我们要你帮我查出注册时间的年

res = models.User.objects.filter(register_time__year=2020)
print(res) # <QuerySet [<User: ZhouQian>, <User: ANDREASZHOU>, <User: ak>, <User: az>]>

4.多表查询

我们在做多表查询的之前需要做一些准备工作,下面就是我们准备工作要写的模型类,将写好的模型类迁移到数据库中,这样我们就可以开始做我们的多表的查询。模型类的代码如下所示。

class Book(models.Model):
title = models.CharField(max_length=32, verbose_name='书名')
price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')
publish_date = models.DateField(auto_now_add=True, verbose_name='出版时间')
publish = models.ForeignKey(to='Publish', verbose_name='书和出版社多对一',on_delete=models.CASCADE)
author = models.ManyToManyField(to='Author', verbose_name='书和作者多对多') class Publish(models.Model):
name = models.CharField(max_length=32, verbose_name='出版社名称')
addr = models.CharField(max_length=32, verbose_name='出版社地址')
email = models.EmailField(verbose_name='联系邮箱')
# EmailField其实和varchar(254)是一样的。
# 该字段类型不是给models看的,而是给我们后面会学到的校验性组件看的。 class Author(models.Model):
name = models.CharField(max_length=32, verbose_name='作者姓名')
age = models.IntegerField(verbose_name='作者年龄')
author_detail = models.OneToOneField(to='AuthorDetail', verbose_name='作者和作者详情一对一',on_delete=models.CASCADE) class AuthorDetail(models.Model):
phone = models.CharField(max_length=32, verbose_name='手机号')
# 电话号码我们用BigIntegerField或者使用直接使用CharField,而不能用IntegerField。
addr = models.CharField(max_length=32, verbose_name='作者地址')

5.外键的增删改

我们前面已经建立了表之间的关系,那么我们现在可以使用orm框架实现外键的增删改查,因为查是最难的知识点,所以我们将查和增删改分开讲解,我们先讲解增删改,后面再讲解查。

1)一对一、一对多外键的增删改

# 一对一、一对多外键的增
# 增:
models.Book.objects.create(title='白蛇传', price=255, publish_id=3) # 1.直接写id的形式增加
publish_obj = models.Publish.objects.filter(pk=2).first() # 2.用对象的形式增加
models.Book.objects.create(title='武当派',price=388,publish=publish_obj)
# 一对一、一对多外键的删
# 删:我们设置为级联更新,级联删除
models.Publish.objects.filter(pk=1).delete()
# 一对一、一对多外键的改
# 改:
models.Book.objects.filter(pk=7).update(publish_id=3) # 1.直接写id的形式更新
publish_obj = models.Publish.objects.filter(pk=1).first() # 2.用对象的形式更新
models.Book.objects.filter(pk=7).update(publish=publish_obj)

2)多对多外键增删改清空

接下来我们学习多对多外键的增删改,我们依次用下面的代码来写:

# 多对多外键的增
# 直接写id的形式增加
book_obj = models.Book.objects.filter(pk=7).first()
print(book_obj.author) # app01.Author.None 就类似于你已经进入了第三张表的关系了
book_obj.author.add(1) # 书籍id为1的书籍绑定一个主键为1的作者 book_obj = models.Book.objects.filter(pk=8).first()
print(book_obj.author) # app01.Author.None 就类似于你已经进入了第三张表的关系了
book_obj.author.add(1, 2, 3, 4) # 用对象的形式增加
author_obj = models.Author.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
author_obj2 = models.Author.objects.filter(pk=4).first()
book_obj = models.Book.objects.filter(pk=4).first()
book_obj1 = models.Book.objects.filter(pk=5).first()
print(book_obj.author) # app01.Author.None 就类似于你已经进入了第三张表的关系了
book_obj.author.add(author_obj, author_obj1, author_obj2)
book_obj1.author.add(author_obj)
'''
add()给第三张关系表添加数据,括号内既可以传数字也可以传对象,并且支持一个或者多个。
'''
# 多对多外键的删
# 直接写id的形式删除
book_obj = models.Book.objects.filter(pk=5).first()
print(book_obj.author) # app01.Author.None 类似于进入了第三张表
book_obj.author.remove(2)
# 用对象的形式删除
author_obj = models.Author.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=3).first()
book_obj = models.Book.objects.filter(pk=4).first()
book_obj.author.remove(author_obj,author_obj1)
'''
remove():括号内既可以传数字也可以传对象,并且数字和对象可以有一个或者是多个。
'''
# 多对多外键的改----记住这里的set方法只可以传入一个可迭代的对象,不然会报错。可迭代对象的列表和元组都是可以的。
# 直接写id的形式修改
book_obj = models.Book.objects.filter(pk=4).first()
book_obj.author.set([2]) # 这个括号内必须是一个可迭代对象,列表和元组都是可以的
book_obj.author.set((3,))
book_obj.author.set([2])
# 用对象的形式修改
book_obj = models.Book.objects.filter(pk=7).first()
author_obj = models.Author.objects.filter(pk=3).first()
author_obj1 = models.Author.objects.filter(pk=4).first()
book_obj.author.set([author_obj, author_obj1]) # 这里面必须是一个可迭代对象,列表和元组都是可以的。
'''
set():set的括号内必须是一个可迭代的对象,可迭代对象里面既可以是数字也可以是对象,并且数字和对象可以有一个或者是多个。
'''
# 多对多的清空---清空的clear()方法中不需要传入任何的参数和对象。我们只要点这个方法就可以。
# 清空:在第三张关系表中清空某个书籍与作者的绑定关系
book_obj = models.Book.objects.filter(pk=7).first()
book_obj.author.clear()
'''
clear():括号内不需要加任何的参数
'''

6.正反向的概念

在我们讲解多表查询的时候,我们在这里先学一个概念,这个概念就是关于正反向的概念,如果我们弄清楚了这个概念以后,我们的下面的学下就会表的更加的轻松。

外键字段在我手上,那么我查你就是正向。外键字段如果不在我手上,那么我查你就是反向。

  • book 》》》外键字段在书哪儿(正向)》》》publish

  • publish》》》外键字段在书哪儿(反向)》》》book

一对一,多对多正反向的判断也是如此

7.多表查询--基于对象的跨表查询(子查询)

正向查询按字段,如果我们发现结果是有多个的时候我们是字段加上all(),如果发现结果只有一个的时候,我们是字段即可。

反向查询按表名小写,如果发现结果有多个的时候我们是表名小写加__set,并且还要加上all()。如果是单个的时候我们是直接表名小写,也不用加__set和all()

1)正向查询

1.查询书籍主键为1的出版社名称

书籍查出出版社  正向
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.publish
print(res) # 打印出来的是出版社对象
print(res.name) # 北京出版社
print(res.addr) # 北京
这个res是一个Publish对象,我们打印调用了`__str__`方法,显示出是对象:北京出版社。

2.查询书籍主键为2的作者

书籍查作者是正向查询
book_obj = models.Book.objects.fliter(pk=2).first()
res = book_obj.author
print(res) # 打印出来是app01.Author.None
res = book_obj.author.all() # 打印出很多个作者对象

3.查询作者jason的电话号码

作者到作者的详情,所以是正向。所以我们这里这样写:
author_obj = models.Author.objects.filter(name='jason').first()
res=author_obj.author_detail
print(res) 得到的结果是一个AuthorDetail对象。
print(res.phone)
print(res.addr)

上面我们得到了一个特点是:利用orm跨表查询是比较的简单。在书写orm语句的时候跟写sql语句是一样的,不要企图一次性将orm语句写完,如果比较复杂,就写一点看一点,分段写

正向的时候什么时候需要加.all()呢?当你的结果可能有多个的时候就需要加.all(),如果是一个则直接拿到数据对象。

2)反向查询

4.查询出版社是北京出版社出版的书籍

出版社查书   反向
publish_obj = models.Publish.objects.filter(name='北京出版社').first()
res = publish_obj.book_set
print(res) # app01.Book.None
res = publish_obj.book_set.all()
print(res) 返回的是queryset,我们可以理解为列表里面套对象

5.查询作者是jason写过的书

Author 到 book 是反向查询
author_obj = models.Author.objects.filter(name='jason').first()
res = author_obj.book_set app01.Book.None
res = author_obj.book_set.all()

6.查询手机号是110的作者姓名

authoudetail 到 author 是反向查询 AuthorDetail-->Book是反向的查询
author_detail_obj = models.AuthorDetail.objects.filter(phone=110).first()
res = author_detail_obj.author
print(res.name)

基于对象反向查询的时候的规律

当你的查询结果可以有多个的时候,我们就必须表名小写加上_set.all()

当你的查询结果只有一个的时候,我们就必须是表名小写,不需要加_set.all()

8.多表查询--基于双下划线的跨表查询(联表查询)

例子1.查询书籍主键为1的出版社名称(一行代码搞定)

select Publish.name from (select * from Book,Publish where publish_id = Publish.id ) as Book_Publish where Book.id =1;

1.查询jason的手机号和作者姓名

正向

res=models.Author.objects.filter(name='json').values('author_detail__phone',‘name’)
print(res) # query_set:类似于列表里面套字典

反向

res = model.AuthorDetail.objects.filter(author__name='jason')   拿作者姓名jason的作者详情
res = model.AuthorDetail.objects.filter(author__name='jason').values('phone','author__name')
print(res)

2.查询书籍主键为1的出版社名称和书的名字

正向

# 书籍查出版社是正向
res = models.Book.objects.filter(pk=1).values('publish__name','title')
print(res)

反向

res = models.Publish.objects.filter(book__id=1).values('name','book__title')
print(res)

3.查询书籍主键为1的作者姓名

正向

res = models.Book.objects.filter(pk=1).values('author__name')
print(res) # queryset 类似于列表里面套字典

反向

res= models.Author.objects.filter(book__pk=1).values('name')
print(res) # queryset 类似于列表里面套字典

4.查询书籍主键是1的作者的手机号

Book Author AuthorDetail

res = models.Book.objects.filter(pk=1).values('author__author_detail__phone')
print(res)

你只要掌握了正反向的概念以及双下划线的查询,那么你就可以无限制的跨表查询,联表查询。

9.聚合查询

在这里我们先学习一个东西,我们必须明白一个理论的知识。这个理论知识就是:只要是跟数据库相关的模块基本上都在django.db.models里面,如果上述没有那么应该在django.db里面。聚合函数涉及的一般是如下:max,min,sum,count,avg,在django中,我们应该使用aggregate()。

from app01 import models
from django.db.models import Max,Min,Count,Sum,Avg # 1.计算所有书的平均价格
res = models.Book.objects.aggregate(Avg('price'))
print(res)
# 2.上诉的方法统一使用
res=models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('pk'),Avg('price'))
print(res) # 返回的是字典
{'price__max': Decimal('388.00'), 'price__min': Decimal('255.00'), 'pk__count': 5, 'price__avg': Decimal('334.800000'), 'price__sum': Decimal('1674.00')}

10.分组查询

分组在mysql中是group by,在我们的django是用annotate作为分组的使用。一般分组和聚合是在一起使用的。两者相辅相成,也就是我们平时所说的分组聚合。

MySQL分组查询有哪些特点呢?分组时候默认只能获取到分组的依据,组内其他字段无法直接获取了。因为MySQL默认是严格模式,ONLY_FULL_GROUP_BY

我们看下面的几个题目来深刻的体会和理解分组查询的意义和内涵。

# 1.统计每一本书的作者的个数
# models后面点什么我们就按照什么来分组,models.Book.objects.values('price').annotate()按照书的价格分组
# res = models.Book.objects.annotate(author_number=Count('author__id')).values('title', 'author_number')
# print(res)<QuerySet [<Book: Book object (3)>, <Book: Book object (4)>, <Book: Book object (5)>, <Book: Book object (7)>, <Book: Book object (8)>]>
# print(res)
# < QuerySet[{'title': '小斌张嘎', 'author_number': 0}, {'title': '白蛇传', 'author_number': 1}, {'title': '武当派',
# 'author_number': 0}, {
# 'title': '聊斋', 'author_number': 2}, {'title': '斗破苍穹', 'author_number': 4}] > # 2.统计每一个出版社卖的最便宜的书的价格
# res = models.Publish.objects.annotate(book_price=Min('book__price')).values('name', 'book_price')
# print(res)
# < QuerySet[{'name': '上海出版社', 'book_price': Decimal('388.00')}, {'name': '杭州出版社', 'book_price': Decimal('255.00')}, {
# 'name': '北京出版社', 'book_price': Decimal('255.00')}, {'name': '嘉兴出版社', 'book_price': None}] > # 3.统计不止是一个作者的图书
# res = models.Book.objects.annotate(author_num=Count('author__pk')).filter(author_num__gt=1).values('title', 'author_num')
# print(res) # <QuerySet [{'title': '聊斋', 'author_num': 2}, {'title': '斗破苍穹', 'author_num': 4}]> # 4.查询每个作者出的书的总价格
# res = models.Author.objects.annotate(book_sum=Sum('book__price')).values('name', 'book_sum')
# print(res)
# < QuerySet[{'name': 'AndreasZhou', 'book_sum': Decimal('643.00')}, {'name': '周周', 'book_sum': Decimal('643.00')}, {
# 'name': '憨憨', 'book_sum': Decimal('643.00')}, {'name': '周乾', 'book_sum': Decimal('388.00')}] >

在这里我们补充一个知识点,这个知识点就是:只要你的orm语句得出来的结果还是一个QuerySet对象,那么它就可以继续无限制的点QuerySet对象封装的方法。

还有一个知识点就是,如果我想要按照指定的字段分组该如何处理呢?

models.Book.objects.values('price').annotate(),后续我们在写项目的时候会使用到这个知识点。

11.F查询

我们现在来讲解一下什么是F查询,F查询的用途是什么呢?

F查询:能够帮助你直接获取到列表中某个字段对应的数据

1.查询卖出数大于库存数的书籍

from django.db.models import F
res = models.Book.objects.filter(maichu__gt=F('库存'))
print(res)
# <QuerySet [<Book: Book object (3)>, <Book: Book object (7)>]>

2.将所有书籍的价格提升50块

# 2.将所有书籍的价格提升50块
from django.db.models import F
res = models.Book.objects.all().values('title', 'price')
print(res)
res = models.Book.objects.update(price=F('price') + 50)
print(res) models.Book.objects.update(price=F('price')+50)
F('price'):表示获取的是原来的价格

3.将所有书的名称后面加上爆款两个字(了解)

'''
在操作字符串类型的数据的时候,F不能够直接做到字符串的拼接。
'''
from django.db.models.functions import concat
from django.db.models import Value
models.Book.objects.update(title=concat((F('title'),Value('爆款')))

12.Q查询

在学习Q查询之前,我们先来说明一个问题,filter默认只是支持使用的是与(and)关系。但是往往这样一种关系是不能满足于我们平时的使用。所以我们需要更多的逻辑关系,使得我们更加的操作方便,因此我们在这里引入了一种查询方式,这个查询方式叫做Q查询。

1.查询卖出数大于100或者价格小于600的书籍

`res = models.Book.objects.filter(maichu__gt=100,price__lt=600)`

`print(res)`

'''

filter括号内多个参数是and关系,是我们想要的是或,非等关系,那我们怎么办呢?

'''

from django.db.models import Q

`res = models.Book.objects.filter(Q(maichu__gt=100,price__lt=600))` Q包裹,逗号分隔,还是and关系

`res = models.Book.objects.filter(Q(maichu__gt=100|price__lt=600))` Q包裹,|分隔,or关系

`res = models.Book.objects.filter(~Q(maichu__gt=100,price__lt=600))`   Q包裹,~分隔,not关系

`print(res)`

2.Q的高阶用法 能够将查询条件左边也变成字符串的形式,而不再是变量名的形式。使用Q我们可以实现一个简单的搜索功能。

q = Q()
q.connector='or'
q.children.append(('maichu__gt',100))
q.children.append(('price__lt',600))
res=models.Book.objects.filter(q) # filter括号内也支持直接放q对象,默认还是and关系
print(res)

13.django中如何开启事务

事务:我们知道事务有四个特性,这四个特性分别是:

原子性:不可分割的最小单位。

一致性:跟原子性是相辅相成的。

隔离性:事务之间是互相不干扰。

持久性:事务一旦确认是永久有效的。

事务的回滚:rollback

事务的确认:commit

from django.db import transaction
try:
with transaction.atomic():
# sql1
# sql2
# ...
# 在with代码块内书写的所有orm操作都是同一个事务
except Exception as e:
print(e)
print('执行其他操作')

14.orm中常用字段以及参数

# 常用字段
AutoField()
IntegerField()
CharField()
DecimalField()
EmailField()
DateField()
DateTimeField()
TimeField()
OneToOneField()
ManyToManyField()
ForeignField()
# 常用参数
null
unique
verbose_name
default
auto_now
auto_now_add
to
to_field
on_delete
max_length
choices
# 了解字段
SmallIntegerField()
PositiveSmallIntegerField()
PositiveIntegerField()
PositiveIntegerField()
BooleanField()
# 了解参数
related_name
through
through_fields
db_table

参考:https://www.cnblogs.com/liuqingzheng/articles/9627915.html

15.choices参数(数据库字段设计常见)

'''
用户表
姓名
学历
工作经验
是否生子
是否结婚
客户来源
...
针对某个可以列举完全的可能性字段,我们该如何存储? 只要某个字段的可能性是可以列举完全的,那么一般情况下都会采用choices参数
'''
class User(models.Model):
username = models.CharField(max_length=32,verbose_name='用户名')
age = models.IntegerField(verbose_name='年龄')
gender_choices = (
(1,'男'),
(2,'女'),
(3,'其他'),
)
gender = models.IntegerField(choices=gender_choices)
'''
改gender字段存的还是数字,但是如果存的数字在上面元组列举的范围之内,那么可以非常轻松的获取到数字对应的真正内容。
1.gender字段存的数字不在上述元组列举的范围内容
2.如果在的话,如何获取对应的中文信息
'''
from app01 import models
models.User.objects.create(username='zhouqian',age=18,gender=1)
models.User.objects.create(username='zhoukun',age=28,gender=2)
models.User.objects.create(username='AndreasZhou',age=20,gender=3)
models.User.objects.create(username='thanzhou',age=18,gender=4) user_obj = models.User.objects.filter(pk=1).first()
print(user_obj.gender) user_obj = models.User.objects.filter(pk=1).first()
# 只要是choices参数的字段,如果想要获取对应信息。固定写法:get_字段名_display()
print(user_obj.get_gender_display()) # 如果没有对应关系,那么字段是什么还是展示什么
user_obj = models.User.objects.filter(pk=4)..first()
print(user_obj.get_gender_display()) # 4
gender_choices=(
(1,'男'),
(2,'女'),
(3,'其他'),
)
gender = models.IntegerField(choices=gender_choices) scores_choices = (
('A','优秀'),
('B','良好'),
('C','及格'),
('D','不及格'),
)
# 保证字段的类型跟列举出来的元组的第一个数据类型一致即可。
score = models.CharField(choices=scores_choices,null=True)

16.多对多三种创建方式

# 系统自带
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author') class Author(models.Model):
name = models.CharField(max_length=32) '''
优点:代码不需要你写,非常方便,还支持orm提供操作第三张关系表的方法,add(),remove(),clear(),set()
不足之处:第三张关系表的扩展性极差(没有第三张表,没有办法额外添加字段)
'''
# 纯手动
class Book(models.Model):
name = models.CharField(max_length=32) class Author(models.Model):
name = models.CharField(max_length=32) class Book2Author(models.Model):
book_id = models.ForeignKey(to='Book')
author_id = models.ForeignKey(to='Author') '''
优点:第三张表完全取决于你自己进行额外的扩展
不足之处:需要你自己手写代码,写的代码比较多。不能够使用orm提供的简单的方法,不建议你用该方式。
'''
# 半自动
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author',
through='Book2Author'
through_fields=('book','author')
) class Author(models.Model):
name = models.CharField(max_length=32) class Book2Author(models.Models):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author') '''
半自动:可以使用orm的正反向查询,但是没发使用add,set,remove,clear这四个方法 '''

总结:需要掌握全自动和半自动,为了扩展性更高,一般我们都会采用半自动(写代码给自己留一条后)。

django学习(三)的更多相关文章

  1. day17 Django学习三

    参考博客: http://www.cnblogs.com/wupeiqi/articles/5237704.html http://www.cnblogs.com/wupeiqi/articles/5 ...

  2. Django学习(三) Django模型创建以及操作

    在Django中可以建立自己的模型Model,这里对应Java里的实体类,跟数据库表是对应的.其中用到了django.db模块中的models.如下图所示: mysite/news/models.py ...

  3. python+django学习三

    在这个网站看https://sshwsfc.github.io/xadmin/     xadmin结果一堆的坑,文档找不到界面,dome登陆就报错permission denied for rela ...

  4. Django学习笔记(三)—— 型号 model

    疯狂暑期学习 Django学习笔记(三)-- 型号 model 參考:<The Django Book> 第5章 1.setting.py 配置 DATABASES = { 'defaul ...

  5. Django基础学习三_路由系统

    今天主要来学习一下Django的路由系统,视频中只学了一些皮毛,但是也做下总结,主要分为静态路由.动态路由.二级路由 一.先来看下静态路由 1.需要在project中的urls文件中做配置,然后将匹配 ...

  6. Django 学习笔记(三)模板导入

    本章内容是将一个html网页放进模板中,并运行服务器将其展现出来. 平台:windows平台下Liunx子系统 目前的目录: hello ├── manage.py ├── hello │ ├── _ ...

  7. django 学习之DRF (三)

    Django学习之DRF-03 视图集    1.视图集介绍    2.视图集基本使⽤        1.需求 使⽤视图集获取列表数据和单⼀数据        2.实现 class BookInfoV ...

  8. Django 学习笔记之四 QuerySet常用方法

    QuerySet是一个可遍历结构,它本质上是一个给定的模型的对象列表,是有序的. 1.建立模型: 2.数据文件(test.txt) 3.文件数据入库(默认的sqlite3) 入库之前执行 数据库同步命 ...

  9. Python框架之Django学习

    当前标签: Django   Python框架之Django学习笔记(十四) 尛鱼 2014-10-12 13:55 阅读:173 评论:0     Python框架之Django学习笔记(十三) 尛 ...

随机推荐

  1. 如何用Keil MDK5创建新项目

    1.安装相应软件 2.创建与Build项目 创建项目 下载与调试— ST-Link

  2. “随手记”开发记录day07

    今天完成了关于我们页面中的相关信息,由于之前没有做过这个东西,只想着用一个view解决 可是发现我们整的太简单了,还是太年轻,最后想出来要跟java代码一起解决这个问题, 效果

  3. 介绍一种 Python 更方便的爬虫代理池实现方案

    现在搞爬虫,代理是不可或缺的资源 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那 ...

  4. 2020-03-26:eureka 和其他注册中心比如zk有什么不同?

    从eureka工作原理可以看出,eureka client有缓存功能,即使eureka所有的serve都宕掉,仍然能给服务消费者发送服务信息,所以eureka保证了服务可用性,不能保证数据一致性,是一 ...

  5. C#LeetCode刷题之#448-找到所有数组中消失的数字(Find All Numbers Disappeared in an Array)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3712 访问. 给定一个范围在  1 ≤ a[i] ≤ n ( n ...

  6. 总结vue知识体系之实用技巧

    vue 作为目前前端三大框架之一,对于前端开发者可以说是必备技能.那么怎么系统地学习和掌握 vue 呢?为此,我做了简单的知识体系体系总结,不足之处请各位大佬多多包涵和指正,如果喜欢的可以点个小赞!本 ...

  7. 阿里云体验实验室 教你如何《快速搭建LNMP环境》

    ## 体验平台简介 面向开发者和中小企业打造的一站式.全云端的开发平台,打开浏览器就可以开发.调试.上线,所测即所得,并结合无服务器的模式,重新定义云原生时代的研发工作方法论.旨在降低开发者上手成本和 ...

  8. Atomic原子类

    Atomic原子类 Atomic原子类位于并发包java.util.concurrent下的java.util.concurrent.Atomic中. 1. 原子更新基本类型类 使用原子方式更新基本数 ...

  9. 【数论】莫比乌斯反演Mobius inversion

    本文同步发布于作业部落,若想体验更佳,请点此查看原文.//博客园就是渣,连最基本的符号都打不出来.

  10. Android 用空格作为分割符切割字符串

    项目中有需要用到空格作为分割符切割字符串,进而转为List. String wordStore = edWord.getText().toString(); String[] word = wordS ...