安装之前注意看下自己的计算机名 是否是英文 如果是中文 安装后启动Django时极有可能报"utf-8"解码错误
终端安装:
pip install django==1.11.22 -i https://pypi.tuna.tsinghua.edu.cn/simple
启动Django:
①终端启动 (麻烦)
第一种: django-admin startproject mysite 启动: python manage.py runserver 127.0.0.1:8000
②pycharm创建(推荐)
File---new project---Django 创建Django ### Django默认端口是8000 可以手动修改 点击下拉DJango的Edit下拉框更改port
关于Pycharm激活 可以看我的另一篇博客 :https://www.cnblogs.com/wakee/p/10952062.html
'''
目录介绍
py目录:
settings.py : 用户自定义的各种配置
urls.py : 路由文件
wsgi.py : 启动socket服务端的 文件
mange.py: 管理文件 python mange.py 各种命令
__init__.py: 一般用来指定连接数据的格式问题(需要导入pymysql)
文件:
templates: 存放html的地方
static: 静态文件 js(可以包含jQuery) css img bootstrap等文件
models : ORM链接数据库py 自创的连接数据库的py文件
其他手动创建的路由分发文件
'''
1 settings中:
配置模板文件路径:'DIRS': [os.path.join(BASE_DIR, 'templates')] (一般系统自动配置好)
2:配置静态资源的文件路径:
STATIC_URL = '/static/'
### 在下面配置静态资源文件
STATICFILES_DIRS = (
os.path.join(BASE_DIR, 'static'), (逗号不能少)
)
3:注释中间件
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
#'django.middleware.csrf.CsrfViewMiddleware', (注释中间件,这是取消防止csrf攻击,后期可开启csrf攻击)
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
4:在app中__init__.py文件中
# 连接mysql数据库时指定连接
import pymysql
pymysql.install_as_MySQLdb()
wsgiref模块 帮你处理http数据 这是本地环境使用的 上线使用uwsgi
中间件 处理连接的的过程和 处理一些安全问题 比如CSRF攻击
URL系统 处理函数分发
jinja2模板语言 django用的是自己写的模板语法
flask框架 用的jinja2
官方的说法: 中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。 本质上: 本质上就是一个自定义类 ,是介于request与response处理之间的一道处理过程类中,定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
注意
但是由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。
如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
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',
]
从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下:
请求到达中间件之后,先按照正序执行每个注册中间件的process_request方法,如果process_request方法返回的值是None,就依次执行;如果返回的值是HttpResponse对象,则不再执行后面的process_request方法,而是执行当前对象中间件的process_response方法,并将HttpResponse对象返回给浏览器。
process_request方法都执行完后,匹配路由,找到要执行的视图函数,先不执行视图函数,先执行中间件中的process_view方法,process_view方法返回None,继续按顺序执行,所有process_view方法执行完后执行视图函数。假如中间件3 的process_view方法返回了HttpResponse对象,则4,5,6的process_view以及视图函数都不执行,直接从最后一个中间件,也就是中间件6的process_response方法开始倒序执行。

process_template_response和process_exception两个方法的触发是有条件的,执行顺序也是倒序。总结所有的执行流程如下:

process_request(self,request) 发送请求 process_view(self, request, callback, callback_args, callback_kwargs) 执行完 request 预处理函数并确定待执行的 view 之后,但在 view 函数实际执行之前。 process_template_response(self,request,response) response参数应该是一个由view或者中间件返回的TemplateResponse对像(或等价的对象)。如果响应的实例有render()方法,process_template_response()会在view刚好执行完毕之后被调用。这个方法必须返回一个实现了render方法的响应对象。 process_exception(self, request, exception) 收集错误信息,当一个view引发异常时,Django会调用 process_exception()来处理。返回一个None或一个HttpResponse对象。如果返回HttpResponse对象,会将响应交给处理响应的中间件处理。由于处理响应时是从下到上的,此层以上的process_exception()是不会被调用的。 process_response(self, request, response) 必须返回 HttpResponse 对象。这个 response 对象可以是传入函数的那一个原始对象(通常已被修改),也可以是全新生成的。 执行顺序也是按照以上顺序执行的。
process_request
执行时间: 在视图函数之前,在路由匹配之前 参数: request:请求对象,与视图中用到的request参数是同一个对象 返回值: None:按照正常的流程走 HttpResponse:接着倒序执行当前中间件的以及之前执行过的中间件的process_response方法,不再执行其它的所有方法 执行顺序: 按照MIDDLEWARE中的注册的顺序执行,也就是此列表的索引值
process_response
执行时间: 最后执行 参数: request:请求对象,与视图中用到的request参数是同一个对象 response:响应对象,与视图中返回的response是同一个对象 返回值: response:必须返回此对象,按照正常的流程走 执行顺序: 按照注册的顺序倒序执行
process_view
执行时间: 在process_request方法及路由匹配之后,视图之前 参数: request:请求对象,与视图中用到的request参数是同一个对象 view_func:将要执行的视图函数(它是实际的函数对象,而不是函数的名称作为字符串) view_args:url路径中将传递给视图的位置参数的元组 view_kwargs:url路径中将传递给视图的关键值参数的字典 返回值: None:按照正常的流程走 HttpResponse:它之后的中间件的process_view,及视图不执行,执行所有中间件的process_response方法 执行顺序: 按照注册的顺序执行
process_exception
执行时间: 视图之后,process_response之前 参数: request:请求对象,与视图中用到的request参数是同一个对象 exception:视图函数异常产生的Exception对象 返回值: None:按照正常的流程走 HttpResponse对象:不再执行后面的process_exception方法 执行顺序: 按照注册的顺序倒序执行
process_template_response
此方法必须在视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)时,才被执行.
执行时间: 视图之后,process_exception之前 参数: request:请求对象,与视图中用到的request参数是同一个对象 response:是TemplateResponse对象(由视图函数或者中间件产生) 返回值: response:必须返回此对象,按照正常的流程走 执行顺序: 按照注册的顺序倒序执行
from django.utils.deprecation import MiddlewareMixin
第二步自定义
from django.utils.deprecation import MiddlewareMixin
# from django.http import HttpResponse
from django.shortcuts import HttpResponse, redirect
# 方式一:
class MyMiddleware(MiddlewareMixin):
def process_request(self, request):
next_url = request.path_info
if not request.path_info.startswith("/login/"):
# 做登录验证
login_flag = request.session.get("login", "")
if not login_flag:
return redirect("/login/?next={}".format(next_url))
def process_view(self, request, view_func, view_args, view_kwargs):
pass
def process_exception(self, request, exception):
if isinstance(exception, ValueError):
return HttpResponse("404")
def process_response(self, request, response):
return response
# 方式二:
class SimpleMiddleware(object):
def __init__(self, get_response):
self.get_response = get_response
# 一次性配置和初始化。
def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called.
# 这里写的代码会在视图被调用前执行来处理请求
response = self.get_response(request)
# 这里写的代码会在视图调用后执行来处理响应
# Code to be executed for each request/response after
# the view is called.
return response
def process_view(self, request, view_func, view_args, view_kwargs):
pass
def process_exception(self, request, exception):
pass
def process_template_response(self, request, response):
pass
第三步 中间件注册
# 在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',
'mymiddlewares.middlewares.MyMiddleware',
'mymiddlewares.middlewares.SimpleMiddleware',
]
路由定义
路由即请求地址与视图函数的映射关系,如果把网站比喻为一本书,那路由就好比是这本书的目录,在Django中路由默认配置在urls.py中,如下图:

