54.Django之视图层.
Django之视图层
【一】三板斧
1)HttpResponse
- 能返回字符串形式的数据
# 若想得到字典格式
def hr_dict_1(request):
data = {'username': 'ST1', 'age': 20}
# 将字典格式转为json字符串
data_json = json.dumps(data)
# 显示一个json格式的字符串
return HttpResponse(data_json)
def hr_dict_2(request):
data = {'username': 'ST1', 'age': 20}
# 将字典格式转为json字符串
data_json = json.dumps(data)
# 显示一个json数据
return HttpResponse(data_json,content_type='application/json')
2)render
- 返回一个页面进行渲染
3)redirect
- 重定向至新的路由地址
【二】form表单文件上传下载
-
form表单若想上传文件类型的数据
method:必须为'post' enctype:必须指定为form-data类型
-
实例
# html <form action="" method="post" enctype="multipart/form-data"> <p>普通信息:<input type="text" name="data_1"></p> <p>文件上传:<input type="file" name="data_file"></p> <input type="submit"> </form>
def file(request): # 获取post请求的数据 if request.method == 'POST': # 获取的请求(只有普通文本数据) # print(request.POST) # 获取文件数据 print(request.FILES) # # 提取文件数据 file_obj = request.FILES.get('data_file') # 获取文件名称 with open(file_obj.name, 'wb') as f: # 进行逐行读取 for line in file_obj.chunks(): f.write(line) return render(request, 'file.html')
【三】request对象方向
1)request.method
- 该方法返回客户端用于发起请求的HTTP方法
- 可用该方法来确定请求的类型,并相应的执行特点操作
2)request.POST
- 该属性是一个类似字典的对象,包含了请求中通过POST方法发送的所有参数
- 可用参数的名字作为键来访问单个参数
3)request.GET
- 该属性包含了请求中通过GET方法发送的所有参数
- 可用参数的名字作为键来访问单个参数
4)request.FILES
- 该属性是一个类似字典的对象,包含了请求中通过文件上传组件发送的所有文件
- 可用文件的名字作为键来访问单个文件
5)request.path
- 只能获取到路由地址,无法获取到参数
- 该属性表示请求URL中的路径部分
- 若请求的URL是
"http://example.com/foo/bar/"
,那么request.path将为"/foo/bar/"
6)request.path_info
- 只能获取到路由地址,无法获取到参数
- 用于表示请求URL的路径部分,不包括域名和查询参数
- 若请求的URL是
"http://example.com/foo/bar/?page=2"
,equest.path_info 的值将是"/foo/bar/"
7)request.get_full_path()
- 即能获取到路由地址又能获取到完整的路由地址后面的参数
- 该方法返回请求URL的完整路径,包括路径部分和任何查询参数
- 若请求的URL是
"http://example.com/foo/bar/?page=2"
,equest.get_full_path()将返回"/foo/bar/?page=2"
【四】FBV与CBV
1)FBV
2)CBV
1.使用
# 引入一个类
from django.views import View
# 创建一个类
class cbv_view(View):
# 写视图函数
def get(self, request):
print('cbv的get视图')
return render(request, 'cbv_view.html')
def post(self, request):
print(request.POST)
return render(request, 'cbv_view.html')
# urls
path('home/',cbv_view.as_view(), name='cbv_view')
# cbv_view.html
<form action="" method="post">
<p>username:<input type="text" name="username"></p>
<p>password:<input type="text" name="password"></p>
<input type="submit">
</form>
【五】CBV源码剖析
# 定义一个视图类(views.py)
from django.views import View
class LoginView(View):
def get(self, request):
...
def post(self, request):
...
# 定义路由(urls.py)
from App.views import LoginView
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', LoginView.as_view())
]
'''
class Login():
# 静态绑定方法
@staticmethod
def index():
...
# 类的绑定方法
@classmethod
def play(cls):
...
# 对象的绑定方法
def run(self):
...
#对象和类都可以直接调用没有固定参数
'''
# 进入源码(从urls.py的as_view进入)
# path("login/",login) --->主动执行 login 拿到 HttpResponse
# LoginView.as_view() ---> as_view 内部内嵌函数 view ---> 执行 view 获取到 Django的响应对象
# 【一】确认为类的绑定方法
@classonlymethod
def as_view(cls, **initkwargs):
# 【二】initkwargs 没给值就没有参数
for key in initkwargs:
# 【1】遍历传入的每一个键
# http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] (源码自带)
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__)
)
# 【2】去自己的类属性里面映射属性,如果没有对应的属性则报错
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)
)
#【三】 由于initkwargs没参数,所以上面的for循环不走
def view(request, *args, **kwargs):
# 【1】cls = LoginView,调用类生成一个自己的对象 self = LoginView 的对象
self = cls(**initkwargs)
# 【2】self.setup:自己没写过就去父类里面找(setup跳转)
self.setup(request, *args, **kwargs)
# 【4】校验自己是否有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__
)
# 【5】返回了一个dispatch的函数的结果(dispatch跳转)
# 结果是返回了一个Django的响应对象
return self.dispatch(request, *args, **kwargs)
view.view_class = cls
view.view_initkwargs = initkwargs
view.__doc__ = cls.__doc__
view.__module__ = cls.__module__
view.__annotations__ = cls.dispatch.__annotations__
view.__dict__.update(cls.dispatch.__dict__)
if cls.view_is_async:
markcoroutinefunction(view)
return view
# 【3】view的setup方法
def setup(self, request, *args, **kwargs):
# (1)校验自己有get方法而没有 head 方法
if hasattr(self, "get") and not hasattr(self, "head"):
# 将自己的head属性替换成get属性(head=get的内存地址)
self.head = self.get
# (2)给自己的对象初始化一个属性request对象
self.request = request
self.args = args
self.kwargs = kwargs
# 【6】进入到dispatch方法
def dispatch(self, request, *args, **kwargs):
# (1)将当前的请求方式转为全小写(对应get和post)
if request.method.lower() in self.http_method_names:
# (2)因为当前请求方式在上述列表内
# 从当前对象中映射出指定属性名对应的属性值,函数名---> 函数的内存地址
# handler:拿到get或post的函数内存地址
# self.http_method_not_allowed:如果参数不存在,则返回报错信息
handler = getattr(
self, request.method.lower(), self.http_method_not_allowed
)
else:
handler = self.http_method_not_allowed
# (3)handler get 函数的内存地址
# get()--->Django的响应对象,HttpReponse / render / redirect ...
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},
)
response = HttpResponseNotAllowed(self._allowed_methods())
if self.view_is_async:
async def func():
return response
return func()
else:
return response