准备工作
将不同day下的代码分目录管理,方便后续复习查阅
- (testenv) [root@localhost projects]# ls
- mysite1
- (testenv) [root@localhost projects]# mkdir day01 day02
- (testenv) [root@localhost projects]# cp -rf mysite1/ day01/
- (testenv) [root@localhost projects]# cp -rf mysite1/ day02/
- (testenv) [root@localhost projects]# ls day01/
- mysite1
- (testenv) [root@localhost projects]# ls day02/
- mysite1
- (testenv) [root@localhost projects]# rm -rf mysite1/
使用Pycharm打开day02下的mysite1项目进行操作

请求是指浏览器端通过HTTP协议发送给服务器端的数据
响应是值服务器端接收到请求后做相应的处理后再回复给浏览器端的数据


根据HTTP标准,HTTP请求可以使用多种请求方法
HTTP1.0定义了三种请求方法:GET/POST/HEAD方法(最常用)

HTTP1.1新增了五种请求方法:OPTIONS/PUT/DELETE/TRACE/CONNECT方法

- path_info:URL字符串
- method:字符串,表示HTTP请求方法,常用值:GET/POST
- GET:QueryDict查询字典的对象,包含GET请求方式的所有数据
- POST:QueryDict查询字典的对象,包含POST请求方式的所有数据
- FILES:类似于字典的对象,包含所有的上传文件信息
- COOKIES:Python字典,包含所有的cookie,键和值都是字符串
- session:类似于字典的对象,表示当前的会话
- body:字符串,请求体的内容(POST/PUT)
- scheme:请求协议(http/https)
- request.get_full_path():请求的完整路径
- request.META:请求中的元数据(消息头)
- request.META[‘REMOTE_ADDR’]:客户端IP地址
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- from django.contrib import admin
- from django.urls import path
- from . import views
-
- urlpatterns = [
- # ......
- ###day02###
- path("test_request", views.test_request),
- ]
修改 mysite1/mysite1/views.py,添加指定视图函数
- def test_request(request):
- print("path info is:", request.path_info)
- print("method is:", request.method)
- print("query string:", request.GET)
- print("full path:", request.get_full_path())
- return HttpResponse("test request ok~")
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_request?a=1&b=2



响应状态码
HTTP状态码的英文为 Http Status Code,下面是常见的HTTP状态码
200:请求成功
301:永久重定向,资源/网页等被永久转移到其他URL地址
302:临时重定向
404:请求的资源/网页等不存在
可以访问一个不存在的URL,显示404

500:服务器内部错误
HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为 5种类型:
| 分类 | 分类描述 |
|---|---|
| 1** | 信息,服务器收到请求,需要请求者继续执行操作 |
| 2** | 成功,操作被成功接收并处理 |
| 3** | 重定向,需要进—步的操作l以完成请求 |
| 4** | 客户端错误,请求包含语法错误或无法完成请求 |
| 5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
构造函数格式:HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)
作用:向客户端浏览器返回响应,同时携带响应体内容
参数
常见的Content_Type如下
- text/html:默认的,html文件
- text/plain:纯文本
- text/css:css文件
- text/javascript:javascript文件
- application/json:json数据传输
- multipart/form-data:文件提交
HttpResponse子类

修改 mysite1/mysite1/views.py,修改指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect # 导入重定向
-
- def test_request(request):
- print("path info is:", request.path_info)
- print("method is:", request.method)
- print("query string:", request.GET)
- print("full path:", request.get_full_path())
- # return HttpResponse("test request ok~") # 注释掉普通响应
- return HttpResponseRedirect("/page/1") # 改为重定向,会自动跳转到/page/1
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_request,观察浏览器地址变化以及响应数据

无论是GET还是POST请求,统一都由视图函数接收请求,通过判断request.method属性来区分具体的请求动作
样例
- if request.method == "GET":
- 处理GET请求时的业务逻辑
- elif request.method == "POST":
- 处理POST请求时的业务逻辑
- else:
- 其他请求业务逻辑
处理方式
- def test_get_post(request):
- if request.method == "GET":
- pass
- elif request.method == "POST":
- # 处理用户提交数据
- pass
- else:
- pass
- return HttpResponse("--test get post is ok --")GET处理
GET请求动作,一般用于向服务器获取数据,能够产生GET请求的场景:
GET请求方式中,如果有数据需要传递给服务器,通常会用查询字符串(QueryString)传递
服务器端接收参数
方法示例
- request.GET["参数名"] # QueryDict
- request.GET.get("参数名", "参数值")
- request.GET.getlist("参数名")
- # page?a=100&b=200&c=300&b=400
- # request.GET的值是--->QueryDict({"a": ["100"], "b": ["200", "400"], "c": ["300"],})
- # a = request.GET["a"]
修改 mysite1/mysite1/views.py,修改指定视图函数
- def test_get_post(request):
- if request.method == "GET": # 处理GET请求
- print(request.GET) # 打印QueryDict
- print(request.GET["a"])
- print(request.GET.get("c", "no c"))
- elif request.method == "POST":
- # 处理用户提交数据
- pass
- else:
- pass
- return HttpResponse("--test get post is ok --")
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- from django.contrib import admin
- from django.urls import path
- from . import views
-
- urlpatterns = [
- # ......
- ###day02###
- path("test_request", views.test_request),
- path("test_get_post", views.test_get_post),
- ]
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_get_post?a=400,并查看终端打印数据


