Django框架-模型层

一、单表查询之必知必会13条

1、时间字段中的两个关键性参数

create_time = models.DateField()  # 年月日
create_time = models.DateTimeField() # 年月日时分秒
# 两个关键性参数
# auto_now:每次操作数据 都会自动刷新当前操作的时间
# auto_now_add:在创建数据的时候 会自动将创建时间记录下来 后续的修改不会影响该字段

2、搭建测试环境

在django中,你可以写一个单独测试某一个py文件的测试脚本,不需要再频繁的走web请求

搭建步骤:

  • 新建一个py文件,或者直接使用app下面的test.py文件
  • 从manage.py中复制三行代码到test.py内
import os

if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "day54.settings")
# 上面是从manage.py中复制过来的
import django
django.setup()
# 再写这两行代码,测试环境就搭建好了

3、单表的增删改查

  • models.py中写入以下代码
from django.db import models

# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=8,decimal_places=2)
create_time = models.DateField() # 年月日
# create_time = models.DateTimeField() # 年月日 时分秒 def __str__(self):
return self.title
# 方式1: create
book_obj = models.Book.objects.create(title='三国',price=19.99,create_time='2019-11-11') # 方式2:对象点save()方法
from datetime import datetime
ctime = datetime.now()
book_obj = models.Book(title='xxx',price=96.66,create_time=ctime)
book_obj.save()
print(models.Book.objects.all())
print(models.Book.objects.get(id=1))
print(models.Book.objects.get(pk=1))
"""
pk会自动查找到当前数据的主键字段
"""
print(models.Book.objects.filter(pk=2))
# get方法拿到的是Book对象,而all和filter拿到的是queryset对象
# 1.update方法
models.Book.objects.filter(pk=1).update(title='三国演义')
# 2.对象.save()
book_obj = models.Book.objects.get(pk=1)
book_obj.price = 666.66
book_obj.save()
# delete方法
models.Book.objects.filter(pk=2).delete()

4、必知必会13条

# < 1 > all(): 查询所有结果
# < 2 > filter(**kwargs): 它包含了与所给筛选条件相匹配的对象
# < 3 > get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。(源码就去搂一眼~诠释为何只能是一个对象)
# < 4 > exclude(**kwargs): 它包含了与所给筛选条件不匹配的对象
print(models.Book.objects.exclude(pk=1)) # 只要pk不是1的数据全部查询出来 # < 5 > order_by(*field): 对查询结果排序('-id') / ('price')
print(models.Book.objects.order_by('price')) # 默认是升序
print(models.Book.objects.order_by('-price')) # 加负号就是降序 # < 6 > reverse(): 对查询结果反向排序 >> > 前面要先有排序才能反向
print(models.Book.objects.order_by('price').reverse()) # < 7 > count(): 返回数据库中匹配查询(QuerySet)的对象数量。
print(models.Book.objects.count()) # 对查询出来的结果进行一个计数 # < 8 > first(): 返回第一条记录
print(models.Book.objects.filter(pk=1).first()) # < 9 > last(): 返回最后一条记录
print(models.Book.objects.all())
print(models.Book.objects.all().last()) # < 10 > exists(): 如果QuerySet包含数据,就返回True,否则返回False
print(models.Book.objects.filter(pk=1000))
print(models.Book.objects.filter(pk=1000).exists()) # < 11 > values(*field): 返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列model的实例化对象,而是一个可迭代的字典序列
print(models.Book.objects.values('title','price')) # 得到的结果是列表套字典 # < 12 > values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
print(models.Book.objects.values_list('title','price')) # 得到的结果是列表套元组 # < 13 > distinct(): 从返回结果中剔除重复纪录
"""
去重的前提是 一定要有完全重复的数据 才能去重
"""
print(models.Book.objects.filter(title='三国演义').distinct()) # 无效的去重
print(models.Book.objects.values('title','price','create_time').distinct()) # 13个必会操作总结
# 返回QuerySet对象的方法有
all()
filter()
exclude()
order_by()
reverse()
distinct() # 特殊的QuerySet
values() # 返回一个可迭代的字典序列
values_list() # 返回一个可迭代的元祖序列 # 返回具体对象的
get()
first()
last() # 返回布尔值的方法有
exists() # 返回数字的方法有
count()

二、Django终端打印SQL语句

问题:查看orm内部sql语句的方法有哪些?

1、如果是queryset对象,那么可以点query直接查看该queryset的内部sql语句

