zoukankan      html  css  js  c++  java
  • Django View视图

    视图view

    一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应。响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片。

    无论视图本身包含什么逻辑,都要返回响应。大家约定成俗将视图放置在项目(project)或应用程序(app)目录中的名为views.py的文件中。

    • Django使用请求Request和响应Response来给整个系统传递状态
    • 当用户请求一个页面时,Django创建一个包含元数据和请求内容的HttpRequest对象。然后Django加载适当的视图,HttpRequest对象作为视图函数的第一个参数,每个视图负责返回一个HttpResponse对象。
    from django.http import HttpResponse
    
    def show(req):
        name = 'Jerry'
        content = '<h1>hello %s!</h1>' % name
        return HttpResponse(content)

     首先从 django.http模块导入了HttpResponse类。然后定义了show函数。它就是视图函数;每个视图函数的第一个参数都为request,其实是一个HttpRequest对象。视图函数中封装了一个HTML格式的字符串,传入HttpResponse()后,实例化一个HttpResponse对象并返回。

    当浏览器向服务端请求一个页面时,Django创建一个HttpRequest对象,该对象包含关于请求的元数据。然后,Django加载相应的视图,将这个HttpRequest对象作为第一个参数传递给视图函数。

    HttpRequest对象

    对象属性

    HttpRequest.scheme:字符串(http/https)表示http还是https请求

    HttpRequest.body:原始的http请求主体

    HttpRequest.path:完整的请求路径,不包括域

    HttpRequest.method:请求中使用的HTTP方法(GET/POST)

    HttpRequest.encoding:请求的字符集

    HttpRequest.GET:类似字典的对象,包含所有给定的HTTP GET参数

    HttpRequest.POST:类似字典的对象,包含所有给定的HTTP POST参数,前提是请求包含表单数据。

    HttpRequest.COOKIES:客户端cookies信息,字典类型

    HttpRequest.FILES:一个包含所有文件对象的字典. key是<inputtype="file" name="" />中name的值,每一个value是一个上传的文件对象,如果要上传文件需要在 <form> 标签中添加 enctype="multipart/form-data",不然收到的是一个空值

    HttpRequest.META:请求的META属性

    HttpRequest.headers:一个不区分大小写的类似dict的对象,包含请求中所有HTTP加前缀的标题的访问

    def index(request):
    
        print(request.scheme)  #http
        print(request.body)  #b''
        print(request.path)  #/app/
        print(request.method)  #GET
        print(request.encoding)  #None
        print(request.GET)  #<QueryDict: {'name': ['aaa']}>
        print(request.POST)  #<QueryDict: {}>
        print(request.META.get('CONTENT_TYPE'))  #text/plain
        print(request.META.get('REMOTE_ADDR'))  #127.0.0.1
        print(request.headers.get('Connection'))  #keep-alive
        print(request.headers.get('Accept-Encoding'))  #gzip, deflate, br
    
        return HttpResponse('<h1>hello</h1>')
    HttpRequest属性

    对象方法

    HttpRequest.get_host():返回当前服务器的IP和端口

    HttpRequest.get_port():返回当前服务器原始端口

    HttpRequest.get_full_path():返回附加查询的请求路径

    HttpRequest.is_secure():如果返回True,请求时安全的,也就是https协议

    HttpRequest.is_ajax():是否为ajax请求

    def index(request):
    
        print(request.get_host())  #127.0.0.1:8000
        print(request.get_port())  #8000
        print(request.get_full_path())  #/app/?name=aaa
        print(request.is_secure())  #False
        print(request.is_ajax())  #False
    
        return HttpResponse('<h1>hello</h1>')
    HttpRequest方法

    HttpResponse对象

    对象属性

    HttpResponse.content:表示内容的字节字符串,如果需要,从字符串编码。

    HttpResponse.charset:一个字符串,表示将在其中编码响应的字符集。如果未在HttpResponse实例化时间给出,则将从中提取 content_type,如果不成功,DEFAULT_CHARSET则将使用该 设置。

    HttpResponse.status_code:该响应的HTTP状态代码。除非reason_phrase明确设置,否则修改 status_code构造函数外部的值也会修改值reason_phrase。

    HttpResponse.reason_phrase:响应的HTTP原因短语。它使用了HTTP标准的默认原因短语。除非明确设置,否则reason_phrase由status_code的值确定。

    对象方法

    HttpResponse.__init__(content = b'', content_type=None, status=200, reason=None, charset=None)

    使用给定的页面内容和内容类型实例化对象。

    • content:最常见的是迭代器,字节串或字符串。其他类型将通过编码其字符串表示形式转换为bytestring。
    • content_type:是可选的字符集编码完成的MIME类型,用于填充HTTP Content-Type标头。
    • status:响应的HTTP状态代码。
    • reason:HTTP响应短语。如果未提供,将使用默认短语。
    • charset:编码响应的字符集。如果没有给出,它将从中提取content_type,如果不成功,DEFAULT_CHARSET将使用该设置。

    HttpResponse.set_cookie(key, value, max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None):设置一个cookie。

    HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None):在对cookie设置之前进行签名加密,加密后的cookie中的键值对将是密文的;获取cookie信息时也要使用相对应方法HttpRequest.get_signed_cookie()。

    HttpResponse.delete_cookie(key,path ='/',domain = None):使用给定的key删除对应的cookie,path、domain应该指定和set_cookie()时相同的值。

    render()

    结合一个给定的模板和一个给定的上下文字典, 并返回一个渲染后的HttpResponse对象。

    def render(request, template_name, context=None, content_type=None, status=None, using=None):
        """
        Return a HttpResponse whose content is filled with the result of calling
        django.template.loader.render_to_string() with the passed arguments.
        """
        content = loader.render_to_string(template_name, context, request, using=using)
        return HttpResponse(content, content_type, status)

    必需参数:

    • request:用于生成此响应的HttpRequest对象;
    • template_name:要使用的模板的完整名称;

    可选参数:

    • context:添加到模板上下文的一个字典,默认是一个空字典, 通过它可以向模板传入自定义参数,视图将在渲染模板之前调用它;
    • content_type:生成的文档要使用的MIME类型.,默认为DEFAULT_CONTENT_TYPE设置的值"text/html";
    • status:响应的状态码. 默认为200;
    • useing:用于加载模板的模板引擎的名称。
    from django.shortcuts import render
    
    def my_view(request):
        active = True
        return render(request, 'index.html', {'name': active}, content_type='application/xhtml+xml')

    redirect()

    默认返回一个临时的重定向,传递permanent=True可以返回一个永久的重定向。临时重定向(响应状态码: 302)和永久重定向(响应状态码: 301)对普通用户来说是没什么区别的, 它主要面向的是搜索引擎的机器人。

    def redirect(to, *args, permanent=False, **kwargs):
        """
        Return an HttpResponseRedirect to the appropriate URL for the arguments
        passed.
        """
        redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
        return redirect_class(resolve_url(to, *args, **kwargs))

    参数可以是:

    • 一个模型: 将调用模型的get_absolute_url()函数
    • 一个视图, 可以带有函数: 可以使用urlresolvers.reverse来反向解析名称
    • 一个绝对的或相对的URL, 将原封不动的作为重定向的位置
    from django.shortcuts import redirect
    
    def my_view(request):
        return redirect('/some/url/')
    
    def my_view(request):
        return redirect('https://example.com/')

    Cookie、Session

    浏览器请求服务器是无状态的。无状态指一次用户请求时,浏览器、服务器无法知道之前这个用户做过什么,每次请求都是一次新的请求。无状态的应用层面的原因是:浏览器和服务器之间的通信都遵守HTTP协议。根本原因是:浏览器与服务器是使用Socket套接字进行通信的,服务器将请求结果返回给浏览器之后,会关闭当前的Socket连接,而且服务器也会在处理页面完毕之后销毁页面对象。

    但有时候用户需要保持登陆状态,或者一些。 实现会话保持主要有两种方式:cookie和session。

    Cookie

    Cookie是由服务器端生成,发送给User-Agent(一般是浏览器),浏览器会将Cookie的key/value保存到某个目录下的文本文件内,下次请求同一网站时就发送该Cookie给服务器(前提是浏览器设置为启用cookie)。通常情况下,它用于判断两个请求是否来自同一个浏览器 - 例如,保持用户登录。它记住无状态HTTP协议的有状态信息。

    Cookie主要用于三个目的:

    1. 会话管理,登录,购物车,游戏分数或服务器应记住的任何其他内容;
    2. 个性化,用户首选项,主题和其他设置;
    3. 跟踪,记录和分析用户行为。

    特点

    cookie数据保存在客户端,以key-value存储;

    cookie有过期时间,默认关闭浏览器过期;

    cookie是基于域名安全的;

    当浏览器请求某网站时,会将本网站下所有Cookie信息提交给服务器。

    Session

    session是存储在后端数据库中的键值对,django生成一个随机字符串sessionid作为key,用户的信息作为value;

    当浏览器第一次发送请求时,服务器会生成与用户相关的session,然后将在sessionid放入cookie中返回给浏览器,浏览器会将此cookie保存在本地;之后每次请求时浏览器都会将这个cookie发给服务器,服务器在提取到sessionid后,会根据这个随机字符串去数据库中找出这个请求者的信息。

    特点

    session数据保存在服务器,以key-value存储;

    session依赖于cookie,每个客户端的session信息标识保存在客户端cookie中;

    session也有过期时间,django中session过期时间默认2周,flask开启session过期时间之后默认30天;

    在视图中使用cookie

    HttpResponse.set_cookie(key, value, max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None)

    设置一个cookie

    • key、value:设置cookie中的键值,都是字符串类型;
    • max_age:一个整数,表示在指定秒数后过期;
    • expires:一个datetime或timedelta对象,会话将在这个指定的日期/时间过期;可以不设置,django会根据max_age自动设置;
    • path:指定一个路径,只有在这个路径下才可以访问到cookie;
    • domain:如果你想设置一个跨域的cookie。例如, domain="example.com"将设置域www.example.com,blog.example.com等可读的cookie。否则,cookie只能由设置它的域读取;
    • Secure:https协议访问;
    • httponly:如果为True,就阻止客户端的JavaScript操作cookie。
    def login(request):
        re = redirect('/app/index.html')  #实例一个redirect HttpResponse对象
        re.set_cookie('username', username, max_age=20)  #为对象设置cookie信息
        return re  #返回HttpResponse对象)

    HttpResponse.set_signed_cookie(key, value, salt='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=False, samesite=None):在对cookie设置之前进行签名加密,加密后的cookie中的键值对将是密文的;获取cookie信息时也要使用相对应方法HttpRequest.get_signed_cookie();

    HttpRequest.COOKIES.get(key, None):通过请求对象的COOKIES属性获取;

    HttpRequest.get_signed_cookie(key):获取加密cookie的方法;

    HttpResponse.delete_cookie(key,path ='/',domain = None):使用给定的key删除对应的cookie,path、domain应该指定和set_cookie()时相同的值。

    在视图中使用session

    当SessionMiddleware激活时,每个HttpRequest 对象 - 任何Django视图函数的第一个参数,将具有一个 session属性,这是一个类似字典的对象。request.session可以在视图中的任何位置查看编辑它。

    backends.base.SessionBase类是所有的session对象的基类;它具有标准的字典方法

    # 设置session
    request.session[key] = value
    request.session.setdefault(key, value)
    
    # 修改session
    request.session[key] = value
    
    # 将新的字典更新进去
    request.session.update(dicts)
    
    # 获取session
    request.session.get(key)
    request.session.keys()
    request.session.values()
    request.session.items()
    
    # 设置过期时间
    request.session.set_expiry()
    # 获取过期时间、日期
    request.session.get_expiry_age()
    request.session.get_expiry_date()
    # 是否关闭浏览器时session过期
    request.session.get_expire_at_browser_close()
    # 从数据库存储中删除过期的会话
    request.session.clear_expired()
    
    # 删除指定key
    del request.session[key]
    request.session.pop(key)
    
    # 清空session,不会删除数据库
    request.session.clear()
    # 删除session_key的session数据,删除数据库
    request.session.delete(session_key=None)
    request.session.flush()
    
    # 创建一个key唯一的新的session对象,并保存
    request.session.create()
    
    # 保存session数据,如果must_create = True则创建新session
    request.session.save(must_create=False)
    
    # 创建新的session_key,同时保留当前session数据
    request.session.cycle_key()
    
    # 加载session,返回一个字典
    request.session.load()
    
    # 如果session为空,返回True
    request.session.is_empty()
    
    # 如果session_key已存在,则返回True
    request.session.exists(session_key)
    
    # 包含sessionid的属性
    request.session.session_key
    
    # 通过modified属性可以明确告诉session对象它已经被修改
    request.session.modified = True
    session对象方法

    基于类的视图

    使用基于类的视图

    views.py

    from django.shortcuts import render, redirect
    from . import models
    from django import views
    
    class Login(views.View):
        # 重写get()方法,前端get请求执行此方法
        def get(self, request, *args, **kwargs):
            return render(request, 'myapp/login.html')
    
        # 重写post()方法,前端post请求执行此方法
        def post(self, request, *args, **kwargs):
            # 从前端请求获取用户信息
            username = request.POST.get('username')
            password = request.POST.get('password')
            # 从数据库中获取与用户信息相同的对象个数
            user_auth = models.Administrator.objects.filter(username=username, password=password).count()
            # 如果用户信息验证通过
            if user_auth:
                # 设置session
                request.session['username'] = username
                request.session['password'] = password
                request.session['active'] = True
                # 实例化重定向对象
                httpresponse = redirect('/app/index.html')
                # 返回重定向
                return httpresponse
            else:
                # 用户验证不通过,返回错误信息
                login_error = '登陆失败'
                return render(request, 'myapp/login.html', {'login_error': login_error})
    基于view类的用户登陆

    当使用类封装view函数后,在URLconf中将配置类属性as_view() 作为参数来调用。

    当一个请求到达的 URL 被关联模式匹配时,这个类方法返回一个函数。这个函数创建一个类的实例,调用 setup() 初始化它的属性,然后调用 dispatch() 方法。观察请求并决定它是GET和POST

    from django.contrib import admin
    from django.urls import path, include, re_path
    from myapp.views import Login
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        re_path(r'login.html$', Login.as_view()),
    ]
    urls.py

    装饰类

    类上的方法与独立函数完全不同,因此不能应用函数装饰器到方法上,需要先将它转换为方法装饰器。method_decorator装饰器转换函数。

    假设需要定义两个装饰器,可以把两个装饰器防入list中,然后传入method_decorator()中。

    from django.shortcuts import render, redirect
    from django import views
    from django.utils.decorators import method_decorator
    
    def is_login(f):
        def inner(request, *args):
            # 获取请求中的session信息
            username = request.session.get('username')
            # 如果存在session信息,返回执行函数
            if username:
                return f(request, *args)
            # 如果不存在则跳转至登陆页面
            else:
                return redirect('/login.html')
        return inner
    
    class Index(views.View):
        @method_decorator(is_login)
        def get(self, request):
            session = request.session.get('username')
            return render(request, 'myapp/index.html', {'user': session})
    方法前装饰器

    也可以直接把装饰器加在类上,然后参数name指定被装饰的方法

    @method_decorator(is_login, name='get')
    class Index(views.View):
        def get(self, request):
            session = request.session.get('username')
            return render(request, 'myapp/index.html', {'user': session})
    类前装饰器

    如果一个类的所有的请求方法都需要加装饰器,可以直在dispatch方法前添加;因为当请求到达时,会先调用dispatch方法,判断请求方法,再去调用对应的方法。

    class Index(views.View):
        @method_decorator(is_login)
        def dispatch(self, request, *args, **kwargs):
            #返回父类dispatch方法结果
            return super().dispatch(request, *args, **kwargs)
    
        def get(self, request):
            session = request.session.get('username')
            print(session)
            return render(request, 'myapp/index.html', {'user': session})
    dispatch
  • 相关阅读:
    【USACO】接住苹果
    【题解】任务分配
    【伪·题解】高级打字机
    【noi openjudge题解】最低通行费
    【USACO】草地排水
    【POJ2186】受牛仰慕的牛
    【NOIP2011提高组】选择客栈
    [bzoj1026][SCOI2009]windy数 (数位dp)
    [bzoj1025][SCOI2009]游戏 (分组背包)
    [bzoj1024][SCOI2009]生日快乐 (枚举)
  • 原文地址:https://www.cnblogs.com/houyongchong/p/view.html
Copyright © 2011-2022 走看看