一 请求

一 限制http请求

视图中的request,实际上是django源码中的HTTPRequest的子类WSGIRequest类的实例对象,主要由django对客户端请求http协议报文进行解析后得到的请求相关数据在request对象中。web项目运行在http协议下,默认肯定也支持用户通过不同的http请求方法发送数据到服务端。常用的http请求方法:


HTTP请求方法
描述
POST 添加/上传
GET 获取/下载
PUT 修改/更新,修改整体
PATCH 修改/更新,修改部分
DELETE 删除/废弃

Django支持让客户端只能通过指定的Http请求来访问到项目的视图。views.py 代码:

# 让用户发送POST才能访问的页面
from django.views.decorators.http import require_http_methods
@require_http_methods(["POST"])  # 注意,中括号中的请求方法名务必大写!!!否则无法正常显示
def login(request):
    return HttpResponse("登录成功!")

二 视图接收http请求

在http请求和响应过程中, 用户往往会在请求过程中发送请求信息给服务端。那么客户端发送请求数据一般无非以下几种格式:

1 获取查询字符串的参数(request.GET)

查询字符串就是url地址上面?号后面的数据,例如:http://127.0.0.1:8000/index?name=xiaoming&pwd=123456。

上面name=xiaoming&pwd=123456就是查询字符串,可以通过request.GET来获取。

注意: GET不是http请求,也就是说,只要地址上有查询字符串,不管使用什么样的http请求方法,都可以使用获取request.GET来获取

from django.http.response import HttpResponse
from django.views.decorators.http import require_http_methods
from django.http import QueryDict
def index(request):
    print("index视图运行了")
    # print(request.method)
    # print(request.headers)
    # print(request.body)
    # print(request.path)
    """获取查询字符串"""
    """
    请求地址:http://127.0.0.1:8000/home/index
    """
    print(request.GET)  # 获取地址栏上的所有的查询字符串,组成一个QueryDict查询字典对象
    """
    打印效果:<QueryDict: {}>
    QueryDict的声明位置: from django.http import QueryDict
    QueryDict的父类继承的就是dict字典,所以字典提供的方法或者操作, QueryDict都有
    之所以使用QueryDict来保存请求参数的原因时:默认的字典的键是唯一的,所以会导致如果有多个值使用了同一个键,则字典会覆盖的。
    而django内部封装的QueryDict允许多个值使用了同一个键,会自动收集所有的值保存在一个列表中作为当前键的值区寄存起来。
    QueryDict常用的方法有2个:
    get(键)     通过指定键获取最后1个值
    getlist(键) 通过指定键获取所有值,并以列表格式返回
    """

    """
    请求地址:http://127.0.0.1:8000/home/index?name=xiapming&mobile=13312345678
    """
    print(request.GET.get("mobile"))
    print(request.GET.get("name"))
    print(request.GET.get("pwd", 123))
    # print(request.Get["pwd"])  # 减少使用中括号,会在没有键的情况下导致程序报错
    """
    打印效果:
        13312345678
        xiapming
        123
    """

    """
    请求地址:http://127.0.0.1:8000/home/index?name=xiaoming&mobile=13312345678&lve=swimming&lve=shopping&lve=game
    """
    print(request.GET.get("lve"))  # game
    print(request.GET.getlist("lve"))  # ['swimming', 'shopping', 'game']
    print(request.GET.getlist("name"))  # ['xiaoming']
    return HttpResponse("<h1>index</h1>")


@require_http_methods(["POST"])  # 注意,中括号中的请求方法名务必大写!!!否则无法正常显示
def login(request):
    return HttpResponse("登录成功!")

2 获取请求体数据(request.POST)

在各种http请求方法中,POST/PUT/PATCH都是可以设置请求体的。request.POST中获取客户端通过POST发送过来的请求体,无法获取PUT/PATCH的请求体。

# @require_http_methods(["POST", "PUT"])  # 注意,中括号中的请求方法名务必大写!!!否则无法正常显示
def index2(request):
    """获取请求体数据"""
    """
    访问地址:http://127.0.0.1:8000/home/index2
    请求体:不设置请求体
    """
    # print(request.POST)
    """
    request.POST获取的结果也是QueryDict查询字典对象
    <QueryDict: {}>
    """

    """
    访问地址:http://127.0.0.1:8000/home/index2
    请求体:name=xiaoming&age=16
    """
    # print(request.POST)

    """
    打印效果:
    <QueryDict: {'name': ['xiaoming'], 'age': ['16']}>
    """
    # print(request.POST.get("name"))


    """
    访问地址:http://127.0.0.1:8000/home/index2
    请求体:name=xiaoming&age=16&citys=["北京", "上海", "天津]
    """
    """
    打印效果:
    <QueryDict: {'name': ['xiaoming'], 'age': ['16'], 'citys': ['北京', '上海', '天津']}>
    """    # print(request.POST)  # ['北京', '上海', '天津']
    # print(request.POST.getlist("citys"))
    # print(request.POST.get("citys"))  # 天津


    """接收原生请求体中的json数据"""
    """
    请求地址:http://127.0.0.1:8000/home/index2
    请求体为json:'{"name": "xiaobai","age": 16}'
    """
    # print(request.POST)  # <QueryDict: {}>
    # print(request.body)    # b'{\n    "name": "xiaobai",\n    "age": 16\n}'
    # import json
    # print(json.loads(request.body))  # {'name': 'xiaobai', 'age': 16}
    return HttpResponse("index2!")