2、在django项目的配置文件中,配置一下参数即可实现所有的orm在查询的时候自动打印对应的sql语句

# 配置代码
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console':{
'level':'DEBUG',
'class':'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'propagate': True,
'level':'DEBUG',
},
}
}

三、神奇的双下划线查询

# 查询价格大于200的书籍
res = models.Book.objects.filter(price__gt=200)
print(res)
# 查询价格小于200的书籍
res = models.Book.objects.filter(price__lt=200)
print(res) # 查询价格大于等于200.22的书籍
res = models.Book.objects.filter(price__gte=200.22)
print(res)
# 查询价格小于等于200.22的书籍
res = models.Book.objects.filter(price__lte=200.22)
print(res) # 查询价格要么是200,要么是300,要么是666.66
res = models.Book.objects.filter(price__in=[200,300,666.66])
print(res)
# 查询价格在200到800之间的
res = models.Book.objects.filter(price__range=(200,800)) # 两边都包含
print(res) # 查询书籍名字中包含p的
"""原生sql语句 模糊匹配
like
% 多个字符
_ 单个字符
"""
res = models.Book.objects.filter(title__contains='p') # 仅仅只能拿小写p
res = models.Book.objects.filter(title__icontains='p') # 忽略大小写
print(res) # 查询书籍是以三开头的
res = models.Book.objects.filter(title__startswith='三')
res1 = models.Book.objects.filter(title__endswith='p')
print(res)
print(res1) # 查询出版日期是2017的年(******)
res = models.Book.objects.filter(create_time__year='2017')
print(res)
# 还可以查月和日(month day)

四、图书管理系统表创建

1、表关系:

  • 一对多ForeignKey

  • 一对一OneToOneField,可以用ForeignKey代替:ForeignKey(unique=True)

    上面两个关键字创建出来的字段会自动加上_id后缀

  • 多对多ManyToManyField

    该字段并不会真正在表中展示出来,他仅仅是一个虚拟字段,他有两个功能,一是告诉orm自动创建第三张表,二是帮助orm跨表查询

2、建表

  • 新建数据库

  • Django默认的数据库改为MySQL

    修改配置文件

    __init__文件中导入pymysql模块

  • models文件中创建模型表

from django.db import models

# Create your models here.
class Book(models.Model):
title = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8,decimal_places=2)
publish_date = models.DateField(auto_now_add=True)
# 库存数
kucun = models.IntegerField(null=True)
# 卖出数
maichu = models.IntegerField(null=True)
publish = models.ForeignKey(to='Publish') # 默认是跟publish的主键字段做的一对多外键关联
authors = models.ManyToManyField(to='Author')
# 虚拟字段 1.自动创建第三张表 2.帮助orm跨表查询
def __str__(self):
return self.title class Publish(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
# email = models.EmailField() # 就是varchar(254)
def __str__(self):
return self.name class Author(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
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)
"""
models.py中的模型类__str__方法 必须返回一个字符串形式数据!!!
"""
def __str__(self):
return self.addr

注意点:

  • CharField必须指定最大长度
  • DecimalField可以指定最大长度以及小数部分的长度
  • DateField设置auto_now_add=True时只会记录记录创建时的时间,之后就不会改变
  • EmailField在数据库中就是varchar类型
  • publish = models.ForeignKey(to='Publish') 默认是跟Publish表的主键字段做的一对多外键关联
  • authors = models.ManyToManyField(to='Author') 数据库中并不会产生这个字段
  • author_detail = models.OneToOneField(to='AuthorDetail')一对一字段一般建在查询频率比较高的表中

3、同步到数据库

# run manage.py by task中
makemigrations
migrate # 终端中
python3 manage.py makemigrations
python3 manage.py migrate

​ 有四张表使我们建的,但app01_book_authors这张表是Djangoorm帮我们建的,是用来存储数据表和作者表的多对多表关系的。

4、手动录入测试数据,到了公司,运维那会有测试库

五、一对多字段的增删改

1、增,两种方式

# publish_id传数字
models.Book.objects.create(title='三国演义',price=189.99,publish_id=1) # publish直接传出版社对象
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.create(title='红楼梦',price=999.99,publish=publish_obj) # pubilsh_id字段是数据库中数据存在的字段
# publish字段是建表时的关联字段

2、改,两种方式

# 传数字的
models.Book.objects.filter(pk=1).update(publish_id=3) # 传对象的
publish_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=publish_obj)

3、删

