4.视图
1.视图参数
# urls.py
urlpatterns = [
path('login/', account.login, name="login"),
path('auth/', order.auth, name='auth'),
]
# views.py
from django.shortcuts import HttpResponse
def login(request):
return HttpResponse("login")
Request 是什么?
requests是一个对象,存放了浏览器给咱们发过来的所有内容,所以含有:
- 请求相关所有的数据: 当前访问的url、请求方式、...
- django额外添加的数据
1.1 request 方法
1.1.1 request.path_info
- 只能获取到路由地址,无法获取到参数
- 它保留了URL路径中的任何编码、特殊字符或斜杠等信息。
http://localhost:8000/api/login/
def login(request):
print(request.path_info) # /api/login/
return HttpResponse("Hello, world. You're at the")
1.1.2 request.path
- 只能获取到路由地址,无法获取到参数
- 它包含在域名之后,在任何查询参数之前
http://localhost:8000/api/login/
def login(request):
print(request.path) # /api/login/
return HttpResponse("Hello, world. You're at the")
1.1.3 request.GET
- 该属性包含了请求中通过GET方法发送的所有参数。
- 这些参数通常会附加在URL之后,以问号分隔。
- 您可以使用参数的名字作为键来访问单个参数,例如
request.GET['page']
也可以直接.get()获取
http://localhost:8000/api/login/?xxx=serein&age=999
def login(request):
print(request.GET) # <QueryDict: {'xxx': ['serein'], 'age': ['999']}>
print(request.GET.get('xxx')) # serein
print(request.GET['age']) # 999
return HttpResponse("Hello, world. You're at the")
1.1.4 request.POST
request.POST
:该属性是一个类似字典的对象,包含了请求中通过POST方法发送的所有参数。- 这些参数通常是通过HTML表单发送的。
- 您可以使用参数的名字作为键来访问单个参数,例如
request.POST['username']
,也可以直接.get()获取
1.1.5 request.method
- 返回客户端用于发起请求的HTTP方法,比如'GET','POST'等
http://localhost:8000/api/login/?xxx=serein&age=999
def login(request):
print(request.method) # GET
return HttpResponse("Hello, world. You're at the")
1.1.6 request.body
- 获取POST请求的请求体
- 获取到的数据是原始格式,数据格式什么样根据content-type决定
def login(request):
print(request.body) # GET
return HttpResponse("Hello, world. You're at the")
# b'{"code":"083Sjmll2yla694F3bll2DguCM2SjmlG","unionId":"oP6QCsyT_9bk1dfSaVf0GEV5Y-yE"}' b'v1=123&v2=456'
# 请求体+请求头 数据格式 b'v1=123&v2=456' content-type格式:content-type:application/x-www-form-urlencoded
# 可以这么取值
print(request.POST)
print(request.POST.get("v1"))
print(request.POST.get("v2"))
1.1.7 request.FILES
request.FILES
:该属性是一个类似字典的对象,包含了请求中通过文件上传组件发送的所有文件。- 当表单中包含文件上传字段时,通过
request.FILES
可以访问上传的文件。 - 您可以使用文件的名字作为键来访问单个文件,例如
request.FILES['file']
,也可以.get()获取 - content-type格式, multipart/form-data
file_obj = request.FILES.get("avatar")
print(file_obj, type(file_obj))
# 165917-16953731571c11.jpg <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
# 获取文件名
file_name = file_obj.name
print(file_name, type(file_name))
1.1.8 request.get_full_path()
- 即能获取到路由地址又能获取到完整的路由地址后面的参数
request.get_full_path()
:该方法返回请求URL的完整路径,包括路径部分和任何查询参数。- 当您需要将完整URL作为字符串使用时,这个方法非常有用。
def login(request):
print(request.get_full_path()) # 获取到GET请求的完整路由地址和参数
# /app01/login/?username=111&password=111
return render(request, "login.html")
1.1.9 request.header
- 获取请求的请求头
1.1.10 request.COOKIES
- 请求头有个特殊的cookie,
- 可以直接request.COOKIES获取
1.1.11 request.resolver_match
- 获取requests中其他值
2. 返回json数据
- 服务端返回json数据
- JsonResponse模块
- from django.http import JsonResponse
# 第一种方式:json模块序列化
def index(request):
data = {"username": "serein", 'password': '1234'}
# 先用json序列化
data = json.dumps(data)
# 三板斧对象
response = HttpResponse(data)
return response
# 第二种办法
from django.http import JsonResponse
def index(request):
data = {"username": "serein", 'password': '1234'}
response = JsonResponse(data)
return response
3. FBV和CBV
3.1 FBV和CBV
- funtion 函数和路由之间的映射关系
- class 类和路由之间的映射关系
3.2 CBV格式
- 视图层
# views.py
from django.shortcuts import render, HttpResponse
# 导入view
from django.views import View
# 重写类,继承view
class LoginView(View):
# get请求
def get(self, request):
pass
return HttpResponse("111")
# post请求
def post(self, request):
return HttpResponse("111")
- 路由层
from django.urls import path
from apps.api.views import LoginView
urlpatterns = [
path('login/', LoginView.as_view())
3.3 CBV源码剖析
class View:
# http_method_names : 存放了我们常用的请求方式
http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
def __init__(self, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
# 绑定给类的函数,绑定方法
@classonlymethod
def as_view(cls, **initkwargs):
# **initkwargs : 可变长关键字参数
for key in initkwargs:
# print(f"key :>>>> {key}") # key :>>>> pattern_name
# 可变长关键字参数中的每一个键值对
# 我们自己写视图类中没有定义过 http_method_names ,只能从父类 View 里面找
if key in cls.http_method_names:
#
raise TypeError(
'The method name %s is not accepted as a keyword argument '
'to %s().' % (key, cls.__name__)
)
# hasattr : 获取到当前对象中的属性
if not hasattr(cls, key):
raise TypeError("%s() received an invalid keyword %r. as_view "
"only accepts arguments that are already "
"attributes of the class." % (cls.__name__, key))
# 上面都没有报错,走到了 view 函数里面
def view(request, *args, **kwargs):
# 获取到当前类的对象 这个 cls ---> Register
self = cls(**initkwargs)
# 获取到了一个 当前的get方法
self.setup(request, *args, **kwargs)
# 必须接受一个位置参数叫request
if not hasattr(self, 'request'):
raise AttributeError(
"%s instance has no 'request' attribute. Did you override "
"setup() and forget to call super()?" % cls.__name__
)
# 触发了 dispatch 方法 ---> 获取到了get函数的返回值
# render
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
def setup(self, request, *args, **kwargs):
# self : 当前Register实例化出来的对象
# 有GET方法 并且 没有 head属性
if hasattr(self, 'get') and not hasattr(self, 'head'):
# self.head 变成了我自己写的 GET 方法
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
# 走到了dispatch方法
def dispatch(self, request, *args, **kwargs):
# request.method.lower() :当前请求方法转全小写
if request.method.lower() in self.http_method_names:
# 获取到了当前对象中的get方法的函数内存地址
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
# get方法的函数内存地址调用
return handler(request, *args, **kwargs)
def http_method_not_allowed(self, request, *args, **kwargs):
logger.warning(
'Method Not Allowed (%s): %s', request.method, request.path,
extra={'status_code': 405, 'request': request}
)
return HttpResponseNotAllowed(self._allowed_methods())
def options(self, request, *args, **kwargs):
"""Handle responding to requests for the OPTIONS HTTP verb."""
response = HttpResponse()
response.headers['Allow'] = ', '.join(self._allowed_methods())
response.headers['Content-Length'] = '0'
return response
def _allowed_methods(self):
return [m.upper() for m in self.http_method_names if hasattr(self, m)]
- 当我们启动Django项目时
- 会自动触发路由中的方法,调用 as_view 方法并自执行
- 在执行后我们查看 as_view 方法的源码 发现
- 在依次给我们的对象赋值后,最终返回了一个自执行的 dispatch 方法
- 于是我们又去查看了 dispatch 方法
- 在 dispatch 内部 ,先是将请求方式转换并进行校验
- 然后开始校验需要调用的方法的调用位置,校验成功并拿到需要执行的方法执行
- 在自己写的类中如果有相关的方法,会首先调用我们重写的类方法,并返回执行结果
- 如果自己的类里面没有该方法 会去自己的父类中调用 父类的方法
- 如果父类 以及 基类 都找不到则报错,抛出异常
- 如果自己的类里面没有该方法 会去自己的父类中调用 父类的方法
3.3 给CBV和FBV加装饰器
3.3.1 给FBV加装饰器
- 只需要将自己定义的装饰器放在指定的视图函数上面用语法糖
def timer(func):
def inner(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
print(f"总耗时 :>>>>> {time.time() - start_time} s ")
return res
return inner
@timer
def register(request):
time.sleep(2)
return HttpResponse("ok")
3.3.2 给CBV加装饰器
from django.utils.decorators import method_decorator
class Login(View):
# 第一种方式
# @timer
# def get(self, request, *args, **kwargs):
# time.sleep(2)
# return HttpResponse("login")
# 第二种方式 : 借助Django内置的公共函数 method_decorator
# @method_decorator(timer)
# def get(self, request, *args, **kwargs):
# time.sleep(2)
# return HttpResponse("login")
# 第三种方式:重写 dispatch 方法做拦截
def get(self, request, *args, **kwargs):
time.sleep(2)
return HttpResponse("login")
def dispatch(self, request, *args, **kwargs):
start_time = time.time()
# 可以什么都不写
# obj = super().dispatch(request, *args, **kwargs)
# 可以放自己的类名和自己的对象 self
obj = super(Login, self).dispatch(request, *args, **kwargs)
print(f"总耗时 :>>>> {time.time() - start_time} s ")
return obj
# if request.method.lower() in self.http_method_names:
# handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
# else:
# handler = self.http_method_not_allowed
# return handler(request, *args, **kwargs)
标签:知识点,return,必备,request,视图,method,login,self,def
From: https://www.cnblogs.com/Formerly/p/18102496