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
posted on 2024-06-26 21:10  晓雾-Mist  阅读(7)  评论(0)    收藏  举报