models.Publish.objects.filter(pk=2).delete()  # 默认都是级联更新 级联删除
# 会将Publish表中的id=2和Book表中的publish_id=2所对应的所有数据全部删除

六、多对多字段的增删改

1、增

# 要给主键为1的书籍添加作者
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors) # 对象点击多对多虚拟字段 会直接跨到多对多的第三张表
book_obj.authors.add(1)
book_obj.authors.add(2,3) # 可以传多个数字 author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.add(author_obj)
book_obj.authors.add(author_obj1,author_obj2) # 可以传对象,并且可以传多个
# add(),是给书籍添加作者,括号内既可以传数字也可以传对象,并且支持一次性传多个,逗号隔开即可

2、改

# 将主键为1的书籍对象 作者修改为2,3
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.set([2,]) # 必须传一个可迭代对象
book_obj.authors.set([2,3]) author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj,])
book_obj.authors.set([author_obj, author_obj1, author_obj2])
# 将不要的删掉,要的留下来,没有的新增
# set()括号内,需要传一个可迭代对象,可以是多个数字组合,也可以是多个对象组合,但是不要混着用!!!

3、删,remove和clear

# remove()括号内既可以传数字,也可以传对象,并且支持传多个,逗号隔开即可
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.remove(3)
book_obj.authors.remove(1,2) author_obj = models.Author.objects.filter(pk=1).first()
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj)
book_obj.authors.remove(author_obj1,author_obj2)
# clear() 将某本书跟作者的关系全部清空
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.authors.clear() # 清空当前书籍与作者的所有关系,不需要传参数

七、基于对象的正反向查询

1、正向与反向的概念

    # 一对一
# 正向:author---关联字段在author表里--->authordetail 按字段
# 反向:authordetail---关联字段在author表里--->author 按表名小写 # 一对多
# 正向:book---关联字段在book表里--->publish 按字段
# 反向:publish---关联字段在book表里--->book 按表名小写_set.all() 因为一个出版社对应着多个图书 # 多对多
# 正向:book---关联字段在book表里--->author 按字段
# 反向:author---关联字段在book表里--->book 按表名小写_set.all() 因为一个作者对应着多个图书

查询技巧:正向查询按外键字段,反向查询按表名小写

2、基于对象的跨表查询(子查询:将一张表的查询结果当做另外一个查询语句的条件)

# 1.查询书籍id是1 的出版社名称
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.publish) # 拿到的是一个publish对象
print(book_obj.publish.name)
print(book_obj.publish.addr) # 2.查询书籍id是2的作者姓名
book_obj = models.Book.objects.filter(pk=2).first()
print(book_obj.authors) # app01.Author.None
# 当遇到这种查询结果时,说明我们的查询方式并没有错,但还差一点点
# 这里是因为书籍与作者是多对多关系,所以一本书查到的作者可能有多个,所以要利用all拿出来
print(book_obj.authors.all())
res = book_obj.authors.all()
for r in res:
print(r.name) # 3.查询作者是jason的家庭住址
author_obj = models.Author.objects.filter(name='jason').first()
print(author_obj.author_detail.addr) # 4.查询出版社是东方出版社出版的书籍
publish_obj = models.Publish.objects.filter(name='东方出版社').first()
# 由出版社查书,反向查询,按表名小写book
print(publish_obj.book)
# 上面的查询方式是会报错的,说publish对象没有book属性,必须要加_set
print(publish_obj.book_set) # app01.Book.None
# 标志性的结果,说明缺少all
print(publish_obj.book_set.all()) # 5.查询作者是jason的写过的所有的书籍
author_obj = models.Author.objects.filter(name='jason').first()
# 由作者查书,反向查询,同理
print(author_obj.book_set) # app01.Book.None
print(author_obj.book_set.all()) # 6.查询电话号码是130的作者姓名
author_detail_obj = models.AuthorDetail.objects.filter(phone=130).first()
# 由作者详情查作者,反向查询,但是这里不需要加_set
print(author_detail_obj.author.name)
print(author_detail_obj.author.age)
"""
总结:当你反向查询的结果是多个的时候,就需要加_set,否则直接表明小写即可
"""
# 7.查询书籍id为1 的作者的电话号码
book_obj = models.Book.objects.filter(pk=1).first()
# 正向查询,查多个
author_list = book_obj.authors.all()
for author_obj in author_list:
print(author_obj.author_detail.phone)

3、基于双下划线的跨表查询(连表操作)

1、SQL语句中的连表操作:inner join,left join,right join,union