# urls.py
from django.conf.urls import url
# 由一条条映射关系组成的urlpatterns这个列表称之为路由表
urlpatterns = [
url(regex, view, kwargs=None, name=None), # url本质就是一个函数
]
#函数url关键参数介绍
# regex:正则表达式,用来匹配url地址的路径部分,
# 例如url地址为:http://127.0.0.1:8001/index/,正则表达式要匹配的部分是index/
# view:通常为一个视图函数,用来处理业务逻辑
# kwargs:略(用法详见有名分组)
# name:略(用法详见反向解析)
注意
''' 当APPEND_SLASH=True(如果配置文件中没有该配置,APPEND_SLASH的默认值为True),并且用户请求的url地址的路径部分不是以 / 结尾,第一次请求之后没有发现路径会在请求路径后面加/ 再去匹配一次 当APPEND_SLASH=False时 默认就匹配一次 不成功不会加/再次匹配 '''
无名分组
在普通的正则匹配中加上()就是无名分组
urls.py文件
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 该正则会匹配url地址的路径部分为:article/数字/,匹配成功的分组部分会以关键字参数(article_id=匹配成功的数字)的形式传给视图函数,有几个有名分组就会传几个关键字参数
url(r'^aritcle/(?P<article_id>d+)/$',views.article),
]
views.py文件
from django.shortcuts import render
from django.shortcuts import HttpResponse
# 需要额外增加一个形参,形参名必须为article_id
def article(request,article_id):
return HttpResponse('id为 %s 的文章内容...' %article_id)
测试:
python manage.py runserver 8001 # 在浏览器输入:http://127.0.0.1:8001/article/3/ 会看到: id为 3 的文章内容...
有名分组
有名分组其实就是在无名的分组的基础上加上了名字
语法为:(?P<名字> 正则表达式),就是在无名分组的括号里面加上了?P<名字>,注意其中P为大写
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 该正则会匹配url地址的路径部分为:article/数字/,匹配成功的分组部分会以关键字参数(article_id=匹配成功的数字)的形式传给视图函数,有几个有名分组就会传几个关键字参数
url(r'^aritcle/(?P<article_id>d+)/$',views.article),
]
区别
区别在于无名分组是以位置参数的形式传递,有名分组是以关键字参数的形式传递
路由分发
1 创建两个app
# 新建项目mystie2 E:git>django-admin startproject mysite2 # 切换到项目目录下 E:git>cd mysite2 # 创建app01和app02 E:gitmysite2>python3 manage.py startapp app01 E:gitmysite2>python3 manage.py startapp app02
2 在每个app下手动创建urls.py来存放自己的路由,如下:
from django.conf.urls import url
# 导入app01的views
from app01 import views
urlpatterns = [
url(r'^index/$',views.index),
]
app01下的views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse
def index(request):
return HttpResponse('我是app01的index页面...')
app02下的urls.py文件
from django.conf.urls import url
# 导入app02的views
from app02 import views
urlpatterns = [
url(r'^index/$',views.index),
]
app02下的views.py
from django.shortcuts import render
from django.shortcuts import HttpResponse
def index(request):
return HttpResponse('我是app02的index页面...')
3 在总的urls.py文件中(mysite2文件夹下的urls.py)
from django.conf.urls import url,include
from django.contrib import admin
# 总路由表
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 新增两条路由,注意不能以$结尾
# include函数就是做分发操作的,当在浏览器输入http://127.0.0.1:8001/app01/index/时,会先进入到总路由表中进行匹配,正则表达式r'^app01/'会先匹配成功路径app01/,然后include功能会去app01下的urls.py中继续匹配剩余的路径部分
url(r'^app01/', include('app01.urls')),
url(r'^app02/', include('app02.urls')),
]
测试
python manage.py runserver 8001 # 在浏览器输入:http://127.0.0.1:8001/app01/index/ 会看到:我是app01的index页面... # 在浏览器输入:http://127.0.0.1:8001/app02/index/ 会看到:我是app02的index页面...
反向解析
路由设置时通过别名来获取路径
案例:登录成功跳转到index.html页面
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^login/$', views.login,name='login_page'), # 路径login/的别名为login_page
url(r'^index/$', views.index,name='index_page'), # 路径index/的别名为index_page
]
在views.py
from django.shortcuts import render
from django.shortcuts import reverse # 用于反向解析
from django.shortcuts import redirect #用于重定向页面
from django.shortcuts import HttpResponse
def login(request):
if request.method == 'GET':
# 当为get请求时,返回login.html页面,页面中的{% url 'login_page' %}会被反向解析成路径:/login/
return render(request, 'login.html')
# 当为post请求时,可以从request.POST中取出请求体的数据
name = request.POST.get('name')
pwd = request.POST.get('pwd')
if name == 'kevin' and pwd == '123':
url = reverse('index_page') # reverse会将别名'index_page'反向解析成路径:/index/
return redirect(url) # 重定向到/index/
else:
return HttpResponse('用户名或密码错误')
def index(request):
return render(request, 'index.html')
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<!--强调:login_page必须加引号-->
<form action="{% url 'login_page' %}" method="post">
{% csrf_token %} <!--强调:必须加上这一行,如果中间件csrf没有注释掉-->
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h3>我是index页面...</h3>
</body>
</html>
测试
python manage.py runserver 8001 # 在浏览器输入:http://127.0.0.1:8001/login/ 会看到登录页面,输入正确的用户名密码会跳转到index.html # 当我们修改路由表中匹配路径的正则表达式时,程序其余部分均无需修改
总结:
在views.py中,反向解析的使用:
url = reverse('index_page')
在模版login.html文件中,反向解析的使用
{% url 'login_page' %}
1:获取数据
2:对数据进行处理
3:连接数据库(ORM)对数据库操作)
4:对模板进行渲染(模板系统)
django将http协议请求报文中的请求行、首部信息、内容主体封装到了HttpRequest对象中(类似于我们自定义框架的environ参数)。 django会将HttpRequest对象当做参数传给视图函数的第一个参数request,在视图函数中,通过访问该对象的属性便可以提取http协议的请求数据
一.HttpRequest.method
获取请求使用的方法(值为纯大写的字符串格式)。例如:"GET"、"POST"
应该通过该属性的值来判断请求方法
二.HttpRequest.GET
值为一个类似于字典的QueryDict对象,封装了GET请求的所有参数,可通过HttpRequest.GET.get('键')获取相对应的值
三.HttpRequest.POST
值为一个类似于字典的QueryDict对象,封装了POST请求所包含的表单数据,可通过HttpRequest.POST.get('键')获取相对应的值
针对表单中checkbox类型的input标签、select标签提交的数据,键对应的值为多个,需要用:HttpRequest.POST.getlist("hobbies")获取存有多个值的列表,
同理也有HttpRequest.GET.getlist("键")
urls.py
from django.urls import re_path
from app01 import views
urlpatterns = [
re_path(r'^login/$',views.login),
]
Views.py
from django.shortcuts import render,HttpResponse
def login(request):
if request.method == 'GET':
# 当请求url为:http://127.0.0.1:8001/login/?a=1&b=2&c=3&c=4&c=5
# 请求方法是GET,?后的请求参数都存放于request.GET中
print(request.GET)
# 输出<QueryDict: {'a': ['1'], 'b': ['2'], 'c': ['3', '4', '5']}>
# 获取?后参数的方式为
a=request.GET.get('a') # 1
b=request.GET.get('b') # 2
c=request.GET.getlist('c') # ['3', '4', '5']
return render(request,'login.html')
elif request.method == 'POST':
# 在输入框内输入用户名egon、年龄18,选择爱好,点击提交
# 请求方法为POST,表单内的数据都会存放于request.POST中
print(request.POST)
# 输出<QueryDict: {..., 'name': ['egon'], 'age': ['18'], 'hobbies': ['music', 'read']}>
# 获取表单中数据的方式为
name=request.POST.get('name') # egon
age=request.POST.get('age') # 18
hobbies=request.POST.getlist('hobbies') # ['music', 'read']
return HttpResponse('提交成功')
在templates目录下新建login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<!--
method="post"代表在提交表单时会以POST方法提交表单数据
action="/login/" 代表表单数据的提交地址为http://127.0.0.1:8001/login/,可以简写为action="/login/",或者action=""
-->
<form action="http://127.0.0.1:8001/login/" method="post">
{% csrf_token %} <!--强调:必须加上这一行,后续我们会详细介绍-->
<p>用户名:<input type="text" name="name"></p>
<p>年龄:<input type="text" name="age"></p>
<p>
爱好:
<input type="checkbox" name="hobbies" value="music">音乐
<input type="checkbox" name="hobbies" value="read">阅读
<input type="checkbox" name="hobbies" value="dancing">跳舞
</p>
<p><input type="submit" value="提交"></p>
</form>
</body>
</html>
当浏览器基于http协议的POST方法提交数据时,数据会被放到请求体中发送给django,django会将接收到的请求体数据存放于HttpRequest.body属性中,因为该属性的值为Bytes类型,所以通常情况下直接处理Bytes、并从中提取有用数据的操作是复杂而繁琐的,好在django会对它做进一步的处理与封装以便我们更为方便地提取数据,比如
1:如果表单属性method='GET',那么在提交表单时,表单内数据不会存放于请求体中,而是会将表单数据按照k1=v1&k2=v2&k3=v3的格式放到url中,然后发送给django,django会将这些数据封装到request.GET中,注意此时的request.body为空、无用
2:如果表单属性method='POST',那么在提交表单时,表单内的所有数据都会存放于请求体中,在发送给django后会封装到request.body里,此时django为了方便我们提取数据,会request.body的数据进行进一步的处理,具体如何处理呢,需要从form表单提交数据的编码格式说起:
form表单对提交的表单数据有两种常用的编码格式,可以通过属性enctype进行设置,如下
编码格式1(默认的编码格式):enctype="application/x-www-form-urlencoded"
编码格式2(使用form表单上传文件时只能用该编码):enctype="multipart/form-data"
如果form表单提交数据是按照编码格式1,那么request.body中数据的格式类似于GET方法的数据格式,如k1=v1&k2=v2,此时django会将request.body中的数据提取出来封装到request.POST中方便我们提取
如果form表单提交数据是按照编码格式2,那么request.body中数据的格式为b'------WebKitFormBoundaryKtcwuksQltpNprep Content-Disposition: form-data;......',,此时django会将request.body中的数据提取出来封装到request.POST中,将上传的文件数据专门提取出来封装到request.FILES属性中
强调:毫无疑问,编码格式2的数据量要大于编码格式1,如果无需上传文件,还是推荐使用更为精简的编码格式1
我们除了可以采用form表单向django提交数据外,还可以采用ajax技术,ajax可以提交的数据格式有:1、编码格式1 2、编码格式2 3、json,当ajax采用POST方法提交前两种格式的数据时,django的处理方案同上,但是当ajax采用POST方法提交json格式的数据时,django会将接收到的数据存放于HttpRequest.body,此时需要我们自己对HttpRequest.body属性值做反序列化操作,
具体的,我们在讲解ajax时再做具体介绍
二.HttpRequest.FILES
如果使用form表单POST上传文件的话,文件数据将包含在HttpRequest.FILES属性中。
强调:HttpRequest.FILES 只有在请求的方法为POST 且提交的<form> 带有enctype="multipart/form-data" 的情况下才会包含数据。否则,FILES 将为一个空的类似于字典的对象。
案例:form表单上传文件
from django.urls import path,register_converter,re_path
from app01 import views
urlpatterns = [
re_path(r'^register/$',views.register),
]
views.py
from django.shortcuts import render,HttpResponse
def register(request):
if request.method == 'GET':
return render(request,'register.html')
elif request.method == 'POST':
print(request.body)
# 从request.POST中获取用户名
name=request.POST.get('name')
# 从request.FILES获取文件对象
file_obj=request.FILES.get('header_img')
# 上传的文件存放于templates文件夹下
with open('templates/header.png','wb') as f:
for line in file_obj:
f.write(line)
return HttpResponse('注册成功')
在templates目录下新建register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册页面</title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data" >
{% csrf_token %}
<p>
用户名:<input type="text" name="name">
</p>
<p>
头像:<input type="file" name="header_img">
</p>
<p>
<input type="submit" value="提交">
</p>
</form>
</body>
</html>
一.HttpRequest.path 获取url地址的路径部分,只包含路径部分 二.HttpRequest.get_full_path() 获取url地址的完整path,既包含路径又包含参数部分 如果请求地址是http://127.0.0.1:8001/order/?name=egon&age=10#_label3, HttpRequest.path的值为"/order/" HttpRequest.get_full_path()的值为"/order/?name=egon&age=10"
案例:
urls.py
from django.urls import path,register_converter,re_path
from app01 import views
urlpatterns = [
re_path(r'^order',views.order),
]
views.py
from django.shortcuts import render,HttpResponse
# 针对请求的url地址:http://127.0.0.1:8001/order/?name=egon&age=10#_label3
# 从域名后的最后一个“/”开始到“?”为止是路径部分,即/order/
# 从“?”开始到“#”为止之间的部分为参数部分,即name=egon&age=10
def order(request):
print(request.path) # 结果为“/order/”
print(request.get_full_path()) # 结果为"/order/?name=egon&age=10"
return HttpResponse('order page')
一.HttpRequest.META
值为包含了HTTP协议的请求头数据的Python字典,字典中的key及期对应值的解释如下
CONTENT_LENGTH —— 请求的正文的长度(是一个字符串)。
CONTENT_TYPE —— 请求的正文的MIME类型。
HTTP_ACCEPT —— 响应可接收的Content-Type。
HTTP_ACCEPT_ENCODING —— 响应可接收的编码。
HTTP_ACCEPT_LANGUAGE —— 响应可接收的语言。
HTTP_HOST —— 客服端发送数据的目标主机与端口
HTTP_REFERER —— Referring 页面。
HTTP_USER_AGENT —— 客户端使用的软件版本信息
QUERY_STRING —— 单个字符串形式的查询字符串(未解析过的形式)。
REMOTE_ADDR —— 客户端的IP地址。
REMOTE_HOST —— 客户端的主机名。
REMOTE_USER —— 服务器认证后的用户。
REQUEST_METHOD —— 一个字符串,例如"GET" 或"POST"。
SERVER_NAME —— 服务器的主机名。
SERVER_PORT —— 服务器的端口(是一个字符串)。
从上面可以看到,除 CONTENT_LENGTH 和 CONTENT_TYPE 之外,HTTP协议的请求头数据转换为 META 的键时,
都会
1、将所有字母大写
2、将单词的连接符替换为下划线
3、加上前缀HTTP_。
所以,一个叫做 X-Bender 的头部将转换成 META 中的 HTTP_X_BENDER 键。
注意:下述常用属性暂且了解即可,待我们讲到专门的知识点时再专门详细讲解
二.HttpRequest.COOKIES
一个标准的Python 字典,包含所有的cookie。键和值都为字符串。
三.HttpRequest.session
一个既可读又可写的类似于字典的对象,表示当前的会话。只有当Django 启用会话的支持时才可用。
11.HttpRequest.user(用户认证组件下使用)
一个 AUTH_USER_MODEL 类型的对象,表示当前登录的用户。
2.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') 装饰你的视图以让响应能够正确地缓存
from django.shortcuts import HttpResponse,render,redirect # 导入相关包
括号内直接跟一个具体的字符串作为响应体,比较直接很简单,所以这里主要介绍后面两种形式。
render(request, template_name[, context])
参数:
1、request:用于生成响应的请求对象,固定必须传入的第一个参数
2、template_name:要使用的模板的完整名称,必须传入,render默认会去templates目录下查找模板文件
3、context:可选参数,可以传入一个字典用来替换模块文件中的变量
综上,render的功能可以总结为:根据给定字典渲染模板文件,并返回一个渲染后的 HttpResponse对象。
# 返回重定向信息
def my_view(request):
...
return redirect('/some/url/')
# 重定向的地址也可以是一个完整的URL:
def my_view(request):
...
return redirect('http://www.baidu.com/')
向前端返回一个json格式字符串的两种方式
import json
def my_view(request):
data=['egon','kevin']
return HttpResponse(json.dumps(data) )
方式二
from django.http import JsonResponse
def my_view(request):
data=['egon','kevin']
return JsonResponse(data,safe=False)
#默认safe=True代表只能序列化字典对象,safe=False代表可以序列化字典以外的对象
django的视图层由两种形式构成:FBV和CBV
1、FBV基于函数的视图(Function base view),我们之前一直介绍的都是FBV
2、CBV基于类的视图(Class base view)
案例:
urls.py
from django.urls import path,register_converter,re_path
from app01 import views
urlpatterns = [
re_path(r'^login/',views.LoginView.as_view()), # 必须调用类下的方法as_view
]
views.py
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
class LoginView(View):
def dispatch(self, request, *args, **kwargs): # 可在该方法内做一些预处理操作
# 当请求url为:http://127.0.0.1:8008/login/会先触发dispatch的执行
# 如果http协议的请求方法为GET,则调用下述get方法
# 如果http协议的请求方法为POST,则调用下述post方法
obj=super().dispatch(request, *args, **kwargs) # 必须继承父类的dispatch功能
return obj # 必须返回obj
def get(self,request):
return render(request,'login.html')
def post(self,request):
name=request.POST.get('name')
pwd=request.POST.get('pwd')
if name == 'egon' and pwd == '123':
res='登录成功'
else:
res='用户名或密码错误'
return HttpResponse(res)
测试
python manage.py runserver 8001 # 验证GET请求:在浏览器输入:http://127.0.0.1:8001/login/ # 验证POST请求:在表单内输入数据然后提交
一、变量:{{ 变量名 }}
1.1 深度查询:句点符的应用
1.2 过滤器
二、标签:{% 标签名 %}
三、自定义标签和过滤器
四、模板的导入和继承
2.1 变量的基本使用
如果html代码中的数据不是固定死的,而是动态变化的,则必须在html中嵌入变量,为此,模板语法提供了变量的概念,允许我们在html代码中嵌入变量,我们只需要在视图函数中用render方法为html文件中指定的变量赋值即可,具体用法如下
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>{{ msg }}</p>
<p>{{ dic }}</p>
<p>{{ obj }}</p>
<p>{{ li }}</p>
</body>
</html>
我们需要在视图函数中为模板test.html的变量名msg、li、dic、obj、obj_li赋值,views.py内容如下
from django.shortcuts import render
def test(request):
# 传给模板的变量值可以是任意python类型,如下
msg='hello world'
dic={'k1':1,'k2':2}
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
obj=Person('egon',18)
li = [1,'aaa',obj]
return render(request,'test.html',{'msg':msg,'dic':dic,'obj':obj,'li':li})
# 注意:
# 1、render函数的第三个参数包含了要传给模板的变量值,是一个字典类型,该字典中的key必须与模板文件中的变量名相对应,render函数会去templates目录下找到模板文件,
然后根据字典中的key对应到模板文件中的变量名进行赋值操作,最后将赋值后的模板文件内容返回给浏览器
# 2、可以将render函数的第三个参数简写为locals(),如下
return render(request,'test.html',locals()) #locals()会将函数test内定义的名字与值转换为字典中的k与v
2.2 深度查询之句点符的使用
当视图函数传给模板的值中包含多个元素时,若想取出其中的单个元素,就必须使用句点符了。
句点符既可以引用容器类型的元素,也可以引用对象的方法,如下
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--调用字符串对象的upper方法,注意不要加括号-->
<p>{{ msg.upper }}</p>
<!--取字典中k1对应的值-->
<p>{{ dic.k1 }}</p>
<!--取对象的name属性-->
<p>{{ obj.name }}</p>
<!--取列表的第2个元素,然后变成大写-->
<p>{{ li.1.upper }}</p>
<!--取列表的第3个元素,并取该元素的age属性-->
<p>{{ li.2.age }}</p>
</body>
</html>
2.3 过滤器
过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后再显示,具体语法如下
{{ 变量名|过滤器名:传给过滤器的参数 }}
常用内置过滤器
#1、default
#作用:如果一个变量值是False或者为空,使用default后指定的默认值,否则,使用变量本身的值,如果value=’‘则输出“nothing”
{{ value|default:"nothing" }}
#2、length
#作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那么输出是4
{{ value|length }}
#3、filesizeformat
#作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是 12312312321,输出将会是 11.5 GB
{{ value|filesizeformat }}
#4、date
#作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
{{ value|date:"Y-m-d" }}
#5、slice
#作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg"
{{ value|slice:"0:2" }}
#6、truncatechars
#作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,如果value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点
{{ value|truncatechars:8 }}
#7、truncatewords
#作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”hello world egon 嘎嘎“,则输出"hello world ..."
{{ value|truncatewords:2 }}
#8、safe
#作用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转义,例如value="<script>alert(123)</script>",模板变量{{ value }}会被渲染成<script>alert(123)</script>交给浏览器后会被解析成普通字符”<script>alert(123)</script>“,失去了js代码的语法意义,但如果我们就想让模板变量{{ value }}被渲染的结果又语法意义,那么就用到了过滤器safe,比如value='<a href="https://www.baidu.com">点我啊</a>',在被safe过滤器处理后就成为了真正的超链接,不加safe过滤器则会当做普通字符显示’<a href="https://www.baidu.com">点我啊</a>‘
{{ value|safe }}
标签是为了在模板中完成一些特殊功能,语法为{% 标签名 %},一些标签还需要搭配结束标签 {% endtag %}
3.1 常用标签之for标签
#1、遍历每一个元素:
{% for person in person_list %}
<p>{{ person.name }}</p>
{% endfor %}
#2、可以利用{% for obj in list reversed %}反向循环。
#3、遍历一个字典:
{% for key,val in dic.items %}
<p>{{ key }}:{{ val }}</p>
{% endfor %}
#4、循环序号可以通过{{ forloop }}显示
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是第一次循环则返回True,否则返回False
forloop.last 当前循环是最后一次循环则返回True,否则返回False
forloop.parentloop 本层循环的外层循环
#5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子句
{% for person in person_list %}
<p>{{ person.name }}</p>
{% empty %}
<p>sorry,no person here</p>
{% endfor %}
案例
url.py
from django.urls import re_path
from app01 import views
urlpatterns = [
re_path(r'^test/',views.test)
]
view.py
def test(request):
names=['egon','kevin']
dic={'name':'egon','age':18,'sex':'male'}
list1=[]
return render(request,'test.html',locals())
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<hr>
{% for name in names %}
<p>{{ forloop.counter0 }} {{ name }}</p>
{% endfor %}
<!--
输出结果为:
0 egon
1 kevin
-->
<hr>
{% for name in names reversed %}
<p>{{ forloop.revcounter0 }} {{ name }}</p>
{% endfor %}
<!--
输出结果为:
1 kevin
0 egon
-->
<hr>
{% for k,v in dic.items %}
<p>{{ forloop.counter }} {{ k }} {{ v }}</p>
{% endfor %}
<!--
输出结果为:
1 name egon
2 age 18
3 sex male
-->
<hr>
{% for item in list1 %}
<p>{{ item }}</p>
{% empty %}
<p>sorry,no value here</p>
{% endfor %}
<!--
输出结果为:
sorry,no value here
-->
</body>
</html>
3.2 常用标签之if标签
# 1、注意:
{% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,在变量值为空、或者视图没有为其传值的情况下均为False
# 2、具体语法
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>凑活吧</p>
{% endif %}
#3、if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
案例
from django.urls import path,register_converter,re_path
from app01 import views
urlpatterns = [
# 输入http://127.0.0.1:8008/或者http://127.0.0.1:8008/index/都会转发给视图函数index
re_path(r'^$',views.index),
re_path(r'^index/$',views.index),
re_path(r'^login/',views.login),
]
views.py
from django.shortcuts import render
def index(request):
return render(request,'index.html')
def login(request):
if request.method == 'GET':
return render(request,'login.html')
name=request.POST.get('name')
pwd=request.POST.get('pwd')
if name == 'egon' and pwd == '123':
current_user=name
return render(request,'index.html',locals())
else:
msg='账号或密码错误'
return render(request,'login.html',locals())
在templates目录下新建模板文件index.html与login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h3>首页</h3>
<!--
如果用户已经登录,则current_user变量有值,if判断结果为真,会打印变量current_user的值,为当前登录的用户名
如果用户没有登录,则current_user变量无值,if判断结果为假,会打印a标签要求用户先登录
-->
{% if current_user %}
<p>当前登录用户为:{{ current_user }}</p>
{% else %}
<p><a href="/login/">请先登录</a></p>
{% endif %}
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<form action="" method="POST">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
<!--输错账号密码时的提示信息-->
<p style="color: red">{{ msg }}</p>
</body>
</html>
3.3 常用标签之with标签
# with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取变量的值
{% with li.1.upper as v %}
{{ v }}
{% endwith %
3.4 常用标签之csrf_token标签
# 当用form表单提交POST请求时必须加上标签{% csrf_token%},该标签用于防止跨站伪造请求
<form action="" method="POST">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
# 具体工作原理为:
# 1、在GET请求到form表单时,标签{% csrf_token%}会被渲染成一个隐藏的input标签,该标签包含了由服务端生成的一串随机字符串,如<input type="hidden" name="csrfmiddlewaretoken" value="dmje28mFo...OvnZ5">
# 2、在使用form表单提交POST请求时,会提交上述随机字符串,服务端在接收到该POST请求时会对比该随机字符串,对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份
当内置的过滤器或标签无法满足我们需求时,我们可以自定义,具体操作步骤如下
1、在settings中的INSTALLED_APPS添加当前app的名字,不然django无法找到自定义的过滤器或标签
settings.py
# 在settings.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', # 添加当前app的名字
]
2、在文件夹app01中创建子文件夹templatetags(文件夹名只能是templatetags)
from django import template
register = template.Library() # 注意变量名必须为register,不可改变
#1、自定义过滤器
@register.filter
def my_multi_filter(v1 ,v2): # 自定义的过滤器只能定义最多两个参数,针对{{ value1 | filter_multi:value2 }},参数传递为v1=value1,v2=value2
return v1 * v2
#2、自定义标签
@register.simple_tag
def my_multi_tag(v1, v2): # 自定义的标签可以定义多个参数
return v1 * v2
#3、自定义标签扩展之mark_safe
# 注释:我们可以用内置的标签safe来让标签内容有语法意义,如果我们想让自定义标签处理的结果也有语法意义,则不能使用内置标签safe了,需要使用mark_safe,可以实现与内置标签safe同样的功能
from django.utils.safestring import mark_safe
@register.simple_tag
def my_input_tag(id, name):
res = "<input type='text' id='%s' name='%s' />" % (id, name)
return mark_safe(res)
4、自定义过滤器或标签必须重新启动django方可生效
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--必须先加载存有自定义过滤器和标签的文件-->
{% load my_tags %}
<!--salary的值为10,经过滤器my_multi_filter的处理结果为120-->
{{ salary|my_multi_filter:12 }}
<!--结果为2-->
{% my_multi_tag 1 2 %}
<!--
结果为一个input标签,该表的属性id="inp1" name="username"
注意:input的属性值均为字符串类型,所以my_input_tag后的两个值均为字符串类型
-->
{% my_input_tag "inp1" "username" %}
</body>
</html>
对比自定义标签与自定义过滤器
#1、自定义过滤器只能传两个参数,而自定义标签却可以传多个参数
#2、过滤器可以用于if判断,而标签不能
{% if salary|my_multi_filter:12 > 200 %}
<p>优秀</p>
{% else %}
<p>垃圾</p>
{% endif %}
在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、block标签,详解如下
5.1、模板的导入之include标签
#作用:在一个模板文件中,引入/重用另外一个模板文件的内容,
{% include '模版名称' %}
案例:
可以把广告栏写到专门的文件里advertise.html
<div class="adv">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
</div>
然后在base.html文件中用include标签引入advertise.html文件的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
* {
margin: 0;
padding: 0;
}
.header {
height: 50px;
100%;
background-color: black;
}
</style>
</head>
<body>
<div class="header"></div>
<div class="container">
<div class="row">
<div class="col-md-3">
<!--在base.html引入advertise.html文件的内容-->
{% include "advertise.html" %}
</div>
<div class="col-md-9"></div>
</div>
</div>
</body>
</html>
5.2、模板的继承派生之extends标签、block标签
#作用:在一个模板文件中,引入/重用另外一个模板文件的内容
{% extends "模版名称" %}
# 也就是说include有的功能extends全都有,但是extends可以搭配一个block标签,用于在继承的基础上定制新的内容
Django模版引擎中最复杂且最强大的部分就是模版继承了。我们以先创建一个基本的“骨架”模版,它包含我们站点中的全部元素,并且可以定义多处blocks ,例如我们创建base.html内容如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %}自定义title名{% endblock %}
</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
* {
margin: 0;
padding: 0;
}
.header {
height: 50px;
100%;
background-color: #919191;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="header"></div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="list-group">
{% block sidebar %}
<a href="#" class="list-group-item active">服装城</a>
<a href="#" class="list-group-item">美妆馆</a>
<a href="#" class="list-group-item">超市</a>
<a href="#" class="list-group-item">全球购</a>
<a href="#" class="list-group-item">闪购</a>
<a href="#" class="list-group-item">团购</a>
{% endblock %}
</div>
</div>
<div class="col-md-9">
{% block content %}
base.html页面内容
{% endblock %}
</div>
</div>
</div>
</body>
</html>
模板base.html 定义了一个可以用于两列排版页面的简单HTML骨架。我们新建子模板index.html的主要工作就是继承base.html然后填充/覆盖其内部的blocks。
{% extends "base.html" %}
<!--用新内容完全覆盖了父模板内容-->
{% block title %}
index页面
{% endblock %}
{% block sidebar %}
<!--该变量会将父模板中sidebar中原来的内容继承过来,然后我们可以在此基础上新增,否则就是纯粹地覆盖-->
{{ block.super }}
<!--在继承父模板内容的基础上新增的标签-->
<a href="#" class="list-group-item">拍卖</a>
<a href="#" class="list-group-item">金融</a>
{% endblock %}
{% block content %}
<!--用新内容完全覆盖了父模板内容-->
<p>index页面内容</p>
{% endblock %}
我们通过django访问index.html看到内容如下(block标签的内容都完成了替换或更新)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
index页面
</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
* {
margin: 0;
padding: 0;
}
.header {
height: 50px;
100%;
background-color: #919191;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="header"></div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="list-group">
<!--该变量会将父模板中sidebar中原来的内容继承过来,然后我们可以在此基础上新增,否则就是纯粹地覆盖-->
<a href="#" class="list-group-item active">服装城</a>
<a href="#" class="list-group-item">美妆馆</a>
<a href="#" class="list-group-item">超市</a>
<a href="#" class="list-group-item">全球购</a>
<a href="#" class="list-group-item">闪购</a>
<a href="#" class="list-group-item">团购</a>
<!--在继承父模板内容的基础上新增的标签-->
<a href="#" class="list-group-item">拍卖</a>
<a href="#" class="list-group-item">金融</a>
</div>
</div>
<div class="col-md-9">
<!--用新内容完全覆盖了父模板内容-->
<p>index页面内容</p>
</div>
</div>
</div>
</body>
</html>
总结和注意
#1、标签extends必须放在首行,base.html中block越多可定制性越强
#2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写
#3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖
#4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:
{% block content %}
...
{% endblock content %}
#5、在一个模版中不能出现重名的block标签。
STATIC_URL = '/static/' # 找到这一行,然后新增下述代码
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'statics'),# 获取静态文件在服务端的绝对路径
]
#STATIC_URL = '/static/'就是为静态文件的绝对路径起了一个别名,以后我们只需要用路径/static/即可
2、在项目根目录下新增文件夹statics,为了更便于管理,可以在statics下新建子文件夹css、js、img等

