Python基础day56 Django视图层相关

发布时间 2023-08-01 19:55:16作者: 吼尼尼痛

视图层

三板斧问题

在视图函数中写函数跟普通函数不太一样,Django中使用的是局部的request

所有的视图函数不能够没有返回值,并且返回值还必须是HttpResponse对象

# 错误代码
The view app01.views.index didn't return an HttpResponse object. It returned None instead.

其实我们的三板斧方法返回的都是HttpResponse对象

def index(request):
    return HttpResponse('hello world')

在flask中request使用的是全局的request

from ... import request
def index():
    pass

def func():
    pass

JsonResponse序列化

json格式的数据?

  主要就是实现跨语言数据传输

现在实现跨语言数据传输的都是json,在以前使用的是xml

微信支付朝微信的后端发送参数的时候,使用的就是xml

# json格式的数据特点:
{"username":"kevin","age":18}
# 是以字符串形式保存的

# 之前学的如何序列化?
import json
json.dumps    ------------------->JSON.stringify()
json.loads      ------------------->JSON.parse()

# 在JS中是如何做的
JSON.stringify()
JSON.parse()

在Django中如何去序列化

# js中的对象
obj = new Object() # {}
obj = {} # {}

obj.username = 'kevin' # {'username':'kevin'}

consolo.log(obj.username)

from django.http import JsonResponse
def index(request):
    # return render(request, 'index.html')
    # return HttpResponse("index")
    # 追代码----》点进去这个方法去看源码
    # return render(request, "index.html", context={})
    # return redirect()
    d = {'username': 'kevin哈喽', 'age': 18}
    # In order to allow non-dict objects to be serialized set the safe parameter to False.
    l = [1, 2 , 3, 4]
    # 序列化列表
    return JsonResponse(l,safe=False)
    # 如何去序列化,以前的方法
    import json
    # d_json = json.dumps(d,ensure_ascii=False) # 字符串
    # res = JsonResponse(d_json)
    # print(res)  # <JsonResponse status_code=200, "application/json">
    # return HttpResponse(d_json)
  # 序列化并且转码表示中文
  return JsonResponse(d, json_dumps_params={'ensure_ascii': False})
  

form表单上传文件

普通版本

def ad_files(request):
    # 接收提交的文件数据
    # POST只能够获取到post请求的普通数据,拿不到文件数据
    print(request.POST)  # <QueryDict: {}>
    # 接收文件数据
    print(request.FILES)  # <MultiValueDict: {'my_file': [<InMemoryUploadedFile: 弥豆子.jpg (image/jpeg)>]}>
    if request.method == 'POST':
        # 获取文件数据
        file_obj = request.FILES.get('my_file')
        # 上传
        with open(file_obj.name, 'wb') as z:
            for line in file_obj:
                z.write(line)
    return render(request, 'ad_files.html')

随机文件名版本

# 生成随机字符串
def get_random(request):
    random.seed()  # 重新生成随机数种子
    r_int = str(random.randint(1, 9))
    r_str_upper = str(chr(random.randint(65, 90)))
    r_str_lower = str(chr(random.randint(97, 122)))
    r_str = ''
    for i in range(5):
        c_str = random.choices([r_int, r_str_upper, r_str_lower])
        r_str += ''.join(c_str)
    return r_str

def ad_files(request):
    # 接收提交的文件数据
    # POST只能够获取到post请求的普通数据,拿不到文件数据
    print(request.POST)  # <QueryDict: {}>
    # 接收文件数据
    print(request.FILES)  
# <MultiValueDict: {'my_file': [<InMemoryUploadedFile: 弥豆子.jpg (image/jpeg)>]}>
    if request.method == 'POST':
        # 获取文件数据
        file_obj = request.FILES.get('my_file')
        # 拿到上面写的随机字符串
        ran_str = get_random(request)
        # 将随机字符串和文件名拼在一起,防止上传文件名出现重复
        file_name = ran_str + file_obj.name
        # 上传
        with open(file_name, 'wb') as z:
            for line in file_obj:
                z.write(line)
    return render(request, 'ad_files.html')

request对象的其他前几个方法

def z_request(request):
    print(request.path)  # /z_request/只能拿到地址
    print(request.path_info)  # /z_request/只能拿到地址
    print(request.get_full_path())  # /z_request/?username=kevin&age=11  能拿到地址和后面的参数
    return HttpResponse('z_request')
request.body # 现在先不学,它能够接收浏览器发过来的二进制数据,BBS项目中学

C(class)BV的书写和F(function)BV的写法

# 目前写的都是 FBV:function based view 基于函数的师徒
# 在视图文件中书写类 CBV: class based view 基于类的视图
'''
postman的官网地址:https://www.postman.com/downloads/
apizza的挂网地址:http://www.apizza.net/
'''
# 所有的类必须继承django的view类
from django.views import View
# 路由写法
    # CBV的路由
    url('^login/', views.MyLogin.as_view()),   