2、查询

# 1.查询jason作者的手机号
# 正向
res = models.Author.objects.filter(name='jason').values('author_detail__phone','author_detail__addr')
print(res)
# 反向
res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone')
print(res1) # 查询jason这个作者的年龄和手机号
# 正向
res = models.Author.objects.filter(name='jason').values('age','author_detail__phone')
print(res)
# 反向
res1 = models.AuthorDetail.objects.filter(author__name='jason').values('phone','author__age')
print(res1) # 查询手机号是130的作者年龄
# 正向
res = models.AuthorDetail.objects.filter(phone=130).values('author__age')
print(res)
# # 反向
res1 = models.Author.objects.filter(author_detail__phone=130).values('age')
print(res1) # 查询书籍id是1 的作者的电话号码
res = models.Book.objects.filter(pk=1).values('authors__author_detail__phone')
#res1 = models.Book.objects.filter(pk=1).values('外键字段1__外键字段2__外键字段3__普通字段')
print(res)
"""只要表里面有外键字段 你就可以无限制跨多张表""" # 查询出版社为北方出版社的所有图书的名字和价格
res = models.Publish.objects.filter(name='北方出版社').values('book__title','book__price')
print(res) # 查询北方出版社出版的价格大于19的书
res = models.Book.objects.filter(price__gt=19,publish__name='北方出版社').values('title','publish__name')
print(res)

八、聚合查询与分组查询

1、MySQL中的聚合函数:Sum,Max,Min,Avg,Count

2、聚合查询,aggregate

res = models.Book.objects.aggregate(s = Sum('price'))  # 起别名
res1 = models.Book.objects.aggregate(Avg('price'))
res2 = models.Book.objects.aggregate(Count('price'))
res3 = models.Book.objects.aggregate(Max('price'))
res4 = models.Book.objects.aggregate(Min('price'))
res5 = models.Book.objects.aggregate(Max('price'),Min('price'),Count('pk'),Avg('price'),Sum('price')) # 可以写多个

3、分组查询,annotate

# 统计每一本书的作者个数
from django.db.models import Max, Min, Count, Avg, Sum
res = models.Book.objects.annotate(author_num = Count('authors')).values('author_num','title')
print(res) # 统计出每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(mmp = Min('book__price')).values('name','mmp')
print(res) # 统计不止一个作者的图书
res = models.Book.objects.annotate(author_num=Count('authors')).filter(author_num__gt=1)
print(res)
"""
只要是queryset对象,就可以无限制的调用queryset对象的方法!!!
最最常用的就是对一个已经filter过滤完的数据,再进行更细化的筛选
"""

九、F与Q查询

1、F查询,之前查询等号后面的条件都是我们人为输入的,现在变成了需要从数据库中获取数据放在等号后面,F查询的本质就是从数据库中获取某个字段的值。

# 查询库存数大于卖出数的书籍
from django.db.models import F
res = models.Book.objects.filter(kucun__gt=F('maichu'))
print(res) # 将书籍库存数全部增加1000
models.Book.objects.update(kucun=F('kucun')+1000) # 把所有书名后面加上'新款'
from django.db.models.functions import Concat
from django.db.models import Value res = models.Book.objects.update(title=Concat(F('title'), Value('新款')))
models.Book.objects.update(title = F('title')+'新款') # 不能这么写

2、Q查询

from django.db.models import Q
# 查询书籍名称是三国演义或者价格是444.44
res = models.Book.objects.filter(title='三国演义',price=444.44) # filter只支持and关系
res1 = models.Book.objects.filter(Q(title='三国演义'),Q(price=444)) # 如果用逗号 那么还是and关系
res2 = models.Book.objects.filter(Q(title='三国演义')|Q(price=444)) # |表示or关系
res3 = models.Book.objects.filter(~Q(title='三国演义')|Q(price=444)) # ~表示not关系 # Q高级用法
q = Q() # Q是一个类,现实例化一个对象
q.connector = 'or' # 修改查询条件的关系 默认是and
q.children.append(('title__contains','三国演义')) # 以元组的形式往列表中添加筛选条件,q.children可以看做是一个列表
q.children.append(('price__gt',444)) # 往列表中添加筛选条件
res = models.Book.objects.filter(q) # filter支持你直接传q对象 但是默认还是and关系
print(res)