3、新建模板文件index.html,在该文件中对静态文件的引用如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/my.css">
</head>
<body>
<h4>我是红色的,点我就绿</h4>
<img src="/static/img/rb.jpeg" alt="">
<script src="/static/js/jquery-3.3.1.min.js"></script>
<script src="/static/js/my.js"></script>
</body>
</html>
request: 用户所有的请求信息,视图函数参数必须要这个
前后台交互的数据必须使用json格式数据
### 前台发送给后台的方式
第一种方式:
前台HTML发送给后台的方式:(常见的是这两种)
get(html不指定发送方式,默认是get) post (常见的是这两种)
后台获取html请求数据 : if request.method == 'GET':
pass
if request.method == 'POST':
pass
第二种方式:
前台ajax发送数据给后台
前提是:有js和jQuery
{# 这是模态框(弹出框)添加班级 #}
$('#tijiao').click(function () {
console.log($('#classid').val());
$.ajax({
{# 这三步是客户在弹出框输入内容之后 将输入的内容向后台提交 #}
type: "POST",
url : "/classesapp/modal_add_class/",
data: {"classname":$('#classname').val()},
{# 这三步是客户在弹出框输入内容之后 将输入的内容向后台提交 #}
success: function (data) {
{#这是后台收到前台输入的信息之后返货给HTML的数据 也就会data #}
if(data == 'ok'){
alert('添加成功!');
window.location.href = '/classesapp/classes/'; // 让浏览器啊界面返回这个classesapp/classes
}else{
alert('添加失败!');
$('#error').text(data)
}
}
})
});
后台接收HTML的ajax的内容 以及传回给html的内容
def modal_add_class(request):
classname = request.POST.get('classname') # 接收html的值
if not classname:
return HttpResponse('false') # 返回的信息
else:
import pymysql
conn = pymysql.connect(host='127.0.0.1', user='root', password='', db='s858', charset='utf8')
cursor = conn.cursor(cursor=pymysql.cursors.DictCursor)
sql = 'insert into classes (name) values (%s)'
cursor.execute(sql, (classname,))
conn.commit()
return HttpResponse('ok') # 返回的信息
第三种方式:
前台HTML与后台交互的方式: a标签或form表单
<a href="/classesapp/add_class/" type="button" class="btn btn-success" >增加班级</a> # 代表点击增加班级的时候 会运转classesapp/add_class函数
<form action="/teacherapp/update_teacher/" method="post">
{# update_teacher 走这update_teacher函数 #}
<input type="hidden" name="teacherid" value="{{ teacherid }}">
更新后的名称 <input type="text" name="teachername" value="{{ teachername }}">
<input type="submit" value="更新">
</form>
## 表示 页面点击更新按钮时运行/teacherapp/update_teacher这个函数
第四种方式:
widnow.location.href = '/classes/'; # 跳转到classes函数
window.location.reload(); # 刷新当前页面
后台正常接收数据
后台发送给html的方式:
第一种:render:渲染页面
return render(request,'classes.html',{"classes":classes})
代表返回给渲染的是这个HTML: classes.html 和传递的数据是{"classes":classes},要注意的
{"classes":classes}这个数据是传给classes.html这个html页面的 前端可以在html页面中获取这个内容
如果仅仅是传递数据 return render(request,{"classes":classes}),这个是报错的的 因为没有页面渲染
前台获取的后台发送的内容
{% for item in classes %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>
<a href="/classesapp/del_class/?id={{ item.id }}" onclick="return xxxxx()" type="button" class="btn btn-danger">删除</a>
<a href="/classesapp/update_class/?id={{ item.id }}" type="button" class="btn btn-primary">更新</a>
<button type="button" class="btn btn-success ajax_class_modal">弹出框更新</button>
</td>
</tr>
{% endfor %}
第二种:redirect() 重指向的意思
return redirect('/classesapp/classes/')
代表重新指向函数运行 由/classesapp/classes/函数去执行向前台输入信息等
第三种方式: HttpResponse("xxx") 和 JsonResponse(")
'''
HttpResponse
后台返回的格式:
res["code"] = 10000
res['data'] = "success"
return HttpResponse(json.dumps(res))
前台js反序列化:
// js反序列化:
console.log(data);
res = JSON.parse(data);
前台js的序列化:
JSON.stringify(res)
'''
JsonResponse(")
后台返回的格式:
res["code"] = 10000
res['data'] = "success"
return JsonResponse((res)) ### 相当于使用了json.dumps()
前台:
console.log(data) ## data 已经反序列化好的字典
区别:
HTTPResponse:
是由Django创造的,
他的返回格式为
HTTPResponse(content=响应体,content_type=响应体数据类型,status=状态码),
可以修改返回的数据类型,适用于返回图片,视频,音频等二进制文件。
JsonResponse:
是HTTPResponse的子类,适用于处理json格式的数据,但是不能返回模板。
帮助我们将数据转换为json字符串
设置响应头Content-Type为application/json
即(HTML与py的数据格式)
前台:(html中的显示)
{{name}}
列表:
{% for item in mylist%}
{{item}}
{% endfor %}
{{mylist.0}} # 取得列表的首位 直接点语法
{{mylist.1}} # 取得列表的第二位
字典:
{% for key, val in mydict.items %}
{{key}} --- {{val}}
{% endfor %}
1. css
如果想要绑定多个相同的标签的时候, 不要用id选择器, 要用class类别选择器
2. DOM ===》 Document Object Modal
DOM0:
html:
<!--如果onclick是true的话,会执行跳转, 如果是False的 话, 阻止跳转-->
<a href="https://www.baidu.com" onclick="return del();">点击</a>
js:
function del(){
res = window.confirm('是否确认删除?');
return res; // true / false
}
DOM1:
html:
<a href="https://www.baidu.com" id="mya">点击</a>
js:
原生js:
var a = document.getElementById('mya') ;
// console.log(a);
a.onclick = function () {
res = window.confirm('是否确认删除?');
return res;
}
jquery:
$('#mya').click(fucntion(){
res = window.confirm('是否确认删除?');
return res;
})

