WEB框架本质:
服务器程序和应用程序:
是一个socket服务端,而用户的浏览器就是一个socket客户端。
例子:
import socket
sok = socket.socket()
sok.bind(("127.0.0.1",8008))
sok.listen()
while True:
conn,addr = sok.accept()
conn.recv(1000)
conn.send(b"200\tOK")
conn,close()
服务器程序:负责对socket服务端进行封装,并在请求到来时,对请求的各种数据进行整理。
应用程序:负责具体的逻辑处理。
1.WSGI:
WSGI(Web Server GatewayInterface)一种规范,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。
2.uwsgi
Nginx中HttpUwsgiModule的作用是与uWSGI服务器进行交换。WSGI是一种Web服务器网关接口。它是一个Web服务器(如nginx,uWSGI等服务器)与web应用(如用Flask框架写的程序)通信的一种规范。
3.uWSGI
uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。
详细内容(https://www.jianshu.com/p/679dee0a4193)
4.WSGI / uwsgi / uWSGI 这三个概念的区分。
- WSGI是一种通信协议。
- uwsgi是一种线路协议而不是通信协议,在此常用于在uWSGI服务器与其他网络服务器的数据通信。
- 而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器
MVC和MTV框架:
MVC:
Web应用分为
模型(M),
控制器(C)
视图(V),
他们之间以一种插件式的、松耦合的方式连接在一起,模型负责业务对象与数据库的映射(ORM),视图负责与用户的交互(页面),控制器接受用户的输入调用模型和视图完成用户的请求。
img
MTV:
M 代表模型(Model): 负责业务对象和数据库的关系映射(ORM)。
T 代表模板 (Template):负责如何把页面展示给用户(html)。
V 代表视图(View): 负责业务逻辑,并在适当时候调用Model和Template。
img
Django总览(django2.0)
1.Django路由系统url.py:
说明:它的本质是URL与要为该URL调用的视图函数之间的映射表。你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。
from django.urls import path,re_path
urlpatterns = [
path(正则表达式, views视图函数,参数,别名),
path('articles/2003/', views.special_case_2003),
#re_path('^articles/2003/$',view.special_case_2003),
path('articles////' , views.article_detail),
#re_path(r'^articles/(?P[0-9]{4})/(?P[0-9]{2})/(?P[0-9]{2})/$', ,views.article_detail),
]
补充:Django settings.py配置文件中默认没有 APPEND_SLASH 这个参数,但 Django 默认这个参数为 APPEND_SLASH = True。 其作用就是自动在网址结尾加'/'
路由分发include:
----------------------main/urls.py----------------------
from django.urls import path,re_path,include
urlpatterns = [
path('',include('app01.urls'))
]
----------------------app/urls.py----------------------
from django.contrib import admin
from django.urls import path,re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('book//' ,views.book),
re_path('^index/$', views.index),
]
2.Django视图函数views.py:
说明:一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。无论视图本身包含什么逻辑,都要返回响应。代码写在哪里也无所谓,只要它在你当前项目目录下面。除此之外没有更多的要求了——可以说“没有什么神奇的地方”。为了将代码放在某处,大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中。
FBV:
在视图view中使用函数处理请求:
def index(request):
if request.method == 'GET':
return HttpResponse('this is index')
if request.method =='POST':
return HttpResponse('this is post index')
CBV:
在视图view中使用类处理请求:
优点:可以用不同的函数针对不同的HTTP方法处理,而不是通过很多if判断,提高代码可读性
-------------------views.py---------------------------
from django.views import View
class Index(View):
def get(self,request,*args, **kwargs):
return HttpResponse('this is index')
def post(self,request,*args, **kwargs):
return HttpResponse('this is post index')
----------------urls.py--------------------------------
path('index/', views.Index.as_view()),
视图加装饰器:例如登录校验,只有登录才能查看的页面。
-------------------------------函数----------------------------
def warapper(func):
def inner(*args,**kwargs):
start = time.time()
ret = func(*args,**kwargs)
end = time.time()
print(end-start)
return ret
return inner
@warapper
def index(request):
if request.method == 'GET':
return HttpResponse('this is index')
if request.method =='POST':
return HttpResponse('this is post index')
--------------------------------类-------------------------------
前提:类中的方法与独立函数不完全相同,因此不能直接将函数装饰器应用于类中的方法 ,我们需要先将其
转换为方法装饰器。Django中提供了method_decorator装饰器用于将函数装饰器转换为方法装饰器。
对于CBV添加装饰器:///
1.直接添加在dispatch里面,这样每个函数都会执行
from django.utils.decorators import method_decorator
@method_decorator(login_test)
def dispatch(self, request, *args, **kwargs):
res = super(IndexView, self).dispatch(request, *args, **kwargs)
return res
2.添加在每一个函数中
from django.utils.decorators import method_decorator
@method_decorator(login_test)
def get(self, request, *args, **kwargs):
return HttpResponse('this is index')
3.直接添加在类上,后面的name表示只给get添加装饰器
from django.utils.decorators import method_decorator
@method_decorator(login_test, name='get') get是给get方法加 (以这种方式如果想给多个方法加装饰器,需要写多层装饰器,因为name这个参数的值必须是个字符串,并且不能同时写两个方法)
@method_decorator(login_test, name='post') post是给post方法加
class Index(View):
def get(self,request):
return HttpResponse('this is post index')
csrf-token装饰器:
注意csrf-token装饰器的特殊性,在CBV模式下它只能加在dispatch上面
下面这是csrf_token的装饰器:
@csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置csrfToken全局中间件。
@csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
注意:from django.views.decorators.csrf import csrf_exempt,csrf_protec
request对象:
概述:当一个页面被请求时,Django就会创建一个包含本次请求原信息的HttpRequest对象。Django会将这个对象自动传递给响应的视图函数,一般视图函数约定俗成地使用 request 参数承接这个对象。
1.属性:
请求相关的常用值:
path_info 返回用户访问url,不包括域名
method 请求中使用的HTTP方法的字符串表示,全大写表示。
GET 包含所有HTTP GET参数的类字典对象
POST 包含所有HTTP POST参数的类字典对象
body 请求体,byte类型 request.POST的数据就是从body里面提取到的属性,所有的 属性应该被认为是只读的,除非另有说明。
----------------------------------------------------------------------------------
属性:
django将请求报文中的请求行、头部信息、内容主体封装成 HttpRequest 类中的属性。除了特殊说明的之外,其他均为只读的。
0.HttpRequest.scheme
表示请求方案的字符串(通常为http或https)
1.HttpRequest.body
一个字符串,代表请求报文的主体。在处理非 HTTP 形式的报文时非常有用,例如:二进制图片、XML,Json等。但是,如果要处理表单数据的时候,推荐还是使用 HttpRequest.POST 。另外,我们还可以用 python 的类文件方法去操作它,详情参考 HttpRequest.read() 。
2.HttpRequest.path
一个字符串,表示请求的路径组件(不含域名)。
例如:"/music/bands/the_beatles/"
3.HttpRequest.method
一个字符串,表示请求使用的HTTP 方法。必须使用大写。
例如:"GET"、"POST"
4.HttpRequest.encoding
一个字符串,表示提交的数据的编码方式(如果为 None 则表示使用 DEFAULT_CHARSET 的设置,默认为 'utf-8')。这个属性是可写的,你可以修改它来修改访问表单数据使用的编码。接下来对属性的任何访问(例如从 GET 或 POST 中读取数据)将使用新的 encoding 值。如果你知道表单数据的编码不是 DEFAULT_CHARSET ,则使用它。
5.HttpRequest.GET
一个类似于字典的对象,包含 HTTP GET 的所有参数。
6.HttpRequest.POST
一个类似于字典的对象,如果请求中包含表单数据,则将这些数据封装成 QueryDict 对象。如果使用 POST上传文件的话,文件信息将包含在 FILES 属性中。
7.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
8.HttpRequest.FILES
一个类似于字典的对象,包含所有的上传文件信息。FILES 中的每个键为"file" name="" /> 中的name,值则为对应的数据。注意,FILES 只有在请求的方法为POST 且提交的
2.方法
1.HttpRequest.get_full_path()
返回 path,如果可以将加上查询字符串。
例如:"/music/bands/the_beatles/?print=true"
2.HttpRequest.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
返回签名过的Cookie 对应的值,如果签名不再合法则返回django.core.signing.BadSignature。
如果提供 default 参数,将不会引发异常并返回 default 的值。
可选参数salt 可以用来对安全密钥强力攻击提供额外的保护。max_age 参数用于检查Cookie 对应的时间戳以确保Cookie 的时间不会超过max_age 秒。
3.HttpRequest.is_secure()
如果请求时是安全的,则返回True;即请求通是过 HTTPS 发起的。
4.HttpRequest.is_ajax()
如果请求是通过XMLHttpRequest 发起的,则返回True,方法是检查 HTTP_X_REQUESTED_WITH 相应的首部是否是字符串'XMLHttpRequest'。大部分现代的 JavaScript 库都会发送这个头部。如果你编写自己的 XMLHttpRequest 调用(在浏览器端),你必须手工设置这个值来让 is_ajax() 可以工作。如果一个响应需要根据请求是否是通过AJAX 发起的,并且你正在使用某种形式的缓存例如Django 的 cache middleware,你应该使用 vary_on_headers('HTTP_X_REQUESTED_WITH') 装饰你的视图以让响应能够正确地缓存。
3.补充:
from django.shortcuts import render,HttpResponse,redirect
# Create your views here.
def index(request):
print(request.method) #请求方式
print(request.path) #请求路径,不带参数的
print(request.POST) #post请求数据 字典格式
print(request.GET) #get的请求数据 字典格式
print(request.META) #请求头信息,将来用到哪个咱们再说哪个
print(request.get_full_path()) #获取请求路径带参数的,/index/?a=1
print(request.is_ajax()) #判断是不是ajax发送的请求,True和False
'''
Django一定最后会响应一个HttpResponse的示例对象
三种形式:
1 HttpResponse('字符串') 最简单
2 render(页面) 最重要
2.1 两个功能
-- 读取文件字符串
-- 嵌入变量(模板渲染) html里面:{{ name }} , {'name':'chao'}作为render的第三个参数,想写多个变量{'name':'chao','hobby':['篮球','羽毛球']....}
3 redirect() 重定向 最难理解,某个网站搬家了,网址变了,访问原来的网址就重定向到一个新网址,就叫做重定向,网站自己做的重定向,你访问还是访问的你之前的,你自己啥也不用做,浏览器发送请求,然后服务端响应,然后服务端告诉浏览器,你直接跳转到另外一个网址上,那么浏览器又自动发送了另外一个请求,发送到服务端,服务端返回一个页面,包含两次请求,登陆成功后跳转到网站的首页,网站首页的网址和你login登陆页面的网址是不用的。
'''
return render(request,'index.html',{'name':'chao'})
# return HttpResponse('ok')
注意:键值对的值是多个的时候,比如checkbox类型的input标签,select标签,需要用:
request.POST.getlist("hobby")
响应对象:
HttpResponse对象
说明:由Django自动创建的HttpRequest对象相比,HttpResponse对象是我们的职责范围了。我们写的每个视图都需要实例化,填充和返回一个HttpResponse。
使用:
传递字符串
from django.http import HttpResponse
response = HttpResponse("Here's the text of the Web page.")
response = HttpResponse("Text only, please.", content_type="text/plain")
设置或删除响应头信息
response = HttpResponse()
response['Content-Type'] = 'text/html; charset=UTF-8'
del response['Content-Type']
---------------------------------------------------------------------------------
属性:
HttpResponse.content:响应内容
HttpResponse.charset:响应内容的编码
HttpResponse.status_code:响应的状态码
----------------------------------------------------------------------------------
JsonResponse对象
说明:JsonResponse是HttpResponse的子类,专门用来生成JSON编码的响应。
区别:
JsonResponse默认就是content_type="application/json"。HttpResponse(json.dumps(data),content_type="application/json")
from django.http import JsonResponse
def index(request):
# 以1方式 return JsonResponse({'name': 'jbar'})
# 则前端接收 console.log(data.msg);
# 以2方式 return HrrpResponse(json.dumps({'name': 'jbar'}))
# 则前端接收 var data = json.parse(data)
console.log(data.name);
render对象
说明:结合一个给定的模板和一个给定的上下文字典,并返回一个渲染后的 HttpResponse 对象
render(request,template_name,context=None,context_type=None,status=None,using=None)
参数:
request: 用于生成响应的请求对象。
template_name:要使用的模板的完整名称,可选的参数
context:添加到模板上下文的一个字典。默认是一个空字典。如果字典中的某个值是可调用的,视 图将在渲染模板之前调用它。
content_type:生成的文档要使用的MIME类型。默认为 DEFAULT_CONTENT_TYPE 设置的值。默认 为'text/html'
status:响应的状态码。默认为200。
useing: 用于加载模板的模板引擎的名称。
from django.shortcuts import render
---------------------------------------------------------------------------------
例如:
def index(request):
return render(request, 'myapp/index.html', {'foo': 'bar'})
redirect对象
说明:重定向到某个url,在对重定向的url发送一个请求
1.一个定义的路由url
def index(request):
return redict('/home/')
2.一个完整的网址
def index(request):
return redict('http://www.baidu.com')
关于重定向的补充说明:
1.301和302的区别。
301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取
(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)——这是它们的共同点。
他们的不同在于。301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;
302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO302好于301
2.重定向原因:
(1)网站调整(如改变网页目录结构);
(2)网页被移到一个新地址;
(3)网页扩展名改变(如应用需要把.php改成.Html或.shtml)。
这种情况下,如果不做重定向,则用户收藏夹或搜索引擎数据库中旧地址只能让访问客户得到一个404页面错误信息,访问流量白白丧失;再者某些注册了多个域名的
网站,也需要通过重定向让访问这些域名的用户自动跳转到主站点等。
复制代码
临时重定向(响应状态码:302)和永久重定向(响应状态码:301)对普通用户来说是没什么区别的,它主要面向的是搜索引擎的机器人。
3.Django模板系统
介绍:
关于模板渲染你只需要记两种特殊符号(语法):
{{ 变量 }}和 {% 逻辑语句 %}
变量相关的用{{}},逻辑相关的用{%%}。
过滤器:
作用:使用过滤器来改变变量的显示。
过滤器的语法: {{ value|filter_name:参数 }}
使用管道符"|"来应用过滤器。
例如:
{{ name|lower }}会将name变量应用lower过滤器之后再显示它的值。lower在这里的作用是将文本全都变成小写。
-----------------------------------------------------------------------------------
1.default
如果一个变量是false或者为空,使用给定的默认值。 否则,使用变量的值。
{{ value|default:"nothing"}}如果value没有传值或者值为空的话就显示nothing
2.length
返回值的长度,作用于字符串和列表。{{ value|length }}.返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
3.filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}。如果 value 是 123456789,输出将会是 117.7 MB。
4.slice
切片,如果 value="hello world",还有其他可切片的数据类型{{value|slice:"2:-1"}}
5。date
格式化,如果 value=datetime.datetime.now()
{{ value|date:"Y-m-d H:i:s"}}关于时间日期的可用的参数(除了Y,m,d等等)还有很多,有兴趣的可以去查查看看。
详细:https://www.cnblogs.com/clschao/articles/10414811.html
标签:
for标签
1.遍历一个列表:
{% for person in person_list %}
{{ person.name }}
{% endfor %}
2.遍历一个字典:
{% for key,val in dic.items %}
{{ key }}:{{ val }}
if标签
说明:if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断,注意条件两边都有空格。
{% if num > 100 or num < 0 %}
无效
{% elif num > 80 and num < 100 %}
优秀
{% else %}
凑活吧
{% endif %}
csrf_token标签
说明:这个标签用于跨站请求伪造保护。
在页面的form表单里面(注意是在form表单里面)任何位置写上{% csrf_token %},这个东西模板渲染的时候替换成了,隐藏的,这个标签的值是个随机字符串
{% csrf_token %}
模板继承
意义:模版继承可以让您创建一个基本的“骨架”模版,它包含您站点中的全部元素,并且可以定义能够被子模版覆盖的 blocks 。(公用的父模版)
1.父模版base.html
{{ title }}
{% block css %}
{% endblock css %}
{% block container %}
子模版内容
{% endblock container %}
{% block js %}
{% endblock js %}
2.一个子模版
{% extends "base.html" %}
{% block title %}My amazing blog{% endblock %}
{% block content %}
子模版内容
{% endblock %}
{% block js %}
{% endblock %}
组件
意义:可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方,文件的任意位置按如下语法导入即可
语法:{% include 'navbar.html' %}
------------nav.html-------------
Title
-------------------------------嵌入导航栏的页面,test.html---------------------------
Title
{% include 'nav.html' %}
xxxxxxxxxx
自定义标签和过滤器
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
并在项目应用目录app下创建templatetags文件夹,里面做标签和过滤器
-----------DjangoPro/app/templatetags/my_tags.py--------------------------------
#必须模块
from django import template
from django.utils.safestring import mark_safe
#register的名字是固定的,不可改变
register = template.Library()
#自定义标签
@register.simple_tag
def simple_tag_add(v1, v2):
return v1 + v2
#自定义过滤器
@register.filter
def filter_multi(v1, v2):
return v1 * v2
@register.simple_tag
def my_input(id, arg):
result = "" % (name, arg,)
return mark_safe(result)
使用这个过滤器和标签
#在html页面导入my_tags.py,并使用自定义标签和自定义过滤器
{% load tags %}
{% simple_tag_add 100 200 %}
{{ 50|filter_multi:40 }}
{% my_input "my_input" "background-color:#FFB90F" %}
自定义标签不可以用在{% if %} {% endif %} {% for %} {% endfor %} 语句中
自定义过滤器可以
django
{% if 10|filter_multi:30 > 100 %}
{{ 10|filter_multi:30 }}
{% endif %}
使用inclusion_tag
说明:类似于上面的组件,只不过他需要从后端得到数据才能完成渲染成功。多用于返回html代码片段
1.写视图函数得到页面所需要的数据,将数据return回来,
2.给这个视图函数加上@register.inclusion_tag(filename='left_menu.html'),以指定html文件将数据传入。
在需要用到自定义inclusion_tag的html文件中引入,引入固定规则为:
通过使用{% load py文件名 %} {% 对应html文件名 py文件中的视图函数所需参数 %}的固定形式引用自定义的inclusion_tag。
img
详细:https://www.jianshu.com/p/b23c77852e33
4.DjangoORM模型
1.介绍:
概述:ORM是“对象-关系-映射”的简称。(Object Relational Mapping,简称ORM)orm其实就是将类对象的语法翻译成sql语句的一个引擎.
特点:数据模型的设计不需要依赖于特定的数据库,通过简单的配置就可以轻松更换数据库,这极大的减轻了开发人员的工作量,不需要面对因数据库变更而导致的无效劳动.
流程:类对象--->sql--->pymysql--->mysql服务端--->磁盘.
总结:一个类对于数据库一张表。
2.ORM与数据库对应关系
类---------->表
类对象 ---------->行(记录)
类属性 ---------->表的字段(重点)
3.结构:
#在app下的models.py文件中,一个类对于数据库一张表。
class User(modelclass Book(models.Model):
id = models.AutoField(primary_key=True) # 如果表里面没有写主键,表里面会自动生成一个自增主键字段,叫做id字段,orm要求每个表里面必须要写一个主键
name = models.CharField(max_length=32) # 和varchar(32)是一样的,32个字符
birthday = models.DateField() # 必须存这种格式"2018-12-12"
def __str__(self): #类对象显示name值
return self.name
参数详细:https://www.cnblogs.com/clschao/articles/10427807.html
4.使用mysql数据库配置
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
},
'app01':{#可以为每个app都配置自己的数据,并且数据库还可以指定别的,也就是不一定就是 mysql,也可以指定sqlite等其他的数据库
'ENGINE': 'django.db.backends.mysql',
'NAME': 'db1', # 要连接的数据库,连接前需要创建好
'USER': 'root',# 连接数据库的用户名
'PASSWORD': '123',# 连接数据库的密码
'HOST': '127.0.0.1',# 连接主机,默认本机
'PORT':3306 # 端口 默认3306
}
}
#在项目名下的__init__.py文件中写入以下代码即可使用mysql
import pymysql
pymysql.install_as_MySQLdb()
5.同步命令:
settings.py中 INSTALL_APP中必须配置好app
python manage.py makemigrations
python manage.py migrate
6.因为python版本无法使用mysql的解决问题
错误提示:
django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.3 or newer is required; you have 0.7.11.None
原因:
MySQLclient目前只支持到python3.4,因此如果使用的更高版本的python,需要修改如下:
办法:
通过查找路径C:\Programs\Python\Python36-32\Lib\site-packages\Django-2.0-py3.6.egg\django\db\backends\mysql
这个路径里的文件把
if version < (1, 3, 3):
raise ImproperlyConfigured("mysqlclient 1.3.3 or newer is required; you have %s" % Database.__version__)
注释掉。
7.增删改查(单表操作)
增加:
1.方式
jack_obj = models.User(name='jack')
jack_obj.save()
2.方式
models.User.objects.create(name='jack')
3.批量插入
user_list = [
models.User(name='alex'),
models.User(name='mick'),
models.User(name='python')
]
models.User.objects.bulk_create(user_list)
4.update_or_create:有就更新,没有就创建 ,还有个get_or_create,有就查询出来,没有就创建
obj,created = models.UserToken.objects.update_or_create(
user=user, # 查找筛选条件
defaults={ # 添加或者更新的数据
"token":random_str,
}
)
查询:
models.User.objects.all() 获取所有
models.User.objects.filter(**kwargs):
它包含了与所给筛选条件相匹配的对象,结果也是queryset类型
models.User.objects.get(**kwargs):
返回与所给筛选条件相匹配的对象,不是queryset类型,是行记录对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常
models.User.objects.exclude(**kwargs):
排除.它包含了与所给筛选条件不匹配的对象,返回值是queryset类型 :User.objects.exclude(id=6),返回id不等于6的所有的对象
models.User.objects.order_by(*field):
queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型
models.User.objects.reverse():
queryset类型的数据来调用,对查询结果反向排序,返回值还是queryset类型
models.User.objects.count():
queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
models.User.objects.first():
queryset类型的数据来调用,返回第一条记录
:User.objects.all()[0] = User.objects.all().first()
models.User.objects.last():
queryset类型的数据来调用,返回最后一条记录
models.User.objects.exists():
queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False
models.User.objects.values(*field):
用的比较多,返回的是一个字典序列
models.User.objects.values_list(*field):
返回的是一个元组序列
models.User.objects.distinct():
values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录'
详细:https://www.cnblogs.com/clschao/articles/10427807.html
性能优化查询:
def select_related(self, *fields)
性能相关:表之间进行join连表操作,一次性获取关联的数据。
总结:
1. select_related主要针一对一和多对一关系进行优化。
2. select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高 性能。
def prefetch_related(self, *lookups)
性能相关:多表连表操作时速度会慢,使用其执行多次SQL查询在Python代码中实现连表操作。
总结:
1. 对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进 行优化。
2. prefetch_related()的优化方式是分别查询每个表,然后用Python处理他们之间的关系。
def annotate(self, *args, **kwargs)
# 用于实现聚合group by查询
from django.db.models import Count, Avg, Max, Min, Sum
v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id'))
# SELECT u_id, COUNT(ui) AS `uid` FROM UserInfo GROUP BY u_id
v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id')).filter(uid__gt=1)
# SELECT u_id, COUNT(ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
v = models.UserInfo.objects.values('u_id').annotate(uid=Count('u_id',distinct=True)).filter(uid__gt=1)
# SELECT u_id, COUNT( DISTINCT ui_id) AS `uid` FROM UserInfo GROUP BY u_id having count(u_id) > 1
执行原生SQL语句raw查询:
models.User.objects.raw('select * from appuser')
基于双下划线模糊查询:
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)
删除:
models.User.objects.all().delete() #它运行时立即删除对象而不返回任何值
models.User.objects.filter(id=1).delete()
修改:
1.
models.User.objects.filter(id=1).update(name='ooo')
2.
obj = models.User.objects.filter(id=1)
obj.name ='ooo'
obj.save()
8.增删改查(多表操作)
多表概述:
简述:一对一、多对一、多对多 ,用book表和publish表自己来想想关系,想想里面的操作,加外键约束和不加外键约束的区别,一对一的外键约束是在一对多的约束上加上唯一约束。
结构:
文字描述:
----------------------------------------------------------------------------------
作者模型:一个作者有姓名和年龄。
作者详细模型:把作者的详情放到详情表,包含生日,手机号,家庭住址等信息。作者详情模型和作者模型之间是一对一的关系(one-to-one)
出版商模型:出版商有名称,所在城市以及email。
书籍模型: 书籍有书名和出版日期,一本书可能会有多个作者,一个作者也可以写多本书,所以作者和书籍的关系就是多对多的关联关系(many-to-many);一本书只应该由一个出版商出版,所以出版商和书籍是一对多关联关系(one-to-many)。
模型建立:
-----------------------------------------------------------------------------------
from django.db import models
class Author(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
age=models.IntegerField()
authorDetail=models.OneToOneField(to="AuthorDetail",to_field="nid",on_delete=models.CASCADE)
class AuthorDetail(models.Model):#
nid = models.AutoField(primary_key=True)
birthday=models.DateField()
telephone=models.BigIntegerField()
addr=models.CharField( max_length=64)
class Publish(models.Model):
nid = models.AutoField(primary_key=True)
name=models.CharField( max_length=32)
city=models.CharField( max_length=32)
email=models.EmailField()
#多对多的表关系,mysql是手动创建一个第三张表,每个字段外键关联到另外两张多对多关系的表,orm的manytomany自动帮我们创建第三张表,两种方式建立关系都可以,以后的学习我们暂时用orm自动创建的第三张表,因为手动创建的第三张表我们进行orm操作的时候,很多关于多对多关系的表之间的orm语句方法无法使用
#如果你想删除某张表,你只需要将这个表注销掉,然后执行那两个数据库同步指令就可以了,自动就删除了。
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE)
# 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表,并且注意一点,你查看book表的时候,你看不到这个字段,因为这个字段就是创建第三张表的意思,不是创建字段的意思,所以只能说这个book类里面有authors这个字段属性
authors=models.ManyToManyField(to='Author',) #注意不管是一对多还是多对多,写to这个参数的时候,最后后面的值是个字符串,不然你就需要将你要关联的那个表放到这个表的上面
结构-多对多表中自动创建第三张表
class Boy(models.Model):
name = models.CharField(max_length=35)
class Girl(models.Model):
name = models.CharField(max_length=33)
class BoyToGirl(models.Model):
boy = models.ForeignKey(to='Boy',on_delete=models.CASCADE)
girl = models.ForeignKey(to='Girl',on_delete=models.CASCADE)
结构-通过ManyToManyField自动创建第三张表
class Boy(models.Model):
name = models.CharField(max_length=35)
BoyLoveGirls = models.ManyToManyField(to='Girl')
class Girl(models.Model):
name = models.CharField(max_length=33)
结构-多表参数
1.一对一字段
to
设置要关联的表。
to_field
设置要关联的字段。
on_delete
同ForeignKey字段。
2.一对多字段
to
设置要关联的表
to_field
设置要关联的表的字段
related_name
反向操作时,使用的字段名,用于代替原反向查询时的'表名_set'。
related_query_name
反向查询操作时,使用的连接前缀,用于替换表名。
on_delete
当删除关联表中的数据时,当前表与其关联的行的行为。
3.多对多字段:
to
设置要关联的表
related_name
同ForeignKey字段。
related_query_name
同ForeignKey字段。
through
在使用ManyToManyField字段时,Django将自动生成一张表来管理多对多的关联关系。但我们也可以手动创建第三张表来管理多对多关系,此时就需要通过
through来指定第三张表的表名。
through_fields
设置关联的字段。
db_table
默认创建第三张表时,数据库中表的名称。
4.元信息
ORM对应的类里面包含另一个Meta类,而Meta类封装了一些数据库的信息。主要字段如下:
class Author2Book(models.Model):
author = models.ForeignKey(to="Author")
book = models.ForeignKey(to="Book")
class Meta:
unique_together = ("author", "book")
db_table
ORM在数据库中的表名默认是 app_类名,可以通过db_table可以重写表名。db_table = 'book_model'
index_together
联合索引。
unique_together
联合唯一索引。
ordering
指定默认按什么字段排序。
ordering = ['pub_date',]
只有设置了该属性,我们查询到的结果才可以被reverse(),否则是能对排序了的结果进行反转(order_by()方法排序过的数据)
增:
1.一对多
方式1:
publish_obj=Publish.objects.get(nid=1)
#拿到nid为1的出版社对象
book_obj=Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=100,publish=publish_obj)
#出版社对象作为值给publish,其实就是自动将publish字段变成publish_id,然后将publish_obj的id给取出来赋值给publish_id字段,注意你如果不是publish类的对象肯定会报错的,别乱昂
方式2:
book_obj=Book.objects.create(title="金瓶眉",publishDate="2012-12-12",price=100,publish_id=1)
#直接可以写id值,注意字段属性的写法和上面不同,这个是publish_id=xxx,上面是publish=xxx。
2.多对多
方式一: 多对多一般在前端页面上使用的时候是多选下拉框的样子来给用户选择多个数据,这里可以让用户选择多个书籍,多个作者
# 当前生成的书籍对象
book_obj=Book.objects.create(title="追风筝的人",price=200,publishDate="2012-11-12",publish_id=1)
# 为书籍绑定的做作者对象
yuan=Author.objects.filter(name="yuan").first() # 在Author表中主键为2的纪录,注意取的是author的model对象
egon=Author.objects.filter(name="alex").first() # 在Author表中主键为1的纪录
#有人可能会说,我们可以直接给第三张表添加数据啊,这个自动生成的第三张表你能通过models获取到吗,是获取不到的,用不了的,当然如果你知道了这个表的名字,那么你通过原生sql语句可以进行书的添加,所以要通过orm间接的给第三张表添加数据,如果是你手动添加的第三张表你是可以直接给第三张表添加数据
# 绑定多对多关系,即向关系表book_authors中添加纪录,给书添加两个作者,下面的语法就是告诉orm给第三张表添加两条数据
book_obj.authors.add(yuan,egon) # 将某些特定的 model 对象添加到被关联对象集合中。 ======= book_obj.authors.add(*[])
#book_obj是书籍对象,authors是book表里面那个多对多的关系字段名称。
#其实orm就是先通过book_obj的authors属性找到第三张表,然后将book_obj的id值和两个作者对象的id值组合成两条记录添加到第三张表里面去
方式二
book_obj.authors.add(1,2)
book_obj.authors.add(*[1,2]) #这种方式用的最多,因为一般是给用户来选择,用户选择是多选的,选完给你发送过来的就是一堆的id值
删除:
book_obj = models.Book.objects.filter(nid=4)[0]
# book_obj.authors.remove(2) #将第三张表中的这个book_obj对象对应的那个作者id为2的那条记录删除
# book_obj.authors.clear()
# book_obj.authors.set('2') #先清除掉所有的关系数据,然后只给这个书对象绑定这个id为2的作者,所以只剩下一条记录 3---2,比如用户编辑数据的时候,选择作者发生了变化,那么需要重新选择,所以我们就可以先清空,然后再重新绑定关系数据,注意这里写的是字符串,数字类型不可以
一对一和一对多的删改和单表的删改是一样的
修改:
book_obj = models.Book.objects.get(id=1) #获取一个书籍对象
data = {'title':'xxx','price':100} #这个书籍对象更新后的数据
models.Book.objects.filter(id=n).update(**data) #将新数据更新到原来的记录中
book_obj.authors.set(author_list) #将数据和作者的多对多关系加上
查询:
一对多查询
python
正向查询:
关联属性字段所在的表查询被关联表的记录就是正向查询
例子:
book_obj=Book.objects.filter(pk=1).first()book对象.外键字段名称
book_obj.publish.city
反向查询:
被关联表的记录查询关联属性字段所在的表
例子:
publish=Publish.objects.get(name="苹果出版社")
publish.book_set.all() : 与苹果出版社关联的所有书籍对象集合,
写法:小写的表名_set.all(),得到queryset类型数据
2.一对一查询
python 正向查询: egon=Author.objects.filter(name="egon").first() egon.authorDetail.telephone :作者对象.字段名
¨K116K
反向查询(按表名:author):不需要_set,因为一对一正向反向都是找到一条记录
authorDet=AuthorDetail.objects.filter(addr="beijing")[0]
authorDet.author.name
3.多对多查询
类中结构指定related_name : publish = ForeignKey(Book, related_name='bookList') # 查询 人民出版社出版过的所有书籍 publish=Publish.objects.get(name="人民出版社") publish.bookList.all() # 与人民出版社关联的所有书籍对象集合
#### 4.基于双下划线的跨表查询(基于join实现的)
说明:正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表,一对一、一对多、多对多都是一个写法,注意,我们写orm查询的时候,哪个表在前哪个表在后都没问题,因为走的是join连表操作。
python 1.一对多查询 查询苹果出版社出版过的所有书籍的名字与价格(一对多) # 正向查询 按字段:publish queryResult=Book.objects.filter(publish__name="苹果出版社") #通过__告诉orm将book表和publish表进行join,然后找到所有记录中publish.name='苹果出版社'的记录(注意publish是属性名称),然后select book.title,book.price的字段值.values_list("title","price") #values或者values_list # 反向查询 按表名:book queryResult=Publish.objects.filter(name="苹果出版社").values_list("book__title","book__price")
2.多对多查询
查询yuan出过的所有书籍的名字(多对多)
# 正向查询 按字段:authors:
queryResult=Book.objects.filter(authors__name="yuan").values_list("title")
# 反向查询 按表名:book
queryResult=Author.objects.filter(name="yuan")
.values_list("book__title","book__price")
3.一对一查询
# 查询yuan的手机号
# 正向查询
Author.objects.filter(name="yuan").values("authordetail__telephone")
# 反向查询
AuthorDetail.objects.filter(author__name="yuan").values("telephone")
¨K119K
.values_list("title","authors__name")
# 反向查询
queryResult=Publish.objects.filter(name="人民出版社")
.values_list("book__title","book__authors__age","book__authors__name")
¨K120K
.values_list("title","publish__name")
# 方式2:
Author.objects.filter(authordetail__telephone__startswith="151")
.values("book__title","book__publish__name")
4.related_name
反向查询时,如果定义了related_name ,则用related_name替换 表名,例如:
publish = ForeignKey(Blog, related_name='bookList')
查询人民出版社出版过的所有书籍的名字与价格(一对多)
¨K121K
.values_list("bookList__title","bookList__price")
#### 5.聚合查询,分组查询,F查询和Q查询
###### 聚合查询aggregate(args,*kwargs)
python #它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它 from django.db.models import Avg, Max, Min models.Book.objects.all().aggregate(Avg('price')) models.Book.objects.all().aggregate(Min("price")) models.Book.objects.all().aggregate(Max("price"))
###### 分组查询
python -----单表查询------ #annotate里面必须写个聚合函数,不然没有意义,并且必须有个别名=,别名随便写,但是必须有,用哪个字段分组,values里面就写哪个字段,annotate其实就是对分组结果的统计 SQL:select price,Count(*) from book group by price; ORM:Book.objects.values("price").annotate(c=Count("nid")) -----多表查询------- 跨表分组查询本质就是将关联表join成一张表,再按单表的思路进行分组查询,,既然是join连表,就可以使用咱们的双下划线进行连表 -----------------案例------------------- Publish.objects.annotate(MinPrice=Min("book__price"))
###### F查询
python #用F()查询将表中的连个字段作比较,F可以取字段 # 查询评论数大于收藏数的书籍 from django.db.models import F Book.objects.filter(commentNum__lt=F('keepNum')) # 查询评论数大于收藏数2倍的书籍 Book.objects.filter(commentNum__lt=F('keepNum')*2) #修改操作也可以使用F函数,比如将每一本书的价格提高30元: Book.objects.all().update(price=F("price")+30)
###### Q查询
python #Q 对象可以使用&(与) 、|(或)、~(非) 操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。
SQL:Author.objects.filter(Q(name='ales')|Q(name='egon')).first().name
ORM:select name from app01_author where name='ales' or name='egon'
##### 补充:直接执行自定义SQL
python 有时候raw()方法并不十分好用,很多情况下我们不需要将查询结果映射成模型,或者我们需要执行DELETE、 INSERT以及UPDATE操作。在这些情况下,我们可以直接访问数据库,完全避开模型层。 我们可以直接从django提供的接口中获取数据库连接,然后像使用pymysql模块一样操作数据库。
from django.db import connection, connections
cursor = connections['default'].cursor()
cursor = connection.cursor()
cursor.execute("""SELECT * from auth_user where id = %s""", [1])
ret = cursor.fetchone()
## 5.DjangoORM优化
### QuerySet
python 1.可切片:Book.objects.all()[0:2] 2.可迭代:for i in Book.objects.all():print(i.title) 3.缓存机制 : 让查询结果缓存起来,book_obj = Book.objects.all(),减少访问数据库的负载 4.exists()方法: if book_obj.exists():print("keep go"); 5.iterator()方法: 处理成千上万的记录时,将它们一次装入内存是很浪费的。避免在遍历数据的同时产生queryset cache。使用iterator()用来获取数据,处理完数据就将其丢弃。 book_obj = Book.objects.all().iterator() 6.总结: queryset的cache是用于减少程序对数据库的查询,在通常的使用下会保证只有在需要的时候才会查询数据库。 使用exists()和iterator()方法可以优化程序对内存的使用。不过,由于它们并不会生成queryset cache,可能 会造成额外的数据库查询。
### 使用select_related查询优化‘
python 1.意义:对于一对一字段(OneToOneField)和外键字段(ForeignKey),可以使用select_related 来对QuerySet进行优化。
2.作用:在对QuerySet使用select_related()函数后,Django会获取相应外键对应的对象,从而在之后需要的时候不必再查询数据库了
--------------------------------例子--------------------------------------
Book.objects.select_related("publish").first().name
优于
Book.objects.filter(nid=1).publish.name
查询速度
3.总结:
select_related主要针一对一和多对一关系进行优化。
select_related使用SQL的JOIN语句进行优化,通过减少SQL查询的次数来进行优化、提高性能。
可以通过可变长参数指定需要select_related的字段名。也可以通过使用双下划线“__”连接字段名来实现指定的递归查询。
没有指定的字段不会缓存,没有指定的深度不会缓存,如果要访问的话Django会再次进行SQL查询。
也可以通过depth参数指定递归的深度,Django会自动缓存指定深度内所有的字段。如果要访问指定深度外的字段,Django会再次进行SQL查询。
也接受无参数的调用,Django会尽可能深的递归查询所有的字段。但注意有Django递归的限制和性能的浪费。
Django >= 1.7,链式调用的select_related相当于使用可变长参数。Django < 1.7,链式调用会导致前边的select_related失效,只保留最后一个。
### 使用prefetch_related()查询优化
python 1.意义:对于多对多字段(ManyToManyField)和一对多字段,可以使用prefetch_related()来进行优化
2.作用:分别查询每个表,然后用Python处理他们之间的关系。
----------------案例---------------
article_obj=models.Article.objects.prefetch_related("tags").all()
优于
article_obj=models.Article.objects.all()
查询速度
#### prefetch_related()和select_related()区别:
prefetch_related()和select_related()的设计目的很相似,都是为了减少SQL查询的数量,但是实现的方式不一样。后者是通过JOIN语句,在SQL查询内解决问题。但是对于多对多关系,使用SQL语句解决就显得有些不太明智,因为JOIN得到的表将会很长,会导致SQL语句运行时间的增加和内存占用的增加。若有n个对象,每个对象的多对多字段对应Mi条,就会生成Σ(n)Mi 行的结果表。
#### 使用extra方法实现复杂SQL语句
意义:Django的查询语法难以简单的表达复杂的 WHERE
子句,对于这种情况, Django 提供了 extra()
QuerySet
修改机制 — 它能在 QuerySet
生成的SQL从句中注入新子句
Author.objects.extra(select={'name':"1"})
Author.objects.extra(where=['name="alex"'])
#### 使用bulk_create()整体插入减少插入语句的数量。
python user_list = [ models.User(name='alex'), models.User(name='mick'), models.User(name='python') ] models.User.objects.bulk_create(user_list)
### ORM事务控制
python 1.全局事务(!!!不推荐): 统一个http请求对应的所有sql都放在一个事务中执行(要么所有都成功,要么所有都失败)。是全局性的配置, 如果要对某个http请求放水(然后自定义事务),可以用non_atomic_requests修饰器
2.settings配置:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'mxshop',
'HOST': '127.0.0.1',
'PORT': '3306',
'USER': 'root',
'PASSWORD': '123',
'OPTIONS': {
"init_command": "SET default_storage_engine='INNODB'",
#'init_command': "SET sql_mode='STRICT_TRANS_TABLES'", #配置开启严格sql模式
¨K122K
'other':{
'ENGINE': 'django.db.backends.mysql',
......
} #还可以配置其他数据库
}
python 1.局部使用事务(推荐): 详细:https://www.cnblogs.com/clschao/articles/10463267.html
1.Django之Ajax
Ajax (Asynchronous Javascript And XML)
作用:Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML,现在更多使用json数据)在不加载整个页面的情况下,与服务器端数据交互。
优点:使用javascript向服务器发送异步请求;
无须刷新整个页面;
性能高;
特点:浏览器页面局部刷新。
$.ajax({
headers:{"X-CSRFToken":$.cookie('csrftoken')},
#其实在ajax里面还有一个参数是headers,自定制请求头,可以将csrf_token加在这里,我们发contenttype类型数据的时候,csrf_token就可以这样加
Content-Type:
1.application/x-www-form-urlencoded
这应该是最常见的 POST 提交数据的方式了。浏览器的原生
基于ajax的文件上传
html:
views.py
def file(request):
print(request.FILES)
return
JSON概述
JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象
JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串。
2.Djano中的cookie和session
cookie
意义:因为http协议是无状态的,应声出来cookie。就是服务武器发送出来存储在浏览器端的键值对。下次访问服务器浏览器会自动携带这些键值对。一边服务器提取有用信息。
原理:浏览器访问服务端能通过Cookie的内容来判断这个是“谁”了。
django操作cookie
1.获取cookie
request.COOKIES['key']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
2.设置cookie
ret = render(request,'login.html')
ret.set_cookie(key,value)
ret.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...
3.删除cookie
ret = redirect("/login/")
ret.delete_cookie("user")
return ret
Jquery操作cookie
定义:让网站服务器把少量数据储存到客户端的硬盘或内存,从客户端的硬盘读取数据的一种技术
;
session
Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
django操作session
Django的session键值对放在django-session表中
1.获取session
request.session['k1']
request.session.get('k1',None)
2.设置session
request.session['k1'] = 123
request.session.setdefault('k1',123)
3.删除session
del request.session['k1']
4.所有 键、值、键值对
request.session.keys()
request.session.values()
request.session.items()
5.会话session的key
session_key = request.session.session_key 获取sessionid的值
6.将所有Session失效日期小于当前日期的数据删除,将过期的删除
request.session.clear_expired()
7.检查会话session的key在数据库中是否存在
request.session.exists("session_key") #session_key就是那个sessionid的值
8.删除当前会话的所有Session数据
request.session.delete()
9.删除当前的会话数据并删除会话的Cookie。
request.session.flush() #常用,清空所有cookie---删除session表里的这个会话的记录,
这用于确保前面的会话数据不可以再次被用户的浏览器访问
例如,django.contrib.auth.logout() 函数中就会调用它。
10.设置会话Session和Cookie的超时时间
request.session.set_expiry(value)
* 如果value是个整数,session会在些秒数后失效。
* 如果value是个datatime或timedelta,session就会在这个时间后失效。
* 如果value是0,用户关闭浏览器session就会失效。
* 如果value是None,session会依赖全局session失效策略。
django-session流程
django-session配置
1. 数据库Session
SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)
2. 缓存Session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
3. 文件Session
SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()
4. 缓存+数据库
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎
5. 加密Cookie Session
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎
其他公用设置项:
SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
3.Django中间件
说明:介于request与response之间的的一道处理过程。在django全局上改变输入与输出。在view视图函数执行之前和执行之后的额外操作,
流程:多个中间件中的process_response方法是按照MIDDLEWARE中的注册顺序倒序执行的,也就是说第一个中间件的process_request方法首先执行,而它的process_response方法最后执行,最后一个中间件的process_request方法最后一个执行,它的process_response方法是最先执行。
应用场景:IP访问频率限制;URL访问过滤;登录校验;
自定义中间件
#自创建py文件。继承MiddlewareMixin类
--------------------------------md1.py-----------------------------------
from django.utils.deprecation import MiddlewareMixin
class Mymiddleware(MiddlewareMixin):
def process_request(self, request):
print('request方法说明请求来了要处理')
pass
def process_response(self, request, response):
print('response方法说明响应出去时需要处理')
return response
------------------------------settings.py---------------------------------
#注册中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'utils.md1.Mymiddleware'
]
process_request参数
它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
process_response参数
必须return response,不然上层的中间件就没有拿到Httpresponse对象,就会报错
process_view
它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,Django不会调用对应的视图函数。 它将执行中间件的process_response方法并将应用到该HttpResponse并返回结果。
process_exception
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
process_template_response
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
中间件请求流程
说明:
请求到达中间件之后,先按照正序执行每个注册中间件的process_reques方法,process_request方法返回的值是None,就依次执行,如果返回的值是HttpResponse对象,不再执行后面的process_request方法,而是执行当前对应中间件的process_response方法,将HttpResponse对象返回给浏览器。也就是说:如果MIDDLEWARE中注册了6个中间件,执行过程中,第3个中间件返回了一个HttpResponse对象,那么第4,5,6中间件的process_request和process_response方法都不执行,顺序执行3,2,1中间件的process_response方法。
4.Django中的Form和ModelForm组件
Form组件
1.前端页面是form类的对象生成的 -->生成HTML标签功能
2.当用户名和密码输入为空或输错之后 页面都会提示 -->用户提交校验功能
3.当用户输错之后 再次输入 上次的内容还保留在input框 -->保留上次输入内容
注册实例
----------自创建form.py--------
from django import forms
class MyForm(forms.Form):
username = forms.CharField(label='用户名',max_length=10,min_length=2,error_messages={'min_length':'太短了'})
password = forms.CharField(label='密码',max_length=20)
----------register.html-------------
---------------views.py------------------
from .form import MyForm
def register(request):
#保存上次输入的结果
form_obj = MyForm()
if request.method =='POST':
form_obj = MyForm(data=request.POST)
#数据校验成功跳转到index
if form_obj.is_valid():
return redirect('/index/')
return render(request,'register.html',{'form_obj':form_obj})
Form组件常用字段与插件
1.initial:初始值,input框里的初始值
2.errror_messages : 自定义错误信息
3.passowrd :
passowrd = forms.CharField(
min_length=6,
label="密码",
widget=forms.widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True) )#这个密码字段和其他字段不一样,默认在前端输入数据错误的时候,点击提交之后,默认是不保存的原来数据的,但是可以通过这个render_value=True让这个字段在前端保留用户输入的数据
4.radioSelect:单radio值为字符串
gender = forms.ChoiceField(
choices=((1, "男"), (2, "女"), (3, "保密")),
label="性别",
widget=forms.widgets.RadioSelect()
)
5.单选Select:
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=3,
widget=forms.widgets.Select()
)
6.多选Select:
hobby = forms.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"), ),
label="爱好",
initial=[1, 3],
widget=forms.widgets.SelectMultiple()
)
7.单选checkbox:
keep = forms.ChoiceField(
label="是否记住密码",
initial="checked",
widget=forms.widgets.CheckboxInput()
)
8.多选checkbox:
hobby = forms.fields.MultipleChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
label="爱好",
initial=[1, 3],
widget=forms.widgets.CheckboxSelectMultiple()
)
9.date类型
from django import forms
from django.forms import widgets
class BookForm(forms.Form):
date = forms.DateField(widget=widgets.TextInput(attrs={'type':'date'})) #必须指定type,不然不能渲染成选择时间的input框
form组件类参数:
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
IntegerField(Field)
max_value=None, 最大值
min_value=None, 最小值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, 最大值
min_value=None, 最小值
max_digits=None, 总长度
decimal_places=None, 小数位长度
BaseTemporalField(Field)
input_formats=None 时间格式化
DateField(BaseTemporalField) 格式:2015-09-01
TimeField(BaseTemporalField) 格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
DurationField(Field) 时间间隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, 自定制正则表达式
max_length=None, 最大长度
min_length=None, 最小长度
error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False 是否允许空文件
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val 对选中的值进行一次转换
empty_value= '' 空值的默认值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val 对选中的每一个值进行一次转换
empty_value= '' 空值的默认值
ComboField(Field)
fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式
fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中
path, 文件夹路径
match=None, 正则匹配
recursive=False, 递归下面的文件夹
allow_files=True, 允许文件
allow_folders=False, 允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', both,ipv4,ipv6支持的IP格式
unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) 数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) uuid类型
自定义form字段:
class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
自定义校验规则:
import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
# 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误') #自定义验证规则的时候,如果不符合你的规则,需要自己发起错误
class PublishForm(Form):
title = fields.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': '标题5-20个字符'}))
# 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
email = fields.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
钩子方法(对字段校验)
局部钩子
方法:在Fom类中定义 clean_字段名() 方法,就能够实现对特定字段进行校验。
username = forms.CharField(
label='用户名',
min_length=2,
error_messages={'min_length':'必须大于2个字节'},
)
def clean_username(self):
value = self.cleaned_data['username']
if 'root' in value:
raise Exception('最好不要用root当用户名')
else:
return value
全局钩子:
方法:我们在Fom类中定义 clean() 方法,就能够实现对字段进行全局校验,字段全部验证完,局部钩子也全部执行完之后,执行这个全局钩子校验。
password = forms.CharField(label='密码',max_length=20)
re_password = forms.CharField(label='确认密码',max_length=20)
def clean(self):
pwd = self.cleaned_data['password']
re_pwd = self.cleaned_data['re_password']
if pwd != re_pwd:
#在re_password这个字段的错误列表中加上一个错误,并且clean_data里面会自动清除这个 re_password的值,所以打印clean_data的时候会看不到它
self.add_error('re_password','两次密码不一致')
raise ValueError("两次密码不一致")
else:
return self.cleaned_data
全局应用bootstrap样式和其他:
username = forms.CharField(
min_length=8,
label="用户名",
initial="张三",
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
...
def __init__(self, *args, **kwargs):
super(LoginForm, self).__init__(*args, **kwargs)
for field in iter(self.fields):
self.fields[field].widget.attrs.update({
'class': 'form-control'
})
field.error_messages = {'required':"不能为空"} #全部为空的错误信息
ModelForm使用
意义:Django 提供一个辅助类让我们以Django的models.py数据来创建Form。
作用:form与model的终极结合,会根据你model中的字段转换成对应的form字段,并且并你生成标签等操作。
例子:
-----------models.py---------------------
class Book(models.Model):
nid = models.AutoField(primary_key=True)
title = models.CharField( max_length=32)
publishDate=models.DateField()
price=models.DecimalField(max_digits=5,decimal_places=2)
publish=models.ForeignKey(to="Publish",to_field="nid")
authors=models.ManyToManyField(to='Author',)
def __str__(self):
return self.title
-----------forms.py-------------------
from .models import Book
class BookForm(forms.ModelForm):
class Meta:
model = Book
fields = '__all__'
labels = {
'title':'书名',
'price':'价格'
}
ModelForm中class Meta参数:
model = Book # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息
error_messages = {
'title':{'required':'不能为空'}
}
ModelForm的验证:
1.与普通的Form表单验证类型类似,ModelForm表单的验证在调用is_valid() 或访问errors 属性时隐式调用。
2.我们可以像使用Form类一样自定义局部钩子方法和全局钩子方法来实现自定义的校验规则。
3.如果我们不重写具体字段并设置validators属性的话,ModelForm是按照模型中字段的validators来校验的。
save()方法
>>> from myapp.models import Book
>>> from myapp.forms import BookForm
# 根据POST数据创建一个新的form对象
>>> form_obj = BookForm(request.POST)
# 创建书籍对象
>>> new_ book = form_obj.save()
# 基于一个书籍对象创建form对象
>>> edit_obj = Book.objects.get(id=1)
# 使用POST提交的数据更新书籍对象
>>> form_obj = BookForm(request.POST, instance=edit_obj)
>>> form_obj.save()
Form与ModelForm总结:
ModelsForm:功能就是把model和form组合起来。通过models字段进行判断。
1.创建数据:调用save()方法即可
2.编辑数据:instance=new_obj;obj是要修改的数据库的一条数据的对象
Form:自己写判断内容。
ModelForm简单例子
----------------------------------------forms.py-------------------------------
from django.forms import ModelForm
class StudentList(ModelForm):
class Meta:
model =Student #对应的Model中的类
fields = "__all__" #字段,如果是__all__,就是表示列出所有的字段
exclude = None #排除的字段
#error_messages用法:
error_messages = {
'name':{'required':"用户名不能为空",},
'age':{'required':"年龄不能为空",},
}
#widgets用法,比如把输入用户名的input框给为Textarea
#首先得导入模块
from django.forms import widgets as wid #因为重名,所以起个别名
widgets = {
"name":wid.Textarea(attrs={"class":"c1"}) #还可以自定义属性
}
#labels,自定义在前端显示的名字
labels= {
"name":"用户名"
}
----------------------------------------views.py-------------------------------
def student(request):
if request.method == 'GET':
student_list = StudentList()
return render(request,'student.html',{'student_list':student_list})
-------------------------------html------------------------------------------------
1.前端只需要 {{ student_list.as_p }} 一下,所有的字段就都出来了。
2.不过使用 for循环这个student_list,拿到student对象,直接在前端打印这个student,是个input框student.label ,拿到数据库中每个字段的verbose_name ,如果没有设置这个属性,拿到的默认就是字段名,还可以通过student.errors.0 拿到错误信息有了这些,我们就可以通过bootstrap,自己拼出来想要的样式了
student