zoukankan      html  css  js  c++  java
  • Django之 Cookie,Session

    复习

    1,分页

    # 利用URL携带参数page,views.py中通过request.GET来获取page参数

    # utils: 放常用工具

     

    1. 在工具包utils中自定义mypage,并用其完成分页显示(推荐使用)

    book_list.html

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Book_list</title>

        <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">

    </head>

    <body>

    <h1>Book List</h1>

    <div class="container">

        <table class="table table-bordered">

            <thead>

            <tr>

                <th>#</th>

                <th>Title</th>

                <th>Publish Date</th>

            </tr>

            </thead>

            <tbody>

            {% for book in book_list %}

                <tr>

                    <td>{{ forloop.counter }}</td>

                    <td>{{ book.title }}</td>

                    <td>{{ book.publish_date|date:'Y-m-d' }}</td>  # 格式化输出日期

                </tr>

            {% endfor %}

            </tbody>

        </table>

    </div>

     

    <nav aria-label="Page navigation" class="text-center">

        <ul class="pagination">

            {{ page_html|safe }}  # 取消浏览器自动转译功能

        </ul>

    </nav>

    <script src="/static/jquery-3.3.1.min.js"></script>

    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>

    </body>

    </html>

     

    views.py

    from django.shortcuts import render

    from app01 import models

    from utils import mypage

     

    # 用工具包utils中的自定义mypage,完成分页显示

    def book_list(request):

        data = models.Book.objects.all()

        total_num = data.count()

        current_page = request.GET.get('page')

        page_obj=mypage.Page(total_num, current_page, 'book_list',per_page=20)

        book_list = data[page_obj.data_start:page_obj.data_end]

        page_html = page_obj.page_html()

        return render(request, "book_List.html", {'book_list':book_list, 'page_html':page_html})

     

    utils -> mypage.py. (小工具,可反复使用)

    class Page(object):

        """

        这是一个自定义分页类

        可以实现Django ORM数据的分页展示

     

        使用说明:

            from utils import mypage

            page_obj = mypage.Page(total_num, current_page, 'publisher_list')

            publisher_list = data[page_obj.data_start:page_obj.data_end]

            page_html = page_obj.page_html()

            为了显示效果,show_page_num最好使用奇数  #当前页面highlight,左右对称排列

        """

     

        def __init__(self, total_num, current_page, url_prefix, per_page=10, show_page_num=11):

            """

            :param total_num: 数据的总条数

            :param current_page: 当前访问的页码

            :param url_prefix: 分页代码里a标签的前缀

            :param per_page: 每一页显示多少条数据

            :param show_page_num: 页面上最多显示多少个页码

            """

            self.total_num = total_num

            self.url_prefix = url_prefix

            self.per_page = per_page

            self.show_page_num = show_page_num

     

            self.half_show_page_num = self.show_page_num // 2

     

            total_page, more = divmod(self.total_num, self.per_page)  # divmod()得到商和余数的小元组

            if more:

                total_page += 1

            self.total_page = total_page

     

            try:

                current_page = int(current_page)  # GET得到的current_page是字符串,必须要转成int才能进行后续运算操作

            except Exception as e:

                current_page = 1

            if current_page > self.total_page:

                current_page = self.total_page

            if current_page < 1:

                current_page = 1

            self.current_page = current_page

     

            if self.current_page - self.half_show_page_num <= 1:

                page_start = 1

                page_end = self.show_page_num

            elif self.current_page + self.half_show_page_num >= self.total_page:

                page_end = self.total_page

                page_start = self.total_page - self.show_page_num + 1

            else:

                page_start = self.current_page - self.half_show_page_num

                page_end = self.current_page + self.half_show_page_num

            self.page_start = page_start

            self.page_end = page_end

     

        @property  # 将方法装饰成数据属性

        def data_start(self):

            return (self.current_page-1)*self.per_page

     

        @property

        def data_end(self):

            return (self.current_page)*self.per_page

     

        def page_html(self):

            li_list = []

            li_list.append('<li><a href="/{}/?page=1">首页</a></li>'.format(self.url_prefix))

            if self.current_page <= 1:

                prev_html = '<li class="disabled"><a aria-label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'  # disabled,当在第一页时不能选前一页

            else:

                prev_html = '<li><a href="/{}/?page={}" aria_label="Previous"><span aria-hidden="true">&laquo;</span></a></li>'.format(

                    self.url_prefix,self.current_page - 1)

            li_list.append(prev_html)

            for i in range(self.page_start, self.page_end + 1):

                if i == self.current_page:

                    tmp = '<li class="active"><a href="/{0}/?page={1}">{1}</a></li>'.format(self.url_prefix,i) # active,当前页highlight

                else:

                    tmp = '<li><a href="/{0}/?page={1}">{1}</a></li>'.format(self.url_prefix,i)

                li_list.append(tmp)

            if self.current_page >= self.total_page:

                next_html = '<li class="disabled"><a aria-label="Previous"><span aria-hidden="true">&raquo;</span></a></li>'

            else:

                next_html = '<li><a href="/{}/?page={}" aria_label="Previous"><span aria-hidden="true">&raquo;</span></a></li>'.format(

                    self.url_prefix, self.current_page + 1)

            li_list.append(next_html)

            li_list.append('<li><a href="/{}/?page={}">尾页</a></li>'.format(self.url_prefix,self.total_page))

     

            page_html = "".join(li_list)  # 连成一个大的字符串,传至前段,方便后续操作

            return page_html

     

    1. 用Django中的分页,完成显示

    views.py

    # 用django中的工具,完成分页显示;功能单薄,一般不用

    from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger

    def publisher_list(request):

        data = models.Publisher.objects.all()

        current_page = request.GET.get('page')

        page_obj = Paginator(data,10)

        try:

            publisher_list = page_obj.page(current_page)

            # has_next              是否有下一页

            # next_page_number      下一页页码

            # has_previous          是否有上一页

            # previous_page_number  上一页页码

            # object_list           分页之后的数据列表

            # number                当前页

            # paginator             paginator对象

        except PageNotAnInteger:

            publisher_list= page_obj.page(1)

        except EmptyPage:

            publisher_list = page_obj.page(page_obj.num_pages)

    return render(request,'publisher_list.html',{'publisher_list':publisher_list})

     

    publisher_list.html

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Publisher_list</title>

        <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">

    </head>

    <body>

    <h1>Publisher List</h1>

    <div class="container">

        <table class="table table-bordered">

            <thead>

            <tr>

                <th>#</th>

                <th>Publish Name</th>

            </tr>

            </thead>

            <tbody>

            {% for publisher in publisher_list %}

                <tr>

                    <td>{{ forloop.counter }}</td>

                    <td>{{ publisher.name }}</td>

                </tr>

            {% endfor %}

            </tbody>

        </table>

     

        <nav aria-label="Page navigation">

            <ul class="pagination">

                {% if publisher_list.has_previous %}

                    <li>

                        <a href="/publisher_list/?page={{ publisher_list.previous_page_number }}" aria-label="Previous">

                            <span aria-hidden="true">&laquo;</span>

                        </a>

                    </li>

                {% else %}

                    <li class="disabled">

                        <a aria-label="Previous">

                            <span aria-hidden="true">&laquo;</span>

                        </a>

                    </li>

                {% endif %}

                <li class="active"><a href="#">{{ publisher_list.number }}</a></li>

                {% if publisher_list.has_next %}

                    <li>

                        <a href="/publisher_list/?page={{ publisher_list.next_page_number }}" aria-label="Next">

                            <span aria-hidden="true">&raquo;</span>

                        </a>

                    </li>

                {% else %}

                    <li class="disabled">

                        <a aria-label="Next">

                            <span aria-hidden="true">&raquo;</span>

                        </a>

                    </li>

                {% endif %}

            </ul>

        </nav>

    </div>

    <script src="/static/jquery-3.3.1.min.js"></script>

    <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>

    </body>

     

    1. Cookie

    HTTP无状态 -> Cookie

    Cookie:服务端在返回响应的时候设置的,保存在浏览器上的键值对。

     

    复习: 

    print(request.path_info)  # 获得路径

    print(request.get_full_path())  # 获得路径+参数

     

     

    login.html

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Title</title>

    </head>

    <body>

    <form action="{{ request.get_full_path }}" method="post">

        {% csrf_token %}

        <p>Username: <input type="text" name = "username"></p>

        <p>Password: <input type="password" name="pwd"></p>

        <p><input type="submit" value="Login"></p>

    </form>

    </body>

    </html>

     

    views.py

    from django.shortcuts import render

    from django.shortcuts import HttpResponse,render,redirect

    from app01 import models

    from utils import mypage

     

    # 定义一个检测是否登陆的装饰器

    def check_login(func):

        def wrapper(request,*args,**kwargs):

            login_flag = request.get_signed_cookie("login",default="",salt="shanghais1hao")  # 获取Cookie,加盐版的盐要一致

            # login_flag = request.COOKIES.get("login", "") 

    #获取Cookie,非加盐版

     

            # default: 默认值

            # salt: 加密盐

            # max_age: 后台控制过期时间

     

            if login_flag.upper() == 'OK':

                return func(request,*args,**kwargs)

            else:

                url = request.path_info  # 获取跳转源路径

                return redirect("/login/?next={}".format(url))  # 如果是从其他页面跳转来,记录下该页面,完成验证后跳转回去

        return wrapper

     

    # 用工具包utils中的自定义mypage,完成分页显示

    @check_login

    def book_list(request):

        data = models.Book.objects.all()

        total_num = data.count()

        current_page = request.GET.get('page')

        page_obj=mypage.Page(total_num, current_page, 'book_list',per_page=20)

        book_list = data[page_obj.data_start:page_obj.data_end]

        page_html = page_obj.page_html()

        return render(request, "book_List.html", {'book_list':book_list, 'page_html':page_html})

     

    def login(request):

        if request.method == 'POST':

            username = request.POST.get('username')

            pwd = request.POST.get('pwd')

            if username == 'alex' and pwd =='alex':

                url = request.GET.get('next')  # 如果是从其他页面跳转来,跳转至该页面

                if not url:

                    url = '/publisher_list/'  # 若非从其他页面跳转来的,跳转到默认页面

                rep = redirect(url)

                rep.set_signed_cookie("login","ok",salt="shanghais1hao") 

    # 给响应设置Cookie,加密盐版

                # rep.set_cookie("login", "ok") 

    # 给响应设置Cookie

     

                # key, 键

                # value = '', 值

                # max_age = None, 超时时间

                # expires = None, 超时时间(IE requires expires, so set it if hasn't been already.)

                # path = '/', Cookie生效的路径, / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问

                # domain = None, Cookie生效的域名

                # secure = False, https传输

                # httponly = False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

     

                return rep

        return render(request,"login.html")

     

    def logout(request):

        rep = redirect('/login/')

        rep.delete_cookie('login')  # 删除用户浏览器上之前设置的cookie值

        return rep

     Session

     

    Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。依赖cookie

    # 用session前要现有一个数据库

    1. 浏览器请求来了之后,服务端给你分配一个序号(口令)(程序级别完成)

    2. 浏览器收到响应之后,把得到的口令保存在 cookie (浏览器自带)

    3. 浏览器携带着刚才得到的口令,再次发送请求 (浏览器自带)

    4. 服务端拿到口令,去后端根据口令找对应的数据(大字典)(程序级别完成)

     

    views.py

    def login(request):

        err_msg = ""

        if request.method == 'POST':

            username = request.POST.get('username')

            pwd = request.POST.get('pwd')

            is_exist = models.User.objects.filter(name=username,pwd=pwd)

            if is_exist:

                # 登陆成功

                # 1. 生成随机字符串(口令),给浏览器返回

                # 2. 在服务端开辟一块空间,用来保存对应的session数据(大字典)

                # 3. 在服务端开辟的空间中保存需要保存的键值对数据

                request.session['login'] = 'OK'

                request.session['user'] = username  # 可以插入不只一条数据

                request.session.set_expiry(60*60*24*14)  # 两周,python支持上述写法

                return redirect('/index/')

            else:

                err_msg = 'invalid username or password'

        return render(request,'login.html',{'err_msg':err_msg})

     

    def index(request):

        # 1. 判断请求中是否携带了我下发的随机字符串(口令)

        # 2. 拿着口令去后端找对应的session数据

        # 3. 根据固定的key去取固定的值

        login_flag = request.session.get('login')

        if login_flag == 'OK':

            return render(request,'index.html')

        else:

            return redirect('/login/')

     

    def logout(request):

        request.session.flush()  # 删除当前的会话数据并删除会话的Cookie

        return redirect('/login/')

     

    总结:

    # 获取、设置、删除Session中数据

    request.session['k1']

    request.session.get('k1',None)

    request.session['k1'] = 123

    request.session.setdefault('k1',123) # 存在则不设置

    del request.session['k1']

     

    # 所有 键、值、键值对

    request.session.keys()

    request.session.values()

    request.session.items()

    request.session.iterkeys()

    request.session.itervalues()

    request.session.iteritems()

     

    # 会话session的key

    request.session.session_key

     

    # 将所有Session失效日期小于当前日期的数据删除

    request.session.clear_expired()  # session数据库中的数据不会自动清除,需手动删除

     

    # 检查会话session的key在数据库中是否存在

    request.session.exists("session_key")

     

    # 删除当前会话的所有Session数据

    request.session.delete()

    # 删除当前的会话数据并删除会话的Cookie。

    request.session.flush()   # 推荐使用

    这用于确保前面的会话数据不可以再次被用户的浏览器访问

    例如,django.contrib.auth.logout() 函数中就会调用它。

     

    # 设置会话Session和Cookie的超时时间

    request.session.set_expiry(value)

    * 如果value是个整数,session会在些秒数后失效。

    * 如果value是个datatime或timedelta,session就会在这个时间后失效。

    * 如果value是0,用户关闭浏览器session就会失效。

    * 如果value是None,session会依赖全局session失效策略。

     

    1. CBV中加装饰器(Django内置的把函数装饰器转换成方法装饰器)

    方式一:加载CBV视图的get或post方法上

    views.py

    from django import views

    from django.utils.decorators import method_decorator

     

    class Home(views.View):

        @method_decorator(check_login)

        def get(self, request):

            return render(request, "home.html")

        def post(self):

            pass

     

    urls.py

    urlpatterns = [

        url(r'^home/',views.Home.as_view()),

    ]

     

    方式二:加载dispatch方法上

    # 因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。

    from django.utils.decorators import method_decorator

    class HomeView(View):

        @method_decorator(check_login)

        def dispatch(self, request, *args, **kwargs):

            return super(HomeView, self).dispatch(request, *args, **kwargs)

     

        def get(self, request):

            return render(request, "home.html")

     

        def post(self, request):

            print("Home View POST method...")

            return redirect("/index/")

     

    式三:直接加在视图类上,但method_decorator必须传 name 关键字参数

    from django.utils.decorators import method_decorator

     

    @method_decorator(check_login, name="get")

    @method_decorator(check_login, name="post")

    class HomeView(View):

        def dispatch(self, request, *args, **kwargs):

            return super(HomeView, self).dispatch(request, *args, **kwargs)

     

        def get(self, request):

            return render(request, "home.html")

     

        def post(self, request):

            print("Home View POST method...")

            return redirect("/index/")

     

    CSRF Token相关装饰器(csrf_exempt,csrf_protect)

    CSRF Token相关装饰器在CBV只能加到dispatch方法上

    csrf_protect:为当前函数强制设置防跨站请求伪造功能,即便settings没设置全局中间件。

    csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

     

    views.py

    from django.views.decorators.csrf import csrf_exempt, csrf_protect

    @csrf_exempt

    def login(request):

        err_msg = ""

        if request.method == 'POST':

            username = request.POST.get('username')

            pwd = request.POST.get('pwd')

            is_exist = models.User.objects.filter(name=username,pwd=pwd)

            if is_exist:

                # 登陆成功

                # 1. 生成随机字符串(口令),给浏览器返回

                # 2. 在服务端开辟一块空间,用来保存对应的session数据(大字典)

                # 3. 在服务端开辟的空间中保存需要保存的键值对数据

                request.session['login'] = 'OK'

                request.session['user'] = username  # 可以插入不只一条数据

                request.session.set_expiry(60*60*24*14)  # 两周,python支持上述写法

                return redirect('/index/')

            else:

                err_msg = 'invalid username or password'

    return render(request,'login.html',{'err_msg':err_msg})

     

    logins.html

    <!DOCTYPE html>

    <html lang="en">

    <head>

        <meta charset="UTF-8">

        <meta name="viewport" content="width=device-width, initial-scale=1">

        <title>Title</title>

    </head>

    <body>

    <form action="{{ request.get_full_path }}" method="post">

    {#    {% csrf_token %}#}

        <p>Username: <input type="text" name = "username"></p>

        <p>Password: <input type="password" name="pwd"></p>

        <p><input type="submit" value="Login"></p>

        <p style="color:red">{{ err_msg }}</p>

    </form>

    </body>

    </html>

     其他

    有时间这片重新写  有点乱

    [链接]2018年不容错过的Django全栈项目YaDjangoBlog

    https://zhuanlan.zhihu.com/p/33903527

     

     https://www.cnblogs.com/liwenzhou/p/8343243.html

    1. 补充

     

     

  • 相关阅读:
    Checking Types Against the Real World in TypeScript
    nexus pip proxy config
    go.rice 强大灵活的golang 静态资源嵌入包
    几个golang 静态资源嵌入包
    rpm 子包创建学习
    Rpm Creating Subpackages
    ava 类似jest snapshot 功能试用
    ava js 测试框架基本试用
    The Architectural Principles Behind Vrbo’s GraphQL Implementation
    graphql-compose graphql schema 生成工具集
  • 原文地址:https://www.cnblogs.com/maojiang/p/9229347.html
Copyright © 2011-2022 走看看