浏览器访问:http://127.0.0.1:8000/test_get_post,不带参数,请求报错,查看报错信息


浏览器访问:http://127.0.0.1:8000/test_get_post?a=100&a=200&a=300,传递三个参数a


可得,request.GET["a"] 并不能获取a参数的所有值
修改 mysite1/mysite1/views.py,修改指定视图函数
- def test_get_post(request):
- if request.method == "GET": # 处理GET请求
- print(request.GET) # 打印QueryDict
- print(request.GET["a"])
- # 应用场景--复选框,例如:兴趣爱好:篮球,足球,跑步......
- print(request.GET.getlist("a")) # ###获取a参数的所有值###
- print(request.GET.get("c", "no c"))
- elif request.method == "POST":
- # 处理用户提交数据
- pass
- else:
- pass
- return HttpResponse("--test get post is ok --")
浏览器访问:http://127.0.0.1:8000/test_get_post?a=100&a=200&a=300,传递三个参数a,查看终端显示

POST请求动作,一般用于向服务器提交大量/隐私数据,客户端通过表单等POST请求将数据传递给服务器端,如

服务器端接收参数,通过request.method来判断是否为POST请求,如:
- if request.method == "POST":
- 处理POST请求的数据并响应
- else:
- 处理非POST请求时的业务逻辑
使用POST方式接收客户端数据
- request.POST["参数名"] # QueryDict
- request.POST.get("参数名", "参数值")
- request.POST.getlist("参数名")
取消csrf验证,否则Django将会拒绝客户端发来的POST请求,报403响应
修改 mysite1/mysite1/views.py,修改指定视图函数
- # 定义GET请求的响应数据,返回一个FORM表单
- POST_FORM = """
- /test_get_post">
- 用户名: " name="uname">
- " value="提交">
- """
-
- def test_get_post(request):
- if request.method == "GET":
- print(request.GET)
- # print(request.GET["a"]) # 注释掉此处代码,防止服务报错
- print(request.GET.getlist("a"))
- print(request.GET.get("c", "no c"))
- return HttpResponse(POST_FORM) # GET请求响应一个表单数据
- elif request.method == "POST":
- # 处理用户提交数据
- print("uname is:", request.POST.get("uname")) # 处理POST请求
- return HttpResponse("post is ok~") # 返回响应数据
- else:
- pass
- return HttpResponse("--test get post is ok --")
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_get_post,返回表单数据

填写表单数据,点击提交,发送POST请求,查看浏览器显示内容,POST请求失败,403响应

填写表单数据,点击提交,发送POST请求,查看浏览器显示内容,POST请求失败,403响应

取消csrf验证,注释掉 settings.py 中的 MIDDLEWARE 中的 CsrfViewsMiddleWare 的中间件
- # 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',
- ]
重新提交表单数据,数据提交成功

查看终端数据显示

MVC设计模式把Web框架分为三个基础部分:
作用:降低模块间的耦合度(解耦)

MTV和MVC本质上是一样的,MTV代表 Model-Template-View (模型-模板-视图)模式

创建模板文件夹 <项目名>/templates
修改 settings.py 中 TEMPLATES 配置项
配置项(settings.py)中需要修改的部分
设置 DIRS
方案1:通过 loader 获取模板,通过 HttpResponse 进行响应在视图函数中

方案2:使用 render() 直接加载并响应模板,在视图函数中实现

在项目中创建 templates 目录,注意创建路径

