目录html
方式1:python
# 若是想单独测试django中的某个文件,须要手动配置测试脚本(在你应用下的tests.py文件中) import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day55.settings") import django django.setup() # 在测试脚本搭建完毕以后,才能导入django文件进行测试 from app01 import models
方式2:git
直接新建一个任意名称的.py文件,将方式1中的配置拿过来就好了。sql
首先建立模型表:数据库
from django.db import models # Create your models here. class Books(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField()
1.新增(create())django
向数据库添加一条记录后端
# 第一种 : book_obj = models.Books.objects.create(title = '人性的弱点',price='172.44',publish_date='2008-08-08') # 日期格式能够直接写,也能够经过datetime模块生成一个年月日传进去 # 第二种:(利用对象的绑定方法) book_obj = models.Books(title = '将来简史',price='399.44',publish_date='2008-08-09') book_obj.save() ''' 返回的是对象自己 '''
2.修改(update())app
修改表中某一条记录的某些字段函数
res=models.Books.objects.filter(id=1).filter().filter().filter()... ''' id能够写成pk,表示任意一张表的主键字段,咱们不须要记本身建表时设置的主键字段的名字,直接写成pk=? 的形式,就more你是当前表的主键了; 返回的res是一个QuerySet对象,能够无限制的调用queryset对象,表示按照当前filter查询的结果继续按照你写的条件继续往下查询; queryset对象还能够点query查看当前结果内部对应的sql语句 ''' res=models.Books.objects.filter(id=1) print(res.query) ''' SELECT `app01_books`.`id`, `app01_books`.`title`, `app01_books`.`price`, `app01_books`.`publish_date` FROM `app01_books` WHERE `app01_books`.`id` = 1 ''' #方式1: models.Books.objects.filter(id=1).update(price=88.88) # 当条件不存在时,filter空queryset对象,推荐使用filter进行查询。 # 方式2: book_obj = models.Books.objects.get(pk=1) # 返回的是对象自己,get在条件不存在时会报错,不推荐使用这种方法作修改操做。 book_obj.price = 88.88 book_obj.save()
3.删除(delete())测试
删除表中的一条记录
# 方式1: models.Books.objects.filter(pk=3).delete() # 方式2: book_obj = models.Books.objects.get(pk=3) book_obj.delete()
如需将你的orm查询语句内部对应的sql语句打印在终端,能够在Django项目的settings.py配置文件中配置以下代码:
LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
all()
查询全部
res = models.Books.objects.all() # 查询全部 ,返回的结果QuerySet对象 ''' <QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>]> '''
filter()
筛选
res = models.Books.objects.filter(pk=2,title='活着') # 返回的结果QuerySet对象,支持传多个参数 而且是and关系
get()
筛选
res = models.Books.objects.get(title='活着',price = '99.9') # 获取的是数据对象自己,查询条件不存在报错,也能够传多个参数 ''' Books object '''
first()
取queryset中第一个数据对象 ,那么返回的就是一个普通的数据对象了
res = models.Books.objects.filter(title='活着').first()
last()
取queryset中最后一个数据对象 ,返回的就是一个普通的数据对象
res = models.Books.objects.filter(title='活着').last()
count()
统计数据的个数,返回的是数字(数据个数)
num = models.Books.objects.count()
values()
获取数据对象中指定的字段的值
# 按照指定条件查询 res = models.Books.objects.filter(pk=2).values('title','price') print(res) # <QuerySet [{'title': '活着', 'price': Decimal('99.90')}]> # 查全部 res = models.Books.objects.values('title','price') # 能够传多个参数, 返回的是QuerySet对象,列表套字典 ''' <QuerySet [{'title': '三国演义', 'price': Decimal('99.99')}, {'title': '活着', 'price': Decimal('99.90')}, {'title': '许三多卖血记', 'price': Decimal('199.88')}, {'title': '平凡的世界', 'price': Decimal('166.66')}, {'title': '富国论', 'price': Decimal('888.88')}, {'title': '鬼谷子', 'price': Decimal('35.55')}, {'title': '人性的弱点', 'price': Decimal('172.44')}, {'title': '人性的弱点', 'price': Decimal('172.44')}]> '''
values_list()
获取数据对象中指定的字段的值
res = models.Books.objects.values_list('title','price') # 能够传多个参数, 返回的是QuerySet对象,列表套元组 ''' <QuerySet [('三国演义', Decimal('99.99')), ('活着', Decimal('99.90')), ('许三多卖血记', Decimal('199.88')), ('平凡的世界', Decimal('166.66')), ('富国论', Decimal('888.88')), ('鬼谷子', Decimal('35.55')), ('人性的弱点', Decimal('172.44')), ('人性的弱点', Decimal('172.44'))]> '''
order_by()
按照指定的字段排序
# 升序(两种写法) res = models.Books.objects.order_by('price') # 默认是升序,返回的是queryset对象 res1 = models.Books.objects.all().order_by('price') # 降序 res = models.Books.objects.order_by('-price') # 字段前面加负号
res = models.Books.objects.order_by('price').values('title','price') print(res) # queryset对象能够继续经过点语法操做 ''' <QuerySet [{'title': '鬼谷子', 'price': Decimal('35.55')}, {'title': '活着', 'price': Decimal('99.90')}, {'title': '三国演义', 'price': Decimal('99.99')}, {'title': '平凡的世界', 'price': Decimal('166.66')}, {'title': '人性的弱点', 'price': Decimal('172.44')}, {'title': '人性的弱点', 'price': Decimal('172.44')}, {'title': '许三多卖血记', 'price': Decimal('199.88')}, {'title': '富国论', 'price': Decimal('888.88')}]> '''
reverse()
颠倒顺序 ,必须是有序的状况下才能颠倒
res = models.Books.objects.all().order_by('price').reverse() ''' res = models.Books.objects.reverse().values('title','price') # 不排序的状况下返回值按照数据库的id顺序打印,没办法帮你颠倒 print(res) res = models.Books.objects.all().order_by('price').reverse().values('title', 'price') print(res) """ <QuerySet [{'title': '富国论', 'price': Decimal('888.88')}, {'title': '许三多卖血记', 'price': Decimal('199.88')}, {'title': '人性的弱点', 'price': Decimal('172.44')}, {'title': '人性的弱点', 'price': Decimal('172.44')}, {'title': '平凡的世界', 'price': Decimal('166.66')}, {'title': '三国演义', 'price': Decimal('99.99')}, {'title': '活着', 'price': Decimal('99.90')}, {'title': '鬼谷子', 'price': Decimal('35.55')}]> """ '''
exclude()
排除,按照指定条件排除数据,返回的是排除掉的数据以外的其余数据
# 方式1 res = models.Books.objects.all().exclude(title='三国演义') # queryset对象 # 方式2 res = models.Books.objects.exclude(title='三国演义')
exists()
判断查询结果是否有值 返回结果是一个布尔值
res = models.Books.objects.filter(pk=1).exists() print(res)
distinct()
按照指定的条件去重
res = models.Books.objects.values('title','price').distinct() # 能够传入多个去重条件,把这多个条件都同样的数据剔除掉 返回的是一个queryset对象
models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值 models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于十一、2二、33的数据;,也能够写成括号的形式 models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="活") # 获取name字段包含"活"的 models.Tb1.objects.filter(name__icontains="活") # icontains大小写不敏感 models.Tb1.objects.filter(id__range=[1, 3]) # id范围是1到3的,顾头顾尾 ,也能够写成括号的形式 res = models.Tb1.objects.filter(title__endswith='活') # 以“活”开头的 res = models.Tb1.objects.filter(title__endswith='活') # 以“活”结尾的 date字段: date字段能够经过在其后加__year,__month,__day等来获取date的特色部分数据 res=models.Tb1.objects.filter(publish_date='2008-08-08') # 指定年月日 res=models.Tb1.objects.filter(publish_date__lte='2002-03-28') # 日期小于等于2002-03-28的 也能够是lt,或者单独指定year,month,day res=models.Tb1.objects.filter(publish_date__gte='2002-03-28') # 日期大于等于2002-03-28的 也能够是gt res=models.Tb1.objects.filter(publish_date__year='2007') # 只指定年份 res=models.Tb1.objects.filter(publish_date__month='08') # 指定月份 res=models.Tb1.objects.filter(publish_date__day='29') # 指定某一天 models.Tb1.objects.filter(publish_date__week_day=2) models.Tb1.objects.filter(publish_date__week_day__gte=2)
class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField(auto_now_add=True) stored = models.IntegerField(default=1000) saled = models.IntegerField(default=1000) def __str__(self): # 打印对象是触发,控制打印格式 return self.title """ auto_now:每次修改的数据的时候 都会自动更新修改书籍(展现最新的一次修改时间) auto_now_add:当数据建立出来的时候 会自动将建立时间记录下来 """ publish = models.ForeignKey(to='Publish') # 一对多关系,外键字段建在查询频率较高的一方 authors = models.ManyToManyField(to='Author') # 多对多关系,多对多字段建在查询频率较高的一方 class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) def __str__(self): return self.name class Author(models.Model): name = models.CharField(max_length=32) email = models.EmailField() # 对应到数据库的表当中是varchar类型,长度是254 author_detail = models.OneToOneField(to='AuthorDetail') # 一对一关系,一对多字段建在查询频率较高的一方 def __str__(self): return self.name class AuthorDetail(models.Model): phone = models.BigIntegerField() addr = models.CharField(max_length=64) def __str__(self): return self.addr ''' 模型表类建完之后,要使用数据库迁移命令,把表迁移到数据库当中,建表才算完毕 python3 manage.py makemigrations python3 manage.py migrate '''
增
# 方式1: models.Book.objects.create(title='三国演义',price=222.33,publish_id=1) # 直接传表里面的实际字段和数据主键值 # 方式2: publish_obj = models.Publish.objects.filter(pk=2).first() models.Book.objects.create(title='红楼梦',price=444.33,publish=publish_obj) # 传虚拟字段 跟数据对象便可
改
# 方式1: models.Book.objects.filter(pk=1).update(publish_id=2) # 方式2: publish_obj = models.Publish.objects.filter(pk=1).first() models.Book.objects.filter(pk=1).update(publish=publish_obj)
删
models.Publish.objects.filter(pk=1).delete() # 默认级联删除,级联更新,这里删除id=1的出版社,出版社id=1的图书也都跟着删除
增(add)
book_obj = models.Book.objects.filter(pk=2).first() # print(book_obj.publish) # Publish object # print(book_obj.authors) # app01.Author.None 已经跨到第三张表了 # 方式1:(add支持传入多个,以逗号分开) book_obj.authors.add(1) # 在第三张表里面给此书籍对象绑定一个author_id=1的做者 # 方式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方法 可以朝第三张关系表添加数据,即支持传数字--》add(1,2);也支持传对象,add(author_obj,author_obj1);而且二者均可以是多个。
改(set)
book_obj = models.Book.objects.filter(pk=2).first() # 方式1: book_obj.authors.set((1,3)) book_obj.authors.set([1,]) # 方式2: author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() book_obj.authors.set((author_obj,author_obj1))
总结:set方法修改多对多关系表中的数据,既能够传数字也能够传对象,可是传入的一个或多个参数必须是一个可迭代对象,即用小括号或中括号括起来,内部传入你须要的参数数量。ps: set((1,3)), set((author_obj,author_obj1))
删(remove)
book_obj = models.Book.objects.filter(pk=2).first() # 方式1: book_obj.authors.remove(100) book_obj.authors.remove(1,2) # 方式2: author_obj = models.Author.objects.filter(pk=1).first() author_obj1 = models.Author.objects.filter(pk=2).first() book_obj.authors.remove(author_obj) book_obj.authors.remove(author_obj,author_obj1)
总结:remove方法,既能够传数字 也能够传对象;而且都支持传多个 不须要迭代;ps:remove(1,2), remove(author_obj,author_obj1)
清空(clear)
删除某个数据在第三张表中的全部记录
book_obj = models.Book.objects.filter(pk=2).first() book_obj.authors.clear()
正反向查询:
都是基于对象的跨表查询
关系字段在谁哪 由谁查相关联的表就是正向
若是关系字段不在当前表,就是反向
正向查询按外键字段:正向查询,当被查询出来的数据有多个的状况下,须要点.all();ps:app01.Author.None,一旦看到该结果 只须要加.all()便可
**反向查询按表名小写 + _set:**可是,在一对多,多对多的状况下,才须要加;在一对一的关系中,不须要代表小写加_set。
正向查询
1.查询书籍主键为2的出版社名称
book_obj = models.Book.objects.filter(pk=2).first() print(book_obj.publish) # 出版社对象 print(book_obj.publish.name)
2.查询书籍主键为4的做者姓名
book_obj = models.Book.objects.filter(pk=4).first() print(book_obj.authors) # app01.Author.None,跨入到了Author这张表中。 print(book_obj.authors.all()) # 一本书可能有多个做者,因此须要点.all() 返回的是queryset对象,列表内部是一个个的做者对象<QuerySet [<Author: Author object>, <Author: Author object>]>,这个是设置打印格式以后的显示:<QuerySet [<Author: zhang>, <Author: liu>]>,表示id=4 的书籍,有两个做者。
3.查询做者是zhang的手机号码
author_obj = models.Author.objects.filter(name='zhang').first() print(author_obj.author_detail) # AuthorDetail object print(author_obj.author_detail.phone)
总结:正向查询,当被查询出来的数据有多个的状况下,须要点.all();
ps:app01.Author.None,一旦看到该结果 只须要加.all()便可
反向查询
4.查询出版社是东方出版社出版过的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first() print(publish_obj.book_set) # app01.Book.None print(publish_obj.book_set.all())
5.查询做者是zhang写过的书籍
author_obj = models.Author.objects.filter(name='zhang').first() print(author_obj.book_set) # app01.Book.None print(author_obj.book_set.all()) # app01.Book.None
6.查询手机号是120的做者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=120).first() print(author_detail_obj.author) # Author object 不需类名小写+_set,直接做者详情对象点类名(Author)小写便可 print(author_detail_obj.author.email) # 120qq.com
基于双下滑线的联表查询操做,能让两张表组成一张表,使用一条django的orm语句就能查询出想要的信息,使操做更加简洁化。
1.查询书籍pk为2的出版社名称
# 方式1:正向查询 res = models.Book.objects.filter(pk=2).values('publish__name') print(res) # <QuerySet [{'publish__name': '东方出版社'}]> # 方式2:反向查询 res = models.Publish.objects.filter(book__pk=2).values('name') print(res) # <QuerySet [{'name': '北方出版社'}]>
2.查询书籍pk为2的做者姓名和邮箱
# 方式1:正向查询 res =models.Book.objects.filter(pk=2).values('authors__name','authors__email') print(res) # <QuerySet [{'authors__name': 'zhang', 'authors__email': '110@qq.com'}, {'authors__name': 'liu', 'authors__email': '120qq.com'}]> 不须要像上面基本方法的跨表查询,这里不须要用点.all() # 方式2:反向查询 res =models.Author.objects.filter(book__pk=2).values('name','email') print(res) # <QuerySet [{'name': 'zhang', 'email': '110@qq.com'}, {'name': 'liu', 'email': '120qq.com'}]>
总结: models后面点的谁 就以谁为基表
3.查询做者是zhang的家庭地址
# 方式1:正向查询 res=models.Author.objects.filter(name='egon').values('author_detail__addr') print(res) # 方式2:反向查询 res=models.AuthorDetail.objects.filter(author__name='liu').values('addr') print(res)
4.查询出版社是东方出版社出版过的书的名字
# 方式1:正向查询 res = models.Publish.objects.filter(name='东方出版社').values('book__title') print(res) # 方式2:反向查询 res = models.Book.objects.filter(publish__name='东方出版社').values('title') print(res)
5.查询书籍pk是2的做者的手机号
# 方式1:正向查询 res=models.Book.objects.filter(pk=2).values('authors__author_detail__phone') print(res) # 方式2:反向查询 res=models.Author.objects.filter(book__pk=2).values('author_detail__phone') print(res)
1.关键字 aggregate
2.还须要导入模块
from django.db.models import Max, Min, Sum, Avg, Count
from django.db.models import Max, Min, Sum, Count, Avg # 1.筛选出价格最高的书籍的 res = models.Book.objects.aggregate(mr = Max('price')) print(res) # {'mr': Decimal('222.99')} # 2.求书籍总价格 res = models.Book.objects.aggregate(sm = Sum('price')) print(res) # {'sm': Decimal('600.58')} # 3.求书籍平均价格 res = models.Book.objects.aggregate(av = Avg('price')) print(res) # {'av': 150.145} # 4.一块儿使用 res=models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('price'),Avg('price')) print(res) ''' {'price__max': Decimal('222.99'), 'price__min': Decimal('88.80'), 'price__sum': Decimal('600.58'), 'price__count': 4, 'price__avg': 150.145} '''
1.关键字 annotate
2.借助于聚合函数
from django.db.models import Max, Min, Sum, Avg, Count
1).分组查询annotate()至关于sql语句中的group by,是在分组后,对每一个组进行单独的聚合,须要强调的是,在进行单表查询时,annotate()必须搭配values()使用:values("分组字段").annotate(聚合函数)
每一个部门下的员工数 res=Employee.objects.values('department').annotate(num=Count('id')) # 至关于sql: # select department,count(id) as num from app01_employee group by department; print(res) # 输出:<QuerySet [{'department': '财务部', 'num': 2}, {'department': '技术部', 'num': 3}, {'department': '运营部', 'num': 2}]>
2).跟在annotate前的values方法,是用来指定分组字段,即group by后的字段,而跟在annotate后的values方法,则是用来指定分组后要查询的字段,即select 后跟的字段
res=Employee.objects.values('department').annotate(num=Count('id')).values('num') # 至关于sql: # select count(id) as num from app01_employee group by department; print(res) # 输出:<QuerySet [{'num': 2}, {'num': 3}, {'num': 2}]>
3).跟在annotate前的filter方法表示where条件,跟在annotate后的filter方法表示having条件,以下:
# 查询男员工数超过2人的部门名 res=Employee.objects.filter(gender=1).values('department').annotate(male_count=Count("id")).filter(male_count__gt=2).values('department') print(res) # 输出:<QuerySet [{'department': '技术部'}]> # 解析: # 一、跟在annotate前的filter(gender=1) 至关于 where gender = 1,先过滤出全部男员工信息 # 二、values('department').annotate(male_count=Count("id")) 至关于group by department,对过滤出的男员工按照部门分组,而后聚合出每一个部门内的男员工数赋值给字段male_count # 三、跟在annotate后的filter(male_count__gt=2) 至关于 having male_count > 2,会过滤出男员工数超过2人的部门 # 四、最后的values('department')表明从最终的结果中只取部门名
总结:
一、values()在annotate()前表示group by的字段,在后表示取值 一、filter()在annotate()前表示where条件,在后表示having
须要注意的是,若是咱们在annotate前没有指定values(),那默认用表中的id字段做为分组依据,而id各不相同,如此分组是没有意义的。
1.统计每一本书的做者个数 书名 和对应的做者人数
res=models.Book.objects.annotate(author_num=Count('authors__id')).values('title','author_num') print(res)
2.统计出每一个出版社卖的最便宜的书的价格 出版社的名字 价格
res=models.Publish.objects.annotate(min_price=Min('book__price')).values('name','min_price') print(res)
3.统计不止一个做者的图书
res=models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1).values('title','author_num') print(res)
4.查询各个做者出的书的总价格 做者名字 总价格
res=models.Author.objects.annotate(sum_price=Sum('book__price')).values('name','sum_price') print(res)
F查询
可以帮你拿到表中字段所对应的数据
eg:查询卖出数大于库存数的书籍
from django.db.models import F,Q res = models.Book.objects.filter(kun_cun__gt = F('mai_cun')).values('title') # 后面的条件是来自于数据库的其余字段值 print(res) # <QuerySet [{'title': '天龙八部'}]>
2.将全部书的价格上涨100块
models.Book.objects.all().update(price=F('price') + 100)
3.将全部书的名称后面所有加上 "爆款" 后缀
from django.db.models.functions import Concat from django.db.models import Value ret3 = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
Q查询
filter只能按照and的关系查询数据,而Q查询可以支持修改多个查询条件的关系(and or not)
1.查询一下书籍名称是三国演义 或者 库存数是500的书籍
from django.db.models import Q res = models.Book.objects.filter(title='三国演义',kun_cun=500) # and关系 res = models.Book.objects.filter(title='三国演义',kun_cun=500) # and关系 res = models.Book.objects.filter(Q(title='三国演义'),Q(kun_cun=500))# Q包裹以后逗号仍是and关系 res = models.Book.objects.filter(Q(title='三国演义') | Q(kun_cun=500)) # |就是or的关系 res = models.Book.objects.filter(~Q(title='三国演义')|Q(kun_cun=500)) # ~就是not关系 print(res)
Q对象高级用法
q = Q() q.connector = 'or' # 默认是and 能够改为or q.children.append(('title','三国演义')) q.children.append(('kun_cun__gt',500)) res = models.Book.objects.filter(~q) # 取反 print(res) from django.db import transaction with transaction.atomic(): # 在缩进的代码中书写数据库操做 # 该缩进内的全部代码 都是一个事务 pass
orm字段及参数 CharField varchar IntegerField int BigIntegerField bigint EmailField varchar(254) DateField DateTimeField auto_now:每次修改数据的时候 都会自动将当前修改时间更新上去 实时更新 auto_now_add:在建立数据的时候 会将当前时间自动记录 以后不会自动修改 除非你人为修改 AutoField auto_increment BooleanField 布尔值 该字段在存储的时候 你只须要传布尔值True或False 它会自动存成1/0 TextField 专门用来存大段文本 FileField 专门用来文件路径 '/etc/data/a.txt' upload_to = '/etc/data' 给该字段传值的时候 直接传文件对象 会自动将文件对象保存到upload_to后面指定的文件路径中 而后将路径保存到数据库 DecimalField(Field) - 10进制小数 - 参数: max_digits,小数总长度 decimal_places,小数位长度
from django.db import models # Create your models here. #Django中没有对应的char类型字段,可是咱们能够本身建立 class FixCharField(models.Field): ''' 自定义的char类型的字段类 ''' def __init__(self,max_length,*args,**kwargs): self.max_length=max_length # # 从新调用父类的方法 super().__init__(max_length=max_length,*args,**kwargs) def db_type(self, connection): ''' 限定生成的数据库表字段类型char,长度为max_length指定的值 :param connection: :return: ''' return 'char(%s)'%self.max_length #应用上面自定义的char类型 class Class(models.Model): id=models.AutoField(primary_key=True) title=models.CharField(max_length=32) class_name=FixCharField(max_length=16) gender_choice=((1,'男'),(2,'女'),(3,'保密')) gender=models.SmallIntegerField(choices=gender_choice,default=3)