django学习(三)
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学习(三)的更多相关文章
- day17 Django学习三
参考博客: http://www.cnblogs.com/wupeiqi/articles/5237704.html http://www.cnblogs.com/wupeiqi/articles/5 ...
- Django学习(三) Django模型创建以及操作
在Django中可以建立自己的模型Model,这里对应Java里的实体类,跟数据库表是对应的.其中用到了django.db模块中的models.如下图所示: mysite/news/models.py ...
- python+django学习三
在这个网站看https://sshwsfc.github.io/xadmin/ xadmin结果一堆的坑,文档找不到界面,dome登陆就报错permission denied for rela ...
- Django学习笔记(三)—— 型号 model
疯狂暑期学习 Django学习笔记(三)-- 型号 model 參考:<The Django Book> 第5章 1.setting.py 配置 DATABASES = { 'defaul ...
- Django基础学习三_路由系统
今天主要来学习一下Django的路由系统,视频中只学了一些皮毛,但是也做下总结,主要分为静态路由.动态路由.二级路由 一.先来看下静态路由 1.需要在project中的urls文件中做配置,然后将匹配 ...
- Django 学习笔记(三)模板导入
本章内容是将一个html网页放进模板中,并运行服务器将其展现出来. 平台:windows平台下Liunx子系统 目前的目录: hello ├── manage.py ├── hello │ ├── _ ...
- django 学习之DRF (三)
Django学习之DRF-03 视图集 1.视图集介绍 2.视图集基本使⽤ 1.需求 使⽤视图集获取列表数据和单⼀数据 2.实现 class BookInfoV ...
- Django 学习笔记之四 QuerySet常用方法
QuerySet是一个可遍历结构,它本质上是一个给定的模型的对象列表,是有序的. 1.建立模型: 2.数据文件(test.txt) 3.文件数据入库(默认的sqlite3) 入库之前执行 数据库同步命 ...
- Python框架之Django学习
当前标签: Django Python框架之Django学习笔记(十四) 尛鱼 2014-10-12 13:55 阅读:173 评论:0 Python框架之Django学习笔记(十三) 尛 ...
随机推荐
- 如何用Keil MDK5创建新项目
1.安装相应软件 2.创建与Build项目 创建项目 下载与调试— ST-Link
- “随手记”开发记录day07
今天完成了关于我们页面中的相关信息,由于之前没有做过这个东西,只想着用一个view解决 可是发现我们整的太简单了,还是太年轻,最后想出来要跟java代码一起解决这个问题, 效果
- 介绍一种 Python 更方便的爬虫代理池实现方案
现在搞爬虫,代理是不可或缺的资源 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的人,却不知道如何去学习更加高深的知识.那 ...
- 2020-03-26:eureka 和其他注册中心比如zk有什么不同?
从eureka工作原理可以看出,eureka client有缓存功能,即使eureka所有的serve都宕掉,仍然能给服务消费者发送服务信息,所以eureka保证了服务可用性,不能保证数据一致性,是一 ...
- C#LeetCode刷题之#448-找到所有数组中消失的数字(Find All Numbers Disappeared in an Array)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3712 访问. 给定一个范围在 1 ≤ a[i] ≤ n ( n ...
- 总结vue知识体系之实用技巧
vue 作为目前前端三大框架之一,对于前端开发者可以说是必备技能.那么怎么系统地学习和掌握 vue 呢?为此,我做了简单的知识体系体系总结,不足之处请各位大佬多多包涵和指正,如果喜欢的可以点个小赞!本 ...
- 阿里云体验实验室 教你如何《快速搭建LNMP环境》
## 体验平台简介 面向开发者和中小企业打造的一站式.全云端的开发平台,打开浏览器就可以开发.调试.上线,所测即所得,并结合无服务器的模式,重新定义云原生时代的研发工作方法论.旨在降低开发者上手成本和 ...
- Atomic原子类
Atomic原子类 Atomic原子类位于并发包java.util.concurrent下的java.util.concurrent.Atomic中. 1. 原子更新基本类型类 使用原子方式更新基本数 ...
- 【数论】莫比乌斯反演Mobius inversion
本文同步发布于作业部落,若想体验更佳,请点此查看原文.//博客园就是渣,连最基本的符号都打不出来.
- Android 用空格作为分割符切割字符串
项目中有需要用到空格作为分割符切割字符串,进而转为List. String wordStore = edWord.getText().toString(); String[] word = wordS ...