1 Django基础一之web框架的本质
Django 、Flask 这些就是Python语言的web 框架。
1.1web框架的本质
Web应用本质上就是一个socket服务端,而用户的浏览器就是一个socket客户端。
1.1.1什么是 Web 服务器?
平时我们都是通过浏览器(比如Chrome,Firefox等)上网的,当我们在浏览器的地址栏里输入地址后,会得到一个网页。
这个网页就是 web 服务器返回给我们的,而浏览器就称为客户端,当我们输入网址并按下回车后,就像web服务器发送了一个web请求。
这种模式成为 B/S 模式 ,即 Browse / Server 模式
在浏览器中输入地址、按回车后,按下F12 就是看到如下信息
下面就让我们来目睹整个过程吧
- 建立连接:客户机通过TCP/IP协议建立到服务器的TCP连接。
- 请求过程:客户端向服务器发送HTTP协议请求包(Request),请求服务器里的资源文档。
- 应答过程:服务器向客户机发送HTTP协议应答包(Response),如果请求的资源包含有动态语言的内容,那么服务器会调用动态语言的解释引擎负责处理“动态内容”,并将处理得到的数据返回给客户端。由客户端解释HTML文档,在客户端屏幕上渲染图形结果。
- 关闭连接:客户机与服务器断开。
这里Request 和 Response 都需要遵守 HTTP 协议,关于 HTTP 协议的详细内容,可以读读《HTTP 权威指南》
但是实际中的 Web 服务器远远比上面示例的复杂的多,因为要考虑的因素实在是太多了,比如:
- 缓存机制:讲一些经常被访问的页面缓存起来,提高响应速度;
- 安全:防止黑客的各种攻击,比如 SYN Flood 攻击;
- 并发处理:如何响应不同客户端同时发起的请求;
- 日志:记录访问日至,方便做一些分析。
目前在UNIX和LINUX平台下使用最广泛的免费 Web 服务器有Apache和 Nginx 。而这些软件都是遵循遵守 HTTP 协议的。
所以可以称他们为HTTP服务器,只是可以通过HTTP协议语言的解析转换。
https://www.cnblogs.com/clschao/articles/9230431.html
1.1.2Web 应用程序?
Web 服务器接受 Http Request,返回 Response,很多时候 Response 并不是静态文件,因此需要有一个应用程序根据 Request 生成相应的 Response。这里的应用程序主要用来处理相关业务逻辑,读取或者更新数据库,根据不同 Request 返回相应的 Response。注意这里并不是 Web 服务器本身来做这件事,它只负责 Http 协议层面和一些诸如并发处理,安全,日志等相关的事情。
应用程序可以用各种语言编写(Java, PHP, Python, Ruby等),这个应用程序会从Web服务器接收客户端的请求,处理完成后,再返回响应给Web服务器,最后由Web服务器返回给客户端。整个架构如下:
对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
1.1.3Web 框架
框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演。
以 python web 框架 flask 为例,框架本身并不限定我们用哪种架构来组织我们的应用,不过其中一种比较经典的Web框架 Flask 采用了 MVC 架构,可以很好地支持以 MVC 方式组织应用。
- 用户输入 URL,客户端发送请求
控制器(Controller)
首先会拿到请求- 然后用
模型(Models)
从数据库取出所有需要的数据,进行必要的处理,将处理后的结果发送给视图(View)
- 视图利用获取到的数据,进行渲染生成 Html Response返回给客户端。
1.2基于socket自定义web框架
待定
1.3 模板渲染JinJa2
1.4MVC和MTV框架
1.4.1MVC
Web服务器开发领域里著名的MVC模式,所谓MVC就是把Web应用分为模型(M),控制器(C)和视图(V)三层,他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求,其示意图如下所示:
1.4.2MTV
Django的MTV模式本质上和MVC是一样的,也是为了各组件间保持松耦合关系,只是定义上有些许不同,Django的MTV分别是值:
- M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
- T 代表模板 (Template):负责如何把页面展示给用户(html)。
- V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
除了以上三层之外,还需要一个URL分发器,它的作用是将一个个URL的页面请求分发给不同的View处理,View再调用相应的Model和Template,MTV的响应模式如下所示:
一般是用户通过浏览器向我们的服务器发起一个请求(request),这个请求回去访问视图函数,(如果不涉及到数据调用,那么这个时候视图函数返回一个模板也就是一个网页给用户),视图函数调用模型,模型去数据库查找数据,然后逐级返回,视图函数把返回的数据填充到模板中空格中,最后返回网页给用户。
1.5 Django下载安装 创建项目应用
1.5.1Django下载安装
1.5.1.1 cmd下载
第一种 cmd 输入python 进入 python解释器
输入pip3 install django==1.11.9 pip国内的一些镜像 阿里云 http://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/ 豆瓣(douban) http://pypi.douban.com/simple/ 清华大学 https://pypi.tuna.tsinghua.edu.cn/simple/ 中国科学技术大学 http://pypi.mirrors.ustc.edu.cn/simple/ 临时使用: 可以在使用pip的时候在后面加上-i参数,指定pip源 修改源方法 pip3 install django==1.11.9 卸载djange pip uninstall django
1.5.1.2pycham下载
File | Settings | Project: un1 | Project Interpreter 添加django 勾选这个Specify version 选择历史版本
1.5.2创建djange项目
1.5.2.1pythcm创建
注意不要选择虚拟环境
1.5.2.2终端创建
创建项目 django-admin startproject mysite 创建了一个名为"mysite"的Django 项目 启动项目 启动项目 python manage.py runserver 默认是127.0.0.1:8000 python manage.py runserver 127.0.0.1 默认端口号是8000 python manage.py runserver 127.0.0.1:8001
当前目录下会生成mysite的工程,目录结构如下:(大家注意昂,pip下载下来的django你就理解成一个模块,而不是django项目,这个模块可以帮我们创建django项目)
- manage.py ----- Django项目里面的工具,通过它可以调用django shell和数据库,启动关闭项目与项目交互等,不管你将框架分了几个文件,必然有一个启动文件,其实他们本身就是一个文件。
- settings.py ---- 包含了项目的默认设置,包括数据库信息,调试标志以及其他一些工作的变量。
- urls.py ----- 负责把URL模式映射到应用程序。
- wsgi.py ---- runserver命令就使用wsgiref模块做简单的web server,后面会看到renserver命令,所有与socket相关的内容都在这个文件里面了,目前不需要关注它。
1.5.3创建应用
python manage.py startapp blog #通过执行manage.py文件来创建应用blog,执行这句话一定要注意,你应该在这个manage.py的文件所在目录下执行这句话,因为其他目录里面没有这个文件 python manage.py startapp blog2 #每个应用都有自己的目录,每个应用的目录下都有自己的views.py视图函数和models.py数据库操作相关的文件
我们现在只需要看其中两个文件
models.py :之前我们写的那个名为model的文件就是创建表用的,这个文件就是存放与该app(应用)相关的表结构的
views.py :存放与该app相关的视图函数的
1.6基于Django的简单小示例
第1步 先配置setting.py文件中的INSTALLED_APPS 第2步 配置urls.py文件 路径分发 第3步 配置视图,views.py 写自己的逻辑 返回html页面 还是重定向 等等 第4步 创建 对应的html页面 注意点 from表单 不添提交地址就是原地址 我们可以通过请求方式get\post 进行逻辑判断
1.6.1配置setting.py
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config',#添加app01的应用 ]
1.6.2配置配置url
from app01 import views urlpatterns = [#只做路径匹配 不分post还是get url(r'^admin/', admin.site.urls), url(r'^login/', views.login), url(r'^login/(\d+)/(\d+)/', views.articles), #articles/2019/9/ ] # 有名分组参数 url(r'^articles/(?P<month>\d+)/(?P<year>\d+)/', views.articles), #articles/2019/9/ #xx=2019 oo=9 关键字传参
1.6.3找到视图views.py写逻辑
request形参 对象 约定俗成 HttpResponse可以返回字符串 redirect重定向 from django.shortcuts import render,HttpResponse print(request.path) def login(request): if request.method == 'POST': name = request.POST.get('username') # 获取的是字符串用户输入的值 pwd = request.POST.get('pwd') # print(name,pwd,'----------------------') if name == 'aa' and pwd == 'aa': return render(request, 'login2.html') else: return HttpResponse('登录失败!!') else: return render(request, 'login.html')#模板渲染 模板就是html页面 渲染就是字符串替换 第一个参数:request 第二个参数是html页面路径, from django.shortcuts import render,HttpResponse,redirect from django.urls import reverse def home(request): return redirect(reverse('cs1'))
1.6.4创建login.html
如果action里面不写还是原页面 我们可以设置method进行逻辑判断 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <form action="" method="post"> <!-- http://127.0.0.1:8000 /login/ /login2/--> 用户名:<input type="text" name="username"> <!-- http://127.0.0.1:8000/login/login2/ --> 密码:<input type="text" name="pwd"> <input type="submit"> </form> </body> {#<script src="jquery.js"></script>#} </html>
2 Django基础二之URL路由系统
2.1HTTP协议
详细https://www.cnblogs.com/clschao/articles/9230431.html
http协议 请求信息格式 GET / HTTP/1.1 请求行 Host: 127.0.0.1:8003 请求头 Connection: keep-alive Cache-Control: max-age=0 Upgrade-Insecure-Requests: 1 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3 Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 #空行 请求数据 username=ziwen password=666 get请求 请求数据部分是没有数据的,get请求的数据在url上,在请求行里面,有大小限制,常见的get请求方式: 浏览器输入网址,a标签 post请求 请求数据在请求体(请求数据部分) ,数据没有大小限制, 常见方式:form表单提交数据
2.2MVC和MTV框架模式
MVC: M -- models 数据库相关 V -- views 视图相关(逻辑) C -- controller url控制器(url分发器,路由分发) django -- MTV M -- models 数据库相关 T -- templates HTML相关 html就是模板 V -- views 视图相关(逻辑) + controller url控制器(url分发器,路由分发)
django下载安装
下载 pip3 install django==1.11.9 pip3 install django==1.11.9 -i http://xxxxxx 指定源 创建项目 django-admin startproject mysite 创建了一个名为"mysite"的Django 项目 启动项目 python manage.py runserver 默认是127.0.0.1:8000 python manage.py runserver 127.0.0.1 默认端口号是8000 python manage.py runserver 127.0.0.1:8001
2.3django的url路由分发
# url(r'^articles/(\d+)/(\d+)/', views.articles), #articles/2019/9/ 视图函数 def articles(request,year,month): # 位置参数 2019 9 print(year,type(year)) #2019 <class 'str'> #匹配出来的所有数据都是字符串 print(month) return HttpResponse(year+'年'+ month +'月' +'所有文章') # 有名分组参数 url(r'^articles/(?P<xx>\d+)/(?P<oo>\d+)/', views.articles), #articles/2019/9/ #xx=2019 oo=9 关键字传参 def articles(request,oo,xx): # 关键字传参 2019 9 print(xx,type(xx)) #2019 <class 'str'> #匹配出来的所有数据都是字符串 print(oo) return HttpResponse(xx+'年'+ oo +'月' +'所有文章')
3 Django基础三之视图函数
3.1视图
一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。
响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。
无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了
HTTPRequest对象就是咱们的视图函数的参数request
# print(request) #<WSGIRequest: GET '/home/'> # # print(dir(request)) # # print(request.path) #/home/ 纯路径 # print(request.path_info) #/home/ 纯路径 # print(request.get_full_path()) #/home/?a=1&b=2 全路径(不包含ip地址和端口) # print(request.META) #请求头相关数据,是一个字典 # print(request.method) #GET # print(request.GET) # print(request.POST) # print(request.body) 能够拿到请求数据部分的数据(post,get没有)
HTTPResponse对象
HTTPResponse('字符串') render(request,'xx.html') redirect 重定向#用法 redirect(路径) 示例:redirect('/index/')
3.2FBV和CBV 视图
3.2.1FBV(函数类)
FBV(function base views) 就是在视图里使用函数处理请求。
from django.shortcuts import render,HttpResponse,redirect def cs(request): return redirect('/cs1/') #重定向 redirect(路径)
3.2.2CBV(对象)
CBV(class base views) 就是在视图里使用类处理请求。
最后一步源码
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] def dispatch(self, request, *args, **kwargs): # Try to dispatch to the right method; if a method doesn't exist, # defer to the error handler. Also defer to the error handler if the # request method isn't on the approved list. if request.method.lower() in self.http_method_names:#实现分发的 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
通过剖析源码 我们可以在分发前执行我们的逻辑
from django.views import View class LoginView(View): # def dispatch(self, request, *args, **kwargs): # print('xx请求来啦!!!!')请求来之前 但不知道是什么方法前执行 # ret = super().dispatch(request, *args, **kwargs) # print('请求处理的逻辑已经结束啦!!!') # return ret def get(self,request): #处理get请求直接定义get方法,不需要自己判断请求方法了,源码中用dispatch方法中使用了反射来处理的 print('小小小小') return render(request,'login.html') def post(self,request): print(request.POST) return HttpResponse('登录成功')
urls.py路由写法
url(r'^login/', views.LoginView.as_view()),
3.3视图类 加装饰器
3.3.1装饰器装饰FBV
FBV本身就是一个函数,所以和给普通的函数加装饰器无差
def wrapper(func): def inner(*args, **kwargs): start_time = time.time() ret = func(*args, **kwargs) end_time = time.time() print("used:", end_time-start_time) return ret return inner # FBV版添加班级 @wrapper def add_class(request): if request.method == "POST": class_name = request.POST.get("class_name") models.Classes.objects.create(name=class_name) return redirect("/class_list/") return render(request, "add_class.html")
3.3.2装饰器装饰CBV
类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其转换为方法装饰器。Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。
第一步先引入模块from django.utils.decorators import method_decorator` 第2步 加语法糖@method_decorator(wrapper)` from django.shortcuts import render,HttpResponse from django.views import View from django.utils.decorators import method_decorator def wrapper(func): def inner(*args, **kwargs): print(11111) ret = func(*args, **kwargs) print(22222) return ret return inner # @method_decorator(wrapper,name='get') # 方式3给get加 用的不多 class LoginView(View): @method_decorator(wrapper) #方式1 def get(self,request): print('小小小小') return HttpResponse('登录成功') def post(self,request): print(request.POST) return HttpResponse('登录成功')
3.4request对象
Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
请求相关的常用值
- path_info 返回用户访问url,不包括域名
- method 请求中使用的HTTP方法的字符串表示,全大写表示。
- GET 包含所有HTTP GET参数的类字典对象
- POST 包含所有HTTP POST参数的类字典对象
- body 请求体,byte类型 request.POST的数据就是从body里面提取到的
属性
当get请求输入网址http://127.0.0.1:8000/cs/??a=1&b=2
def cs(request): print(request) #<WSGIRequest: GET '/cs/??a=1&b=2'> print(request.path) #/cs/ 纯路径 print(request.path_info) #/cs/ 纯路径 print(request.get_full_path())#/cs/??a=1&b=2全路径 (不包含ip地址和端口) print(request.META) #请求头相关数据,是一个字典 print(request.method) #GET print(request.GET)#<QueryDict: {'?a': ['1'], 'b': ['2']}> print(request.POST)#<QueryDict: {}> print(request.body) #能够拿到请求数据部分的数据(post,get没有) b'' return HttpResponse('666')
输入网址http://127.0.0.1:8000/cs/
def cs(request): print(request) #<WSGIRequest: GET '/cs/??a=1&b=2'> print(request.path) #/cs/ 纯路径 print(request.path_info) #/cs/ 纯路径 print(request.get_full_path())#/cs/??a=1&b=2全路径 (不包含ip地址和端口) print(request.META) #请求头相关数据,是一个字典 print(request.method) #POST print(request.GET)#<QueryDict: {}> print(request.POST)#<QueryDict: {'a': ['1'], 'b': ['2']}> print(request.body) # b'a=1&b=2' 能够拿到请求数据部分的数据(post,get没有) return render(request,'cs.html')
a框输入1 b框输入2
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="" method="post"> a<input type="text" name="a"> b<input type="text" name="b"> <input type="submit"> </form> </body> </html>
3.5Response对象
from django.shortcuts import render,HttpResponse,redirect HTTPResponse('字符串') #返回字符串 render(request,'xx.html')#返回html页面 redirect 重定向 def cs(request): return redirect('/cs1/') #重定向 redirect(路径) def cs1(request): return HttpResponse('666')
4 Django基础四之模板系统
4.1模板渲染的语法
模板渲染的官方文档
关于模板渲染你只需要记两种特殊符号(语法):
{{ }}和 {% %}
变量相关的用{{}},逻辑相关的用{%%}。
{{ 变量 }} {% 逻辑 %} -- 标签
4.2变量
在Django的模板语言中按此语法使用:{{ 变量名 }}。
当模版引擎遇到一个变量,它将计算这个变量,然后用结果替换掉它本身。 变量的命名包括任何字母数字以及下划线 ("_")的组合。 变量名称中不能有空格或标点符号。
我们可以利用 深度查询据点符(.)进行查询
4.2.1万能的点获取值
views.py视图函数中写法
from django.shortcuts import render def home(request): import datetime current_time = datetime.datetime.now() name = '小白' num = 101 d1 = {'xx':'oo','xx2':'oo2','xx3':[11,22,33]} d2 = ['11','22','33'] d3 = [] l1 = ['李业','陈硕','王洋','海狗'] class Person: n = '类的属性' def p(self): return '类p的返回值' obj = Person() return render(request,'home.html',{'name':name,'d1':d1})
HTML页面写法
注意字典 列表 和对象中方法 <h2>{{ name }}</h2> <h2>{{ d1.items }}</h2>items keys vlues <h2>我是"{{ l1.1 }}"</h2> <h2>{{ num }}</h2> <h2>{{ obj.p }}</h2> #如果调用的方法需要传参,sorry用不了
4.3过滤器(内置)
过滤器的语法: {{ value|filter_name:参数 }}
使用管道符"|"来应用过滤器。
注意事项:
过滤器支持“链式”操作。即一个过滤器的输出作为另一个过滤器的输入。
过滤器可以接受参数,例如:{{ sss|truncatewords:30 }},这将显示sss的前30个词。
过滤器参数包含空格的话,必须用引号包裹起来。比如使用逗号和空格去连接一个列表中的元素,如:{{ list|join:', ' }}
'|'左右没有空格没有空格没有空格
参考博客:https://www.cnblogs.com/clschao/articles/10414811.html default 如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。 {{ value|default:"nothing"}} 如果value没有传值或者值为空的话就显示nothing length返回值的长度,作用于字符串和列表。 {{ value|length }} 返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4. filesizeformat将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。 {{ value|filesizeformat }} 如果 value 是 123456789,输出将会是 117.7 MB。 slice 切片,如果 value="hello world",还有其他可切片的数据类型 {{value|slice:"2:-1"}} date格式化, value=datetime.datetime.now() {{ value|date:"Y-m-d H:i:s"}} 关于时间日期的可用的参数(除了Y,m,d等等)还有很多,有兴趣的可以去查查看看。 safe {{ value|safe}} 如果value = "<a href='#'>点我</a>" 那么页面显示的是a标签 truncatechars如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。 {{ value|truncatechars:9}} #注意:最后那三个省略号也是9个字符里面的,也就是这个9截断出来的是6个字符+3个省略号,有人会说,怎么展开啊,配合前端的点击事件就行啦 truncatewords在一定数量的字后截断字符串,是截多少个单词。 例如:‘hello girl hi baby yue ma’, {{ value|truncatewords:3}} #上面例子得到的结果是 'hello girl h1...' cut移除value中所有的与给出的变量相同的字符串 {{ value|cut:' ' }} 如果value为'i love you',那么将输出'iloveyou'. join使用字符串连接列表,{{ list|join:', ' }},就像Python的str.join(list)
4.4标签Tags
标签看起来像是这样的: {% tag %}
。标签比变量更加复杂:
格式 {% tag %}
标签 内容 ... {% endtag %}
4.4.1for标签
{% for person in person_list %} <p>{{ person.name }}</p> <!--凡是变量都要用两个大括号括起来--> {% endfor %}
反向循环
{% for obj in list reversed %}
遍历一个字典:
{% for key,val in dic.items %} <p>{{ key }}:{{ val }}</p> {% endfor %}
forloop
forloop.counter 当前循环的索引值(从1开始),forloop是循环器,通过点来使用功能 forloop.counter0 当前循环的索引值(从0开始) forloop.revcounter 当前循环的倒序索引值(从1开始) forloop.revcounter0 当前循环的倒序索引值(从0开始) forloop.first 当前循环是不是第一次循环(布尔值) forloop.last 当前循环是不是最后一次循环(布尔值) forloop.parentloop 本层循环的外层循环的对象,再通过上面的几个属性来显示外层循环的计数等 实列 {% for i in d2 %} {% for k,v in d1.items %} <li>{{ forloop.counter }}-- {{ forloop.parentloop.counter }} === {{ k }} -- {{ v }}</li> {% endfor %} {% endfor %}
4.4.2for ... empty
for
标签带有一个可选的{% empty %}
从句,以便在给出的组是空的或者没有被找到时,可以有所操作。
{% for person in person_list %} <p>{{ person.name }}</p> {% empty %} <p>sorry,no person here</p> {% endfor %}
4.4.3if 标签
{% if %}
会对一个变量求值,如果它的值是“True”(存在、不为空、且不是boolean类型的false值),对应的内容块会输出。
{% if num > 100 or num < 0 %} <p>无效</p> <!--不满足条件,不会生成这个标签--> {% elif num > 80 and num < 100 %} <p>优秀</p> {% else %} <!--也是在if标签结构里面的--> <p>凑活吧</p> {% endif %} if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。
4.4.4with
多用于给一个复杂的变量起别名,当你需要使用一个“昂贵的”方法(比如访问数据库)很多次的时候是非常有用的
方法1 {% with total=business.employees.count %} #注意等号两边不能有空格 {{ total }} <!--只能在with语句体内用--> {% endwith %} 方法2 {% with business.employees.count as total %} {{ total }} {% endwith %}
4.4.5csrf_token
安全认证机制 我们以post方式提交表单的时候,会报错,还记得我们在settings里面的中间件配置里面把一个csrf的防御机制给注销了啊,本身不应该注销的,而是应该学会怎么使用它,并且不让自己的操作被forbiden,通过这个东西就能搞定。 这个标签用于跨站请求伪造保护, 在页面的form表单里面(注意是在form表单里面)任何位置写上{% csrf_token %},这个东西模板渲染的时候替换成了<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">,隐藏的,这个标签的值是个随机字符串,提交的时候,这个东西也被提交了,首先这个东西是我们后端渲染的时候给页面加上的,那么当你通过我给你的form表单提交数据的时候,你带着这个内容我就认识你,不带着,我就禁止你,因为后台我们django也存着这个东西,和你这个值相同的一个值,可以做对应验证是不是我给你的token,存储这个值的东西我们后面再学,你先知道一下就行了,就像一个我们后台给这个用户的一个通行证,如果你用户没有按照我给你的这个正常的页面来post提交表单数据,或者说你没有先去请求我这个登陆页面,而是直接模拟请求来提交数据,那么我就能知道,你这个请求是非法的,反爬虫或者恶意攻击我的网站,以后将中间件的时候我们在细说这个东西,但是现在你要明白怎么回事,明白为什么django会加这一套防御。 处理反扒 先get请求拿到<input type="hidden" name="csrfmiddlewaretoken" value="8J4z1wiUEXt0gJSN59dLMnktrXFW0hv7m4d40Mtl37D7vJZfrxLir9L3jSTDjtG8">, name与values 在去请求
注意事项
- Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %} ... {% endif %}
4.5模板继承
4.5.1为什么要模板基础?
在写html页面中 发现有很多页面有雷同的样式 为了不必重复造轮子
Web框架需要一种很便利的方法用于动态生成HTML页面。 最常见的做法是使用模板。
模板包含所需HTML页面的静态部分,以及一些特殊的模版语法,用于将动态内容插入静态部分。
模板的设计实现了业务逻辑view与显示内容template的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。
4.5.2模板继承怎么实现?
1. 创建一个xx.html页面(作为母版,其他页面来继承它使用) 2. 在母版中定义block块(可以定义多个,整个页面任意位置) {% block content %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 --> {% endblock %} 3 其他页面继承写法 {% extends 'base.html' %} 必须放在页面开头 4 页面中写和母版中名字相同的block块,从而来显示自定义的内容 {% block content %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 --> {{ block.super }} #这是显示继承的母版中的content这个快中的内容 这是xx1 {% endblock %} 以下是具体运行代码
4.5.2.1创建一个母模板
在templates文件夹 中创建一个muban.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板</title> <style> {% block css %} #mub{ width: 100%; height: 50px; background-color: cornflowerblue; } {% endblock %}{#预留的钩子,共其他需要继承它的html,自定义自己的内容#} </style> </head> <body> <div id="mub">我是模板</div> {% block content %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 --> <h1>我是模板h1</h1> {% endblock %} {% block cs2 %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 --> <h1>我是测试2</h1> {% endblock %} </body> </html>
4.5.2.2其他页面继承写法
在templates文件夹 中创建一个home.html 继承于muban.html
{% extends 'muban.html' %} {% block css %} #mub{ width: 100%; height: 50px; background-color: red; } #s6{ width: 50%; height: 50px; background-color: red; float: right; } {% endblock %} {% block content %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 --> <h1>我改变了模板的内容</h1> <div id="s6">我来测试</div> {% endblock %} {% block cs2 %} <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 --> {{ block.super }} 我在测试2下面 {% endblock %}
4.6组件
组件就是类似于python中的模块 什么时候用 什么时候导入 比如常见的导航条,页尾信息等组件 我们一般 保存在单独的文件中,
1 创建html页面,里面写上自己封装的组件内容,xx.html 2 新的html页面使用这个组件 {% include 'xx.html' %} 以下是代码
4.6.1创建组件
在templates文件夹 中创建一个组件 title.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .nav{ background-color: pink; height: 40px; } </style> </head> <body> <div class="nav"> <span>个人中心</span> <span>首页</span> <span>注册</span> <span>登录</span> </div> </body> </html>
4.6.2引用组件
在templates文件夹 中创建一个home.html 引用组件 title.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% include 'title.html' %} <h1>这是新项目首页</h1> </body> </html>
4.7自定义标签和过滤器
4.7.1为什么要有自定义标签和过滤器?
因为在现实编程中可能内置的标签过滤器 不可以满足我们的需求 所有需要我们自己来创建
4.7.2创建自定义标签和过滤器的流程
1 在应用下创建一个叫做templatetags的文件夹(名称不能改),在里面创建一个py文件,例如xx.py 2 在xx.py文件中引用django提供的template类,写法 from django import template register = template.Library() #register变量名称不能改 定义过滤器 @register.filter 参数至多两个 def xx(v1,v2): return xxx 使用: {% load xx %} xx是py文件 {{ name|xx:'oo' }} # 自定义标签 没有参数个数限制 from django import template register = template.Library() #register变量名称不能改 @register.filter #参数至多两个 def guolv(v1,v2): """ :param v1: 变量的值 管道前面的 :param v2: 传的参数 管道后面的,如果不需要传参,就不要添加这个参数 :return: """ return v1+v2 下面是执行的代码
4.7.2.1在应用文件夹下 创建templatetags文件夹并在里面创建一个xx.文件
from django import template register = template.Library() #register变量名称不能改 @register.filter #参数至多两个 def guolv(v1,v2): """ :param v1: 变量的值 管道前面的 :param v2: 传的参数 管道后面的,如果不需要传参,就不要添加这个参数 :return: """ return v1+v2
4.7.2.2视图views中代码
from django.shortcuts import render,HttpResponse name='测试+' def home(request): return render(request,'home.html',{'name':name})
4.7.2.3创建要引用自定义过滤器的html页面
{% load xx %}{#xx是templatetags文件夹下的xx.py文件#} <!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> {{ name|guolv:'要传给n2的参数' }} </body> </html>
4.7.3 inclusion_tag
多用于返回html代码片段
原理先运行nue.html 调用xx.py 中res函数
res函数将返回值给@register.inclusion_tag对应的页面('result.html') 模板渲染后 以组件的形式给原来的nue.htm
nue.htm
{% load xx %} <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {% res a %}#a是参数 </body> </html>
result.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <ul> {% for i in li %} <li>{{ i }}</li> {% endfor %} </ul> </body> </html>
xx.py
# inclusion_tag 返回html片段的标签 @register.inclusion_tag('result.html') def res(n1): #n1 : ['aa','bb','cc'] return {'li':n1 }
4.8静态文件相关
4.8.1静态文件配置
js、css、img等都叫做静态文件,那么关于django中静态文件的配置,我们就需要在settings配置文件里面写上这写内容:
目录:别名也是一种安全机制,浏览器上通过调试台你能够看到的是别名的名字,这样别人就不能知道你静态文件夹的名字了,不然别人就能通过这个文件夹路径进行攻击。
1 项目目录下创建一个文件夹,例如名为static_file,将所有静态文件放到这个文件夹中 2 settings 配置文件中进行下面的配置 # 静态文件相关配置 STATIC_URL = '/abc/' #静态文件路径别名 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'jingtaiwenjianjia'), ] {% load static %} 3 引入<link rel="stylesheet" href="/abc/css/index.css">
4.8.1.1项目目录下创建一个文件夹,例如名为static_file,将所有静态文件放到这个文件夹中
4.8.1.2 找到settings 配置文件中进行下面的配置
STATIC_URL = '/abc/' #静态文件路径别名 可以随便改 #注意第2个参数一定对应创建的文件夹名 别名可以随便改 STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static_file'), ]
4.8.1.3引入的配置文件的html页面内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/abc/css/index.css"> <link rel="stylesheet" href="/abc/plugins/bootstrap-3.3.7-dist/css/bootstrap.min.css"> </head> <body> <input type="text" class="form-control"> <h1>红浪漫spa会所</h1> <img src="/abc/img/timg.jpg" alt=""> <a href="{% url 'home' %}">首页</a> 技师: <ul> <li>小白</li> <li>小黑</li> </ul> </body> </html>
4.8.2url别名和反向解析
我们给url 起一个别名· 以后不管url怎么改 都可以实现原来的网址 就不会写死了
rurl文件写法 url(r'^index2/', views.index,name='cs'), 反向解析 后端views: from django.urls import reverse 可以实现反向解析 reverse('别名') 例如:reverse('cs') 反向解析为别名对应的地址 /index2/ 带参数的反向解析: reverse( index' ,args=(10,))--- /index2/10/ html: {% url '别名' %} -- 例如:{% url 'cs' %} -- /index2/ 下面是代码
rurl文件写法
from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r'^cs/', views.home,name='cs'), url(r'^cs1/', views.cs1,name='cs1'), ]
后端views.py
用于重定向 redirect 我们利用别名 以后不管 别名cs1 对应的网址这么变 我们通过反解析 ,都可以找到他,写活了他 from django.shortcuts import render,HttpResponse,redirect from django.urls import reverse def home(request): return redirect(reverse('cs1')) def cs1(request): return HttpResponse('测试')
4.8.3url命名空间
在路由分发中可能会错乱为了 避免
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ # url(r'^admin/', admin.site.urls), url(r'^app01/', include('app01.urls',namespace='app01')),#app01/home/ url(r'^app02/', include('app02.urls',namespace='app02')), ] 使用: 后端:reverse('命名空间名称:别名') -- reverse('app01:home') hmtl:{% url '命名空间名称:别名' %} -- {% url 'app01:home' %}
5 orm单表操作
orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执行
5.1ORM简介
- MVC或者MVC框架中包括一个重要的部分,就是ORM,它实现了数据模型与数据库的解耦,即数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动
- ORM是“对象-关系-映射”的简称。(Object Relational Mapping,简称ORM)(将来会学一个sqlalchemy,是和他很像的,但是django的orm没有独立出来让别人去使用,虽然功能比sqlalchemy更强大,但是别人用不了)
- 类对象--->sql--->pymysql--->mysql服务端--->磁盘,orm其实就是将类对象的语法翻译成sql语句的一个引擎,明白orm是什么了,剩下的就是怎么使用orm,怎么来写类对象关系语句。
5.2单表操作
5.2.1创建表
注意创建表前 必须先手动在数据库 中创建一个库 并配好setting中配置
第一步在应用文件夹下 models.py文件中创建一个类 字段与参数 详见5.2.1 class Csbiao(models.Model):#Csbiao创建的表名 id=models.AutoField(primary_key=True) name=models.CharField(max_length=10) birthday=models.DateField() checked = models.BooleanField() 4 执行数据库同步指令,添加字段的时候别忘了,该字段不能为空,所有要么给默认值,要么设置它允许为空null=True 在 Terminal中执行 python manage.py makemigrations #生成记录,每次修改了models里面的内容或者添加了新的app,新的app里面写了models里面的内容,都要执行这两条 python manage.py migrate #执行上面这个语句的记录来创建表,生成的表名字前面会自带应用的名字,例如:你的book表在mysql里面叫做app01_book表
5.2.1 settings配置
settings配置文件中 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql',#固定的 'NAME': 'cs',#cs是数据库中的库 'USER':'root',#账号 'PASSWORD':'',#密码 'HOST':'127.0.0.1',#ip地址 'PORT':3306,#端口号 } } 2 项目文件夹下的init文件中写上下面内容,用pymysql替换mysqldb import pymysql pymysql.install_as_MySQLdb() settings配置文件中将USE_TZ的值改为False # USE_TZ = True USE_TZ = False # 告诉mysql存储时间时按照当地时间来寸,不要用utc时间 使用pycharm的数据库客户端的时候,时区问题要注意
5.2.1 更多字段和参数
<1> CharField 字符串字段, 用于较短的字符串. CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数. <2> IntegerField #用于保存一个整数. <3> DecimalField 一个浮点数. 必须 提供两个参数: 参数 描述 max_digits 总位数(不包括小数点和符号) decimal_places 小数位数 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段: models.DecimalField(..., max_digits=5, decimal_places=2) 要保存最大值一百万(小数点后保存10位)的话,你要这样定义: models.DecimalField(..., max_digits=17, decimal_places=10) #max_digits大于等于17就能存储百万以上的数了 admin 用一个文本框(<input type="text">)表示该字段保存的数据. <4> AutoField 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 自定义一个主键:my_id=models.AutoField(primary_key=True) 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model. <5> BooleanField bool字段 A true/false field. admin 用 checkbox 来表示此类字段. <6> TextField 一个容量很大的文本字段. admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框). <7> EmailField 一个带有检查Email合法性的 CharField,不接受 maxlength 参数. <8> DateField 一个日期字段. 共有下列额外的可选参数: Argument 描述 auto_now 当对象被保存时(更新或者添加都行),自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳. auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间. (仅仅在admin中有意义...) <9> DateTimeField 一个日期时间字段. 类似 DateField 支持同样的附加选项. <10> ImageField 图片· 类似 FileField, 不过要校验上传对象是否是一个合法图片.#它有两个可选参数:height_field和width_field, 如果提供这两个参数,则图片将按提供的高度和宽度规格保存. <11> FileField 文件 一个文件上传字段. 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime #formatting, 该格式将被上载文件的 date/time 替换(so that uploaded files don't fill up the given directory). admin 用一个<input type="file">部件表示该字段保存的数据(一个文件上传部件) . 注意:在一个 model 中使用 FileField 或 ImageField 需要以下步骤: (1)在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. (出于性能考虑,这些文件并不保存到数据库.) 定义MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 WEB服务器用户帐号是可写的. (2) 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django 使用 MEDIA_ROOT 的哪个子目录保存上传文件.你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 出于习惯你一定很想使用 Django 提供的 get_<#fieldname>_url 函数.举例来说,如果你的 ImageField 叫作 mug_shot, 你就可以在模板中以 {{ object.#get_mug_shot_url }} 这样的方式得到图像的绝对路径. <12> URLField 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在( 即URL是否被有效装入且 没有返回404响应). admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框) <13> NullBooleanField 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项 admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据. <14> SlugField "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.#它们通常用于URLs 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. #在 以前的 Django 版本,没有任何办法改变50 这个长度. 这暗示了 db_index=True. 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-#populate the slug, via JavaScript,in the object's admin form: models.SlugField (prepopulate_from=("pre_name", "name"))prepopulate_from 不接受 DateTimeFields. <13> XMLField 一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema #的文件系统路径. <14> FilePathField 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的. 参数 描述 path 必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. Example: "/home/images". match 可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名. 注意这个正则表达式只会应用到 base filename 而不是 路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif. recursive可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录. 这三个参数可以同时使用. match 仅应用于 base filename, 而不是路径全名. 那么,这个例子: FilePathField(path="/home/images", match="foo.*", recursive=True) ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif <15> IPAddressField 一个字符串形式的 IP 地址, (i.e. "24.124.1.30"). <16> CommaSeparatedIntegerField 用于存放逗号分隔的整数值. 类似 CharField, 必须要有maxlength参数.
更多参数
1)null 如果为True,Django 将用NULL 来在数据库中存储空值。 默认值是 False. (1)blank 如果为True,该字段允许不填。默认为False。 要注意,这与 null 不同。null纯粹是数据库范畴的,而 blank 是数据验证范畴的。 如果一个字段的blank=True,表单的验证将允许该字段是空值。如果字段的blank=False,该字段就是必填的。 (2)default 字段的默认值。可以是一个值或者可调用对象。如果可调用 ,每有新对象被创建它都会被调用,如果你的字段没有设置可以为空,那么将来如果我们后添加一个字段,这个字段就要给一个default值 (3)primary_key 如果为True,那么这个字段就是模型的主键。如果你没有指定任何一个字段的primary_key=True, Django 就会自动添加一个IntegerField字段做为主键,所以除非你想覆盖默认的主键行为, 否则没必要设置任何一个字段的primary_key=True。 (4)unique 如果该值设置为 True, 这个数据字段的值在整张表中必须是唯一的 (5)choices 由二元组组成的一个可迭代对象(例如,列表或元组),用来给字段提供选择项。 如果设置了choices ,默认的表单将是一个选择框而不是标准的文本框,<br>而且这个选择框的选项就是choices 中的选项。 (6)db_index 如果db_index=True 则代表着为此字段设置数据库索引。 DatetimeField、DateField、TimeField这个三个时间字段,都可以设置如下属性。 (7)auto_now_add 配置auto_now_add=True,创建数据记录的时候会把当前时间添加到数据库。 (8)auto_now 配置上auto_now=True,每次更新数据记录的时候会更新该字段,标识这条记录最后一次的修改时间。
5.2.1自定义字段(了解)
5.2.2添加表纪录
第一步views表引入app01文件夹下的models.py文件from app01 import models
方式1: new_obj=models.Csbiao(#Csbiao类名也是表名 name='cs', birthday='2019-09-27', checked=1, ) new_obj.save() 方式2: ret = models.Csbiao.objects.create( name='cs111', birthday='2019-09-27', checked=1, ) # ret 是创建的新的记录的model对象(重点) print(ret) #UserInfo object 卫贺 print(ret.name) #UserInfo object print(ret.bday) #UserInfo object
5.2.2.1 时间问题
models.UserInfo.objects.create( name='杨泽涛2', bday=current_date, # now=current_date, 直接插入时间没有时区问题 checked=0 ) 但是如果让这个字段自动来插入时间,就会有时区的问题,auto_now_add创建记录时自动添加当前创建记录时的时间,存在时区问题 now = models.DateTimeField(auto_now_add=True,null=True) 解决方法: settings配置文件中将USE_TZ的值改为False # USE_TZ = True USE_TZ = False # 告诉mysql存储时间时按照当地时间来寸,不要用utc时间 使用pycharm的数据库客户端的时候,时区问题要注意
5.2.3查询表纪录
<1> all(): 查询所有结果,结果是queryset类型 查询所有的数据 .all方法 返回的是queryset集合 all_objs = models.Student.objects.all() # 类似于列表 -- queryset集合 # for i in all_objs: # print(i.name) print(all_objs) <2> filter(**kwargs): 它包含了与所给筛选条件相匹配的对象,结果也是queryset类型 Book.objects.filter(title='linux',price=100) #里面的多个条件用逗号分开,并且这几个条件必须都成立,是and的关系,or关系的我们后面再学,直接在这里写是搞不定or的 models.Student.objects.filter(id=7,name='大壮哥哥',age=78).update( name='大壮禅师', age=78 ) #打散形式传参 models.Student.objects.filter(**{'id':7,'name':'大壮禅师'}).update(age=100) models.Student.objects.all().filter(id=7) queryset类型可以调用fitler在过滤 <3> get(**kwargs): 返回与所给筛选条件相匹配的对象,不是queryset类型,是行记录对象,返回结果有且只有一个, 如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。 Book.objects.get(id=1) <4> exclude(**kwargs): 排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作昂,用这个exclude,返回值是queryset类型 Book.objects.exclude(id=6),返回id不等于6的所有的对象,或者在queryset基础上调用,Book.objects.all().exclude(id=6) exclude(**kwargs): 排除,objects控制器和queryset集合都可以调用,返回结果是queryset类型 query = models.Student.objects.exclude(id=1) print(query) query = models.Student.objects.filter(age=38).exclude(id=6) print(query) <5> order_by(*field): 排序 queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型 models.Book.objects.all().order_by('price','id') #直接写price,默认是按照price升序排列,按照字段降序排列,就写个负号就行了order_by('-cs'),order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序 <6> reverse(): queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型 # 只可以排序之后反转 # query = models.Student.objects.all().order_by('id').reverse() # print(query) <7> count(): queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。 <8> first(): queryset类型的数据来调用,返回第一条记录 Book值 <9> last(): queryset类型的数据来调用,返回最后一条记录,结果为model对象类型 <10> exists(): queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False 空的queryset类型数据也有布尔值True和False,但是一般不用它来判断数据库里面是不是有数据,如果有大量的数据,你用它来判断,那么就需要查询出所有的数据,效率太差了,用count或者exits 例:all_books = models.Book.objects.all().exists() #翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,就是通过limit 1,取一条来看看是不是有数据 <11> values(*field): 用的比较多,queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列 model的实例化对象,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。 里面可以加子段显示 <12> values_list(*field): 它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列 里面可以加子段显示 <13> distinct(): values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录 去重,结果还是queryset 里面不可以传参 显示nanme等等可以用来去重 query = models.Student.objects.all().values('age').distinct() print(query)
5.2.3.2基于双下划线的模糊查询
Book.objects.filter(price__in=[100,200,300]) #price值等于这三个里面的任意一个的对象 Book.objects.filter(price__gt=100) #大于,大于等于是price__gte=100,别写price>100,这种参数不支持 Book.objects.filter(price__lt=100) 小于 Book.objects.filter(price__range=[100,200]) #sql的between and,大于等于100,小于等于200 Book.objects.filter(title__contains="python") #title值中包含python的 Book.objects.filter(title__icontains="python") #不区分大小写 Book.objects.filter(title__startswith="py") #以什么开头,istartswith 不区分大小写 Book.objects.filter(pub_date__year=2012) date类型 # all_books = models.Book.objects.filter(pub_date__year=2012) #找2012年的所有书籍 # all_books = models.Book.objects.filter(pub_date__year__gt=2012)#找大于2012年的所有书籍 all_books = models.Book.objects.filter(pub_date__year=2019,pub_date__month=2)#找2019年月份的所有书籍,如果明明有结果,你却查不出结果,是因为mysql数据库的时区和咱们django的时区不同导致的,了解一下就行了,你需要做的就是将django中的settings配置文件里面的USE_TZ = True改为False,就可以查到结果了,以后这个值就改为False,而且就是因为咱们用的mysql数据库才会有这个问题,其他数据库没有这个问题。
5.2.4删除表纪录
简单查询:filter() -- 结果是queryset类型的数据里面是一个个的model对象,类似于列表 models.UserInfo.objects.filter(id=7).delete() #queryset对象调用 models.UserInfo.objects.filter(id=7)[0].delete() #model对象调用
5.2.5修改表纪录
方式1:update models.UserInfo.objects.filter(id=2).update( name='篮子文', checked = 0, ) #错误示例,model对象不能调用update方法 models.UserInfo.objects.filter(id=2)[0].update( name='加篮子+2', # checked = 0, ) 方式2 ret = models.UserInfo.objects.filter(id=2)[0] ret.name = '加篮子+2' ret.checked = 1 ret.save() 更新时的auto_now参数 # 更新记录时,自动更新时间,创建新纪录时也会帮你自动添加创建时的时间,但是在更新时只有使用save方法的方式2的形式更新才能自动更新时间,有缺陷,放弃 now2 = models.DateTimeField(auto_now=True,null=True)