Django框架-模型层的更多相关文章

  1. Django框架-模型层3/数据传输/Ajax

    目录 一.orm查询优化 1.only与defer 2.select_related与prefatch_related 二.模型层choices参数 三.MTV与MVC模型 1.MVC 2.MTV 3 ...

  2. 【Django】模型层说明

    [Django模型层] 之前大概介绍Django的文章居然写了两篇..这篇是重点关注了Django的模型层来进行学习. ■ 模型定义 众所周知,Django中的模型定义就是定义一个类,其基本结构是这样 ...

  3. python 全栈开发,Day70(模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介)

    昨日内容回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...

  4. Django基础(2)--模板自定义标签和过滤器,模板继承 (extend),Django的模型层-ORM简介

    没整理完 昨日回顾: 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 ...

  5. Django之模型层:表操作

    目录 Django之模型层:表操作 一.ORM简介 django测试环境搭建 Django终端打印SQL语句 二 单表操作 2.1 按步骤创建表 2.2记录 三.多表操作 1 创建模型 2 添加.删除 ...

  6. Django模板自定义标签和过滤器,模板继承(extend),Django的模型层

    上回精彩回顾 视图函数: request对象 request.path 请求路径 request.GET GET请求数据 QueryDict {} request.POST POST请求数据 Quer ...

  7. Django框架-路由层

    Django框架-路由层 一.URL配置(URLconf) 1.基本格式 from django.conf.urls import url urlpatterns = [ url(正则表达式, vie ...

  8. Django之模型层第一篇:单表操作

    Django之模型层第一篇:单表操作 一 ORM简介 ​ 我们在使用Django框架开发web应用的过程中,不可避免地会涉及到数据的管理操作(如增.删.改.查),而一旦谈到数据的管理操作,就需要用到数 ...

  9. 64、django之模型层(model)--建表、查询、删除基础

    要说一个项目最重要的部分是什么那铁定数据了,也就是数据库,这篇就开始带大家走进django关于模型层model的使用,model主要就是操纵数据库不使用sql语句的情况下完成数据库的增删改查.本篇仅带 ...

随机推荐

  1. 微信小程序判断input是否为空

    微信小程序中用到input值时候,判断其内容是否为空,可以用if-else判断内容的length,也可以给input加点击事件,判断其内容:以下是我解决问题的过程wxml代码 <view cla ...

  2. SSH、telnet配置以及它们之间区别

    命令: SSH ip domain-name www.baidu.com --配置主机名(用来远程访问) user privilege secret --配置账户名和密码 line vty --配置端 ...

  3. 记录 Docker 的学习过程 (安装基础篇)

    docker 通过内核来实现 特点是效率高 1. centos7 三台(推荐2c 4g 最低 1c1g)2. 关闭防火墙 selinux3. 做好主机名解析,三台能互相ping通主机名host参考文件 ...

  4. clone()与clone(true)的用法

    clone() 方法生成被选元素的副本,包含子节点.文本和属性. 使用 clone(true) 方法在clone()的基础上还包括克隆元素的事件处理器.

  5. (转)java 虚拟机内存划分

    深入理解java虚拟机(一):java内存区域(内存结构划分)深入理解java虚拟机(二):java内存溢出实战  深入理解java虚拟机(三):String.intern()-字符串常量池深入理解j ...

  6. Eclipse项目工程导入到IDEA继续开发-超详细

    现在Java开发的主流工具是IDEA,不是说Eclipse,各有各的特色.不过我现在深深的爱上了idea这个工具. 但是之前很多项目都是用eclipse开发的,现在就转入到idea中进行继续开发. 1 ...

  7. AntDesign(React)学习-10 Dva 与后台数据交互

    明天正式在线办公没时间学习了,今天晚上再更新一篇, 代码提交一次:https://github.com/zhaogaojian/jgdemo 1.src下创建services目录 创建文件userSr ...

  8. ARM(哈弗、冯氏结构、总线和IO访问、处理器状态和处理机模式)

    1.哈弗结构与冯氏结构 (1)区别: 是否有独立的存储架构和信号通道. (2)举例: 8086:冯氏结构(相同的存储相同的通道) STM32F103:哈弗结构(不同的存储.通道) 8051:改进的哈弗 ...

  9. 洛谷P1051 谁拿了最多奖学金

    https://www.luogu.org/problem/P1051 #include<bits/stdc++.h> using namespace std; struct node { ...

  10. (转)KMP算法

    转自:http://blog.csdn.net/yutianzuijin/article/details/11954939 我们首先用一个图来描述kmp算法的思想.在字符串O中寻找f,当匹配到位置i时 ...