class MyLogin(View):
    # 类里面的方法名字不能够随便写,目前只能写get post等
    # 访问这个地址必须是get请求方式
    def get(self, request):
        # get() takes 1 positional argument but 2 were given
        print("get")
        return HttpResponse("get")

    # 访问这个方法必须是psot请求方式
    # 通过form表单发送post请求
    # 出了form表单,我们还可以使用工具来模拟
    def post(self,request):
        print("post")
        return HttpResponse("post")

CBV的源码分析

# 我们第一次看Django的源码,面试题:你都看过Django的哪些源码,简单说说?

# CBV的源码、settings的源码、权限、频率、认证的、签发token的源码

看源码的步骤是先找到源码的入口
CBV的入口在哪里呢?
path('login/', views.MyLogin.as_view()),

views.MyLogin.as_view()

"""
    类名可以调用哪些方法:
        1. 方法被@classmethod装饰器修饰的方法
            类名来调用类方法有什么特殊之处:
                会把类名自动当成第一个参数传递给方法的第一个形参cls
                对象调用方法把对象自己当成第一个参数传给方法的第一个形参self
            
        2. 被@staticmethod装饰器修饰的方法
"""
# 回头复习面向对象的方法调用

# 第一步
@classonlymethod
    def as_view(cls, **initkwargs):
        # cls:MyLogin
        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)
    
        return view
    
# 第二步:
path('login/', View.view),

# 第三步:
当请求来的时候,开始匹配路由login,就会调用View.view()

# 第四步
        def view(request, *args, **kwargs):
            # self = MyLogin(**initkwargs)
            self = cls(**initkwargs)
            """
                self: MyLogin()
            """
            return self.dispatch(request, *args, **kwargs) # 这句话是最重要的
 # 第五步:self.dispatch(request, *args, **kwargs) 
# 第六步:找到了View类里面的dispatch方法
第七步:
    def dispatch(self, request, *args, **kwargs):
            # getattr: 反射
            # 反射
            # getattr setattr delattr hasattr
            # handler = getattr(self, 'get', self.http_method_not_allowed)
            # handler = getattr(self, 'post', self.http_method_not_allowed)
            # handler就是方法名,对象
            # hander = get
            # hander = post
            # hander = self.http_method_not_allowed
        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)
    

# 问题:如何让我写的CBV类只支持get请求或者只支持post请求?
源码是用来看的,不是用来改的,有时候也能够改,但是你不行,你这个阶段先不要想着改人家源码的


class MyLogin(View):
    http_method_names = ['get',]
    # 类里面的方法名字不能够随便写,目前只能写get post等
    # 访问这个地址必须是get请求方式
    def get(self, request):
        # get() takes 1 positional argument but 2 were given
        print("get")
        return HttpResponse("get")

模板层

模板变量之分配

模板中取值一定要使用句点符  .

模板中的函数一定不能够加括号

# views
def func(request):
    d = {'username': 'jack'}
    a = 1
    b = 1.1
    c = 'hello boy'
    e = [1, 2, 3]
    f = (1, 2, 3)
    g = True
    h = {1, 2, 3}

    def index():
        print('index')
        return 'index'

    class login():
        print('login')

        def index(self):
            return 'login.index'

    return render(request, 'func.html', locals())

# html
<body>
{{ a }}
{{ b }}
{{ c }}
{{ d }}
{{ e.1 }}
{{ f.2 }}
{{ g }}
{{ h }}
{{ index }}
{{ login.index }}
</body>
# 结果
# 1 1.1 hello boy {'username': 'jack'} 2 3 True {1, 2, 3} index login.index

模板之过滤器

# Django自带的过滤器有好几十、但是我们没必要全部记住,只需要记住几个就行了
语法:
    {{ obj|过滤器名称:参数 }}  变量名字|过滤器名称:变量

案例:
# html
{#判定res的值,为False就执行default后面的#}
{{ res|default:'你好啊' }}
{#计算长度,无法计算就返回0#}
{{ res_len|length }}
{#返回数字对应的'人类可读的'文件大小#}
{{ res_size|filesizeformat }}
{#前段返回日期格式时间#}
{{ res_data|date:'Y-m-d H:m:s' }}
{#截取字符串,后面的用...代替#}
{{ res_trunc|truncatechars:9 }}
{#将字符串形式的前端语句生效#}
{{ res_safe|safe }}
{{ res_html }}
 
# views
def z_filter(request):
    res = True
    res_len = 'hello'
    res_size = 199999
    import datetime
    res_data = datetime.datetime.now()
    res_trunc = 'hello good boy'
    # 后端生效前端代码
    res_safe = '<h1>safe</h1>'
    # 第二种方式
    from django.utils.safestring import mark_safe
    res_html = mark_safe('<h2>html</h2>')
    return render(request, 'z_filter.html', locals())