修改 settings.py 文件,设置 DIRS 配置
- TEMPLATES = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'DIRS': [os.path.join(BASE_DIR, "templates")], # 修改DIRS配置
- 'APP_DIRS': True,
- 'OPTIONS': {
- 'context_processors': [
- 'django.template.context_processors.debug',
- 'django.template.context_processors.request',
- 'django.contrib.auth.context_processors.auth',
- 'django.contrib.messages.context_processors.messages',
- ],
- },
- },
- ]
测试模板加载方案一:修改 mysite1/mysite1/views.py,添加指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
-
- # ......之前视图函数省略
- def test_html(request):
- from django.template import loader
- t = loader.get_template("test_html.html") # 指定渲染模板名称
- html = t.render()
- return HttpResponse(html)
在 mysite1/templates 目录中创建指定模板文件:test_html.html

- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <h3>我是模板层!!!</h3>
- </body>
- </html>
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- from django.contrib import admin
- from django.urls import path
- from django.urls import re_path
- from . import views
-
- urlpatterns = [
- # ......
- ###day02###
- path("test_request", views.test_request),
- path("test_get_post", views.test_get_post),
- path("test_html", views.test_html), # 添加新的路由配置
- ]
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_html,查看模板加载是否成功

测试模板加载方案二(推荐使用):修改 mysite1/mysite1/views.py,修改指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
-
- # ......之前视图函数省略
- def test_html(request):
- # 方案一:
- # from django.template import loader
- # t = loader.get_template("test_html.html") # 指定渲染模板名称
- # html = t.render()
- # return HttpResponse(html)
-
- # 方案二:
- from django.shortcuts import render
- return render(request, "test_html.html")
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_html,查看模板加载是否成功


修改 mysite1/mysite1/views.py,修改指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
-
- # ......之前视图函数省略
- def test_html(request):
- from django.shortcuts import render
- dic = {"username": "nfx", "age": 18}
- return render(request, "test_html.html", dic)
修改 mysite1/templates 目录的模板文件:test_html.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <h3> {{ username }} 我是模板层!!!</h3>
- </body>
- </html>
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_html,查看模板加载是否成功


修改 mysite1/mysite1/views.py,创建指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
- from django.shortcuts import render
-
- # ......之前视图函数省略
- def test_html_param(request):
- dic = {}
- dic["int"] = 88
- dic["str"] = "nfx"
- dic["lst"] = ["Tom", "Jack", "Lily"]
- dic["dict"] = {"a": 9, "b": 8}
- dic["func"] = say_hi
- dic["class_obj"] = Dog()
- return render("test_html_param.html")
-
- def say_hi():
- return "hehehe"
-
- class Dog:
- def say(self):
- return "wangwang~"
在 mysite1/templates 目录中创建指定模板文件:test_html_param.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <h3>int is {{ int }}</h3>
- <h3>str is {{ str }}</h3>
- <h3>lst is {{ lst.0 }}</h3>
- <h3>dict is {{ dict }}</h3>
- <h3>dict["a"] is {{ dict.a }}</h3>
- <h3>function is {{ func }}</h3>
- <h3>class_obj is {{ class_obj.say }}</h3>
- </body>
- </html>
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- from django.contrib import admin
- from django.urls import path
- from django.urls import re_path
- from . import views
-
- urlpatterns = [
- # ......
- ###day02###
- path("test_request", views.test_request),
- path("test_get_post", views.test_get_post),
- path("test_html", views.test_html),
- path("test_html_param", views.test_html_param), # 添加新的路由配置
- ]
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_html_param,查看模板加载是否成功

作用:将一些服务器端的功能嵌入到模板层,例如流程控制等
标签语法:
- {% 标签 %}
- ......
- {% 结束标签 %}
语法:

注意:
修改 mysite1/mysite1/views.py,创建指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
- from django.shortcuts import render
-
- # ......之前视图函数省略
- def test_if_for(request):
- dic = {}
- dic["x"] = 10
- return render(request, "test_if_for.html", dic)
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- from django.contrib import admin
- from django.urls import path
- from django.urls import re_path
- from . import views
-
- urlpatterns = [
- # ......
- ###day02###
- path("test_request", views.test_request),
- path("test_get_post", views.test_get_post),
- path("test_html", views.test_html),
- path("test_html_param", views.test_html_param),
- path("test_if_for", views.test_if_for), # 添加新的路由配置
- ]
在 mysite1/templates 目录中创建指定模板文件:test_if_for.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- {% if x > 10 %}
- 今天天气很好
- {% else %}
- 今天天气非常好
- {% endif %}
- </body>
- </html>
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_if_for,查看模板加载是否成功

需求
写一个简单的计算器页面,能够在服务端进行简单的加减乘除计算