3 获取请求头数据(request.headers)

def index3(request):
    """接收请求体参数"""
    print(request.META) # 获取当前项目相关的服务器与客户端环境信息,也包含了请求头信息,以及服务端所在的系统的环境变量
    """
    {
        'LANG': 'zh_CN.UTF-8',    # 服务端系统的默认语言
        'USER': 'moluo',          # 服务端运行的系统用户名
        'HOME': '/home/moluo',    # 服务端运行的系统用户家目录路径
        'DJANGO_SETTINGS_MODULE': 'djdemo.settings',  # 只有在django下才有的,当前django框架运行时加载的配置文件导包路径
        'SERVER_NAME': 'ubuntu',             # 服务端系统名称
        'SERVER_PORT': '8000',               # 服务端的运行端口
        'REMOTE_HOST': '',                   # 客户端的所在IP地址,有时候可能是域名
        'SCRIPT_NAME': '',                   # 客户端本次请求时,服务端执行的程序所在路径
        'SERVER_PROTOCOL': 'HTTP/1.1',       # 服务端运行的协议
        'SERVER_SOFTWARE': 'WSGIServer/0.2', # 服务端运行web服务器的软件打印信息
        'REQUEST_METHOD': 'POST',            # 客户端本次请求时的http请求方法
        'PATH_INFO': '/home/index3/',        # 客户端本次请求时的url路径
        'QUERY_STRING': '',                  # 客户端本次请求时的查询字符串
        'REMOTE_ADDR': '127.0.0.1',          # 客户端的所在IP地址
        'CONTENT_TYPE': 'application/json',  # 客户端本次请求时的数据MIME格式
        'HTTP_USER_AGENT': 'PostmanRuntime/7.26.10', # 客户端本次请求时,所使用的网络代理软件提示信息
        'HTTP_ACCEPT': '*/*',          # 客户端期望服务端返回的数据MIME格式格式
        'HTTP_HOST': '127.0.0.1:8000', # 客户端本次请求时,所使用服务端地址
        'HTTP_ACCEPT_ENCODING': 'gzip, deflate, br', # 客户端期望服务端返回的数据的压缩格式
        'HTTP_CONNECTION': 'keep-alive', # 客户端支持的服务端协议的链接类型,keep-alive 表示客户端支持http的长连接
    }
    """
    print(request.headers)  # 获取HTTP请求头
    """
    {
        'Content-Length': '601',     // 客户端本次请求的内容大小
        'Content-Type': 'multipart/form-data;',   # 客户端本次请求的内容MIME类型
        'User-Agent': 'PostmanRuntime/7.26.10',   # 客户端本次请求的代理软件打印信息
        'Accept': '*/*',   
        'Host': '127.0.0.1:8000',    # 客户端本次请求的服务端地址
        'Accept-Encoding': 'gzip, deflate, br', 
        'Connection': 'keep-alive',
        # 以下就是自定义请求头了
        'Company': 'baidu', 
        'Num': '1000', 
    }
    """
    print("Content-Type=", request.META.get("CONTENT_TYPE"))
    print("自定义请求头,Num=", request.META.get("HTTP_NUM"))
    print("自定义请求头,Company=", request.META.get("HTTP_COMPANY"))
print("Content-Type=", request.headers.get("Content-Type")) print("自定义请求头,Num=", request.headers.get("Num")) print("自定义请求头,Company=", request.headers.get("Company")) return HttpResponse("接收请求体")