处理思路
修改 mysite1/mysite1/views.py,创建指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
- from django.shortcuts import render
-
- # ......之前视图函数省略
- def test_mycal(request):
- if request.method == "GET":
- return render(request, "mycal.html")
- elif request.method == "POST":
- # 处理计算
- x = int(request.POST["x"])
- y = int(request.POST["y"])
- op = request.POST["op"]
-
- result = 0
- if op == "add":
- result = x + y
- elif op == "sub":
- result = x - y
- elif op == "mul":
- result = x * y
- elif op == "div":
- result = x / y
- # locals()相当于:dic = {"x": x, "y": y, "op": op, "result": result}
- return render(request, "mycal.html", locals())
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- from django.contrib import admin
- from django.urls import path
- from django.urls import re_path
- from . import views
-
- urlpatterns = [
- # ......
- ###day02###
- path("test_request", views.test_request),
- path("test_get_post", views.test_get_post),
- path("test_html", views.test_html),
- path("test_html_param", views.test_html_param),
- path("test_if_for", views.test_if_for),
- path("mycal", views.test_mycal), # 添加新的路由配置
- ]
在 mysite1/templates 目录中创建指定模板文件:mycal.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- <form action="/mycal" method="post">
- <input type="text" name="x" value="{{ x }}">
- <select name="op">
- <option value="add" {% if op == "add" %}selected{% endif %}>+ 加</option>
- <option value="sub" {% if op == "sub" %}selected{% endif %}>- 减</option>
- <option value="mul" {% if op == "mul" %}selected{% endif %}>* 乘</option>
- <option value="div" {% if op == "div" %}selected{% endif %}>/ 除</option>
- </select>
- <input type="text" name="y" value="{{ y }}"> =
- <span>{{ result }}</span>
- <div><input type="submit" value="开始计算"></div>
- </form>
- </body>
- </html>
查看服务是否重启,浏览器访问:
http://127.0.0.1:8000/mycal

语法:

内置变量 — forloop

修改 mysite1/mysite1/views.py,修改指定视图函数
- from django.http import HttpResponse, HttpResponseRedirect
- from django.shortcuts import render
-
- # ......之前视图函数省略
- def test_if_for(request):
- dic = {}
- dic["x"] = 10
- dic["lst"] = ["nfx", "benben", "gangzi"] # 添加一个列表数据
- return render(request, "test_if_for.html", dic)
修改 mysite1/templates 目录的模板文件:test_if_for.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>Title</title>
- </head>
- <body>
- {% if x > 10 %}
- 今天天气很好
- {% else %}
- 今天天气非常好
- {% endif %}
-
- <br>
-
- {% for name in lst %}
- {% if forloop.first %} ------- {% endif %}
- <p>{{ forloop.counter }} {{ name }}</p>
- {% if forloop.last %} ======= {% endif %}
- {% empty %}
- 当前没数据
- {% endfor %}
- </body>
- </html>
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/test_if_for,查看模板加载是否成功

模板继承可以使用父模板的内容重用,子模板直接继承父模板的全部内容并可以覆盖父模板中相应的块

语法—父模板:
语法—子模板:
继承模板 extends标签(写在模板文件的第一行)
例如:{% extends 'base.html' %}
子模板重写父模板中的内容块、

重写的覆盖规则
注意
修改 mysite1/mysite1/views.py,创建指定视图函数
- from django.shortcuts import render
-
- # 之前的视图函数省略......
- def base_view(request):
- return render(request, "base.html")
-
-
- def sport_view(request):
- return render(request, "sport.html")
-
-
- def music_view(request):
- return render(request, "music.html")
在 mysite1/templates 目录中创建指定模板文件:base.html
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- {% block mytitle %}
- <title>主页</title>
- {% endblock %}
- </head>
- <body>
- <a href="/music_index">音乐频道</a>
- <a href="/sport_index">体育频道</a>
- <br>
- {% block info %}
- 这是主页
- {% endblock %}
- <br>
- <h3>有任何问题请联系xxxxxx</h3>
- </body>
- </html>
在 mysite1/templates 目录中创建指定模板文件:sport.html
- {% extends "base.html" %}
- {% block mytitle %}
- <title>体育频道</title>
- {% endblock %}
- {% block info %}
- 欢迎来到体育频道
- {% endblock %}
在 mysite1/templates 目录中创建指定模板文件:music.html
- {% extends "base.html" %}
- {% block mytitle %}
- <title>音乐频道</title>
- {% endblock %}
- {% block info %}
- 欢迎来到音乐频道
- {% endblock %}
修改 mysite1/mysite1/urls.py 文件,添加路由配置
- ###day02###
- # ......
- path("base_index", views.base_view),
- path("music_index", views.music_view),
- path("sport_index", views.sport_view),
查看服务是否重启,浏览器访问:http://127.0.0.1:8000/base_index,查看模板加载是否成功