4 获取上传文件(request.FILES

def index4(request):
    """接收上传文件"""
    # print(request.FILES)
    """
    POST  http://127.0.0.1:8000/home/index4
    打印效果:
    <MultiValueDict: {'avatar': [<InMemoryUploadedFile: 1.jpg (image/jpeg)>]}>
    """

    # print(request.FILES.get("avatar"))      # 获取本次客户端上传的指定name值对应的一个文件上传处理对象
    # print(request.FILES.getlist("avatar"))  # 获取本次客户端上传的指定name值对应的多个文件上传处理对象

    """
    django在解析http协议的时候,针对上传文件,会自动实例化一个内存保存文件的文件上传处理对象InMemoryUploadedFile
    from django.core.files.uploadedfile import InMemoryUploadedFile
    """
    # read() 从文件上传处理对象读取文件的内容(bytes格式内容)
    import os
    # # 处理一个上传文件[不仅是图片,任何内容都可以这样处理]
    # file = request.FILES.get('avatar')
    # with open(f"{os.path.dirname(__file__)}/{file.name}", "wb") as f:
    #     f.write(file.read())

    # 处理多个一次性上传文件
    for file in request.FILES.getlist("avatar"):
        with open(f"{os.path.dirname(__file__)}/{file.name}", "wb") as f:
            f.write(file.read())

    return HttpResponse("接收客户端的上传文件") 

二 响应

django和大多数的web框架一样,针对http的响应,提供了2种不同的响应方式:

  1. 响应内容,就是直接返回数据给客户端

    1. 响应html内容【一般用于web前后端不分离的项目】

    2. 响应json内容【一般用于开发web前后端分离的项目的api接口开发】

  2. 响应页面跳转,就是通过返回页面跳转的信息给浏览器,让浏览器自己进行页面跳转

一 响应内容

1 返回HTML数据

def index5(request):
    """响应对象"""
    """
    return HttpResponse(content="正文内容",content_type="内容格式",status="http响应状态码")
    content      响应内容
    content_type 内容格式,默认是 text/html
    status       响应状态码,默认是 200
    headers      响应头,字典格式
    """

    """返回html内容"""
    return HttpResponse("<h1>你好,django</h1>")

2 返回Json数据

def index6(request):
    """响应对象:响应json数据"""
    # 返回字典数据作为json给客户端
    """
    import json
    data = {"name":"xiaoming", "age":16, "sex": True}
    return HttpResponse(json.dumps(data), content_type="application/json;charset=utf-8")
    """

    # 原生返回json数据,太麻烦了
    # 因此django提供了一个HttpResponse的子类JsonResponse,转换提供给我们返回json数据的
    # from django.http.response import JsonResponse
    # data = {"name": "xiaoming", "age": 16, "sex": True}
    # return JsonResponse(data)

    # JsonResponse返回的数据如果不是字典,则必须要加上safe参数声明,并且值为False
    # 返回列表数据给客户端
    from django.http.response import JsonResponse
    data = [
        {"id":1, "name": "小明", "age": 16},
        {"id":3, "name": "小火", "age": 15},
    ]

    return JsonResponse(data, safe=False)
    # return JsonResponse(data, safe=False, json_dumps_params={"ensure_ascii": False})  # 不推荐使用

3 返回图片格式信息

例如:图片,压缩包,视频,或js脚本

def index7(request):
    """返回图片格式"""
    import os
    with open(f"{os.path.dirname(__file__)}/avatar.jpg", "rb") as f:
        content = f.read()
        return HttpResponse(content, content_type="image/jpeg")

4 提供下载压缩包

def index8(request):
    """返回压缩包格式"""
    import os
    with open(f"{os.path.dirname(__file__)}/code.zip", "rb") as f:
        content = f.read()
        return HttpResponse(content, content_type="application/zip")

5 自定义响应头

def index9(request):
    """返回数据的过程中设置响应头"""
    response = HttpResponse("ok")
    # 自定义响应头[值和属性都不能是多字节]
    response["company"] = "baidu"
    return response

二 响应页面跳转

页面跳转也有2种方式:站外跳转与站内跳转。

1 站外跳转

def index10(request):
    """跳转到站外"""
    # 1. 基于django提供的Response对象也可以进行页面跳转
    # from django.http.response import HttpResponse
    # response = HttpResponse(status=301)
    # response["Location"] = "https://www.tmall.com"
    # return response

    # # 2. 基于django提供的Response对象的原生写法[HttpResponseRedirect与HttpResponsePermanentRedirect都是HttpResponse的子类]
    # from django.http.response import HttpResponseRedirect    # 临时重定向
    # # from django.http.response import HttpResponsePermanentRedirect  # 永久重定向
    # return HttpResponseRedirect("https://www.qq.com")

    # 2. 基于django提供快捷函数(简写函数, shortcuts)来完成[常用]
    from django.shortcuts import redirect
    return redirect("http://www.baidu.com")

2 站内跳转

在站内跳转时,如果使用django.urls.reverse函数进行路由反转解析(可以根据路由的别名反向生成路由的URL地址),则必须在总路由文件和子路由文件中,对路由的前缀和子路由后缀进行别名绑定,步骤如下:djdemo/urls.py,总路由,代码:

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('home/', include('home.urls', namespace="index")),  # namespace 是include函数的参数,namespace的值就是提供给reverse使用的
]

home/urls.py,子路由,代码:

from django.urls import path
from home import views

# 使用路由反向解析,reverse时必须在当前路由文件中设置app_name为当前子应用的包名
app_name = "home"

urlpatterns = [
。。
    path('index11', views.index11, name="in11"),
    path('index12', views.index12, name="in12"),
]

home/views.py,代码:

def index11(request):
    """跳转到站内"""
    from django.shortcuts import redirect  # 根据指定的url地址,进行页面跳转

    # # 直接基于redirect跳转
    # return redirect("/home/index12")

    # # 基于reverse+redirect对路由别名进行反向解析进行跳转
    from django.urls import reverse  # 根据路由别名,反向解析生成url地址
    url = reverse("index:in12")
    print(url)
    return redirect(url)


def index12(request):
    return HttpResponse("ok, index12")

 

posted on 2022-11-28 17:52  大明花花  阅读(57)  评论(0编辑  收藏  举报