GVKun编程网logo

Django;如何更改django.contrib.sessions使用的表名?(django修改admin页面)

28

本文将为您提供关于Django;如何更改django.contrib.sessions使用的表名?的详细介绍,我们还将为您解释django修改admin页面的相关知识,同时,我们还将为您提供关于12D

本文将为您提供关于Django;如何更改django.contrib.sessions使用的表名?的详细介绍,我们还将为您解释django修改admin页面的相关知识,同时,我们还将为您提供关于12 Django cooking与session、25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)、Django - cookie & session、Django - Cookie、Session、自定义分页和Django分页器的实用信息。

本文目录一览:

Django;如何更改django.contrib.sessions使用的表名?(django修改admin页面)

Django;如何更改django.contrib.sessions使用的表名?(django修改admin页面)

我如何在’django.contrib.sessions.models’中的Meta类中更改信息,以便我的项目可以具有统一的表名,但应用程序的功能相同?

谢谢

答案1

小编典典

您可以尝试以下方法:

from django.contrib.sessions.models import SessionSession.Meta.db_table = ''my_session''

编辑 以上解决方案会引发错误,但可以进行以下工作:

from django.contrib.sessions.models import SessionSession._meta.db_table = "my_session"

12 Django cooking与session

12 Django cooking与session

一.会话跟踪技术

1.什么是会话跟踪技术

我们需要先了解一下什么是会话!可以把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。例如你给10086打个电话,你就是客户端,而10086服务人员就是服务器了。从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束。在通话过程中,你会向10086发出多个请求,那么这多个请求都在一个会话中。

在JavaWeb中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束.

在一个会话的多个请求中共享数据,这就是会话跟踪技术;例如在一个会话中的请求如下:

  • 请求银行主页;
  • 请求登陆(请求参数是用户名和没密码);
  • 请求转账(请求参数与转账相关的数据);
  • 请求信用卡还款(请求参数与还款相关的数据)

在这上会话中当前用户信息必须在这个会话中共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款!这就说明我们必须在一个会话过程中有共享数据的能力。

2.会话路径技术使用Cookie或session完成

我们知道HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术.

二.Cookie概述

1.什么是Cookie

Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie是key-value结构,类似于一个python中的字典。随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。 Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!

 

2.Cookie规范

  • Cookie大小上限为4KB
  • 一个服务器最多在客户端上保存20个Cookie
  • 一个浏览器最多保存300个Cookie

上面的数据只是HTTP的Cookie规范,但在浏览器大战的今天,一些浏览器为了打败对手,为了展现自己的能力起见,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现把你硬盘占满的可能! 
注意,不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。

3.Cookie与HTTP头

Cookie是通过HTTP请求和响应头在客户端和服务端传递的:

  • Cookie:请求头,客户端发送给服务器端
  • 格式:Cookie:a=A; b=B; c=C。即多个Cookie用分号隔开;
  • Set-Cookie:响应头,服务端发送给客户端;
  • 一个Cookie对象一个Set-Cookie: Set-Cookie: a=A Set-Cookie: b=B Set-Cookie: c=C

4.Cookie的覆盖

如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie: a=A;第二请求服务器端发送的是:Set-Cookie: a=AA,那么客户端只留下一个Cookie,即:a=AA。

5.Django中的Cookie语法

(1).设置Cookie:

rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()
  
rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'',...) 

(2).源码:

''''''
class HttpResponseBase:

        def set_cookie(self, key,                 键
                     value='''',            值
                     max_age=None,        超长时间 
                              cookie需要延续的时间(以秒为单位)
                              如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止。

                     expires=None,        超长时间
                                 expires默认None ,cookie失效的实际日期/时间。 
                                

                     path=''/'',           Cookie生效的路径,
                                                 浏览器只会把cookie回传给带有该路径的页面,这样可以避免将
                                                 cookie传给站点中的其他的应用。
                                                 / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
                     
                             domain=None,         Cookie生效的域名
                                                
                                                  你可用这个参数来构造一个跨站cookie。
                                                  如, domain=".example.com"
                                                  所构造的cookie对下面这些站点都是可读的:
                                                  www.example.com 、 www2.example.com 
                                 和an.other.sub.domain.example.com 。
                                                  如果该参数设置为 None ,cookie只能由设置它的站点读取。

                     secure=False,        如果设置为 True ,浏览器将通过HTTPS来回传cookie。
                     httponly=False       只能http协议传输,无法被JavaScript获取
                                                 (不是绝对,底层抓包可以获取到也可以被覆盖)
                  ): pass

''''''

(3).获取Cookie:

request.COOKIES

(4).删除Cookie

response.delete_cookie("cookie_key",path="/",domain=name)

三.session

Session是服务器端技术,利用这个技术,服务器在运行时可以 为每一个用户的浏览器创建一个其独享的session对象,由于 session为用户浏览器独享,所以用户在访问服务器的web资源时 ,可以把各自的数据放在各自的session中,当用户再去访问该服务器中的其它web资源时,其它web资源再从用户各自的session中 取出数据为用户服务。

1.Django中的session语法

1、设置Sessions值
          request.session[''session_name''] ="admin"
2、获取Sessions值
          session_name = request.session["session_name"]
3、删除Sessions值
          del request.session["session_name"]
4、flush()
     删除当前的会话数据并删除会话的Cookie。
     这用于确保前面的会话数据不可以再次被用户的浏览器访问
5get(key, default=None)
  
fav_color = request.session.get(''fav_color'', ''red'')
  
6、pop(key)
  
fav_color = request.session.pop(''fav_color'')
  
7、keys()
  
8、items()
  
9、setdefault()
  
  
10 用户session的随机字符串
        request.session.session_key
   
        # 将所有Session失效日期小于当前日期的数据删除
        request.session.clear_expired()
   
        # 检查 用户session的随机字符串 在数据库中是否
        request.session.exists("session_key")
   
        # 删除当前用户的所有Session数据
        request.session.delete("session_key")
   
        request.session.set_expiry(value)
            * 如果value是个整数,session会在几秒数后失效。
            * 如果value是个datatime或timedelta,session就会在这个时间后失效。
            * 如果value是0,用户关闭浏览器session就会失效。
            * 如果value是None,session会依赖全局session失效策略。
更多

 

2.session配置

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
   
a. 配置 settings.py
   
    SESSION_ENGINE = ''django.contrib.sessions.backends.db''   # 引擎(默认)
       
    SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
    SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
    SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
    SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
    SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
    SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
    SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
session配置

 

 

 

 

 

 

 

 

 

 

 

 

 

 

25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)

25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)

25 Jun 18

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

一、分页

# 利用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>

    <table>

        <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">

    <ul>

        {{ 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 ><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 ><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><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>

    <table>

        <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>

            {% 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>

                    <a aria-label="Previous">

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

                    </a>

                </li>

            {% endif %}

            <li><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>

                    <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>

 

二、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。

# 用session前要现有一个数据库(一定要执行makemigrations, migrate两条命令,即使models无变化)

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失效策略。

 

四、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>{{ err_msg }}</p>

</form>

</body>

</html>

 

六、其他

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

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

 

七、补充

 

Django - cookie & session

主要内容:

  • 1.cookie
  • 2.session

1.cookie

1.1 cookie的概述

(1) cookie的由来

由于HTTP协议是无状态的。

  • 无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。
  • 一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的
  • 状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。

(2) cookie的定义

Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

(3)cookie的原理

cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。

1.2 Django中操作cookie

 (1)获取cookie

request.COOKIES[''key'']
request.get_signed_cookie(''key'', default=RAISE_ERROR, salt='''', max_age=None)

get_signed_cookie方法的参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间

(2)设置cookie

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'',...)

参数:

  • 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获取(不是绝对,底层抓包可以获取到也可以被覆盖)

 (3)删除cookie

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 删除用户浏览器上之前设置的user的cookie值
    return rep

# cookie 版的登录校验

from django.shortcuts import render,redirect,HttpResponse

def login_required(func):
    def inner(request,*args,**kwargs):
        is_login = request.COOKIES.get(''is_login'')
        #此时未登录前想要访问的页面
        return_url = request.path_info
        if is_login ==''1'':
            ret = func(request,*args,**kwargs)
        else:
            #此时的标准地址,需要添加刚才想要访问的地址
            ret= redirect(''/login/?return_url ={}''.format(return_url))
        return ret
    return inner


def login(request):
    if request.method ==''POST'':
        user = request.POST.get(''user'')
        pwd = request.POST.get(''pwd'')
        if user ==''alex'' and pwd == ''123'':
            ret = redirect(''/home/'')
            #response 对象
            #set_cookie中有两个参数key &value 必填
            ret.set_cookie(''is_login'',''1'')
            return ret
        else:
            return render(request, ''login.html'')
    return render(request,''login.html'')

#注;本质上是设置一个set_cookie的响应头,发请求时候是设置一个cookie的请求头

@login_required
def index(request):
    return HttpResponse(''index'')

@login_required
def home(request):
    # print(request.COOKIES,type(request.COOKIES))
    # is_login = request.COOKIES.get(''is_login'')
    # if is_login !=1:
    #     return redirect(''/login/'')
    return HttpResponse(''home'')

2. session

2.1 session的概述

 session的由来

  • Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。
  • 问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。
  • 我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。
  • 总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。
  • 另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

2.2 session的相关方法

# 获取、设置、删除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的key在数据库中是否存在
request.session.exists("session_key")

# 删除当前会话的所有Session数据(删除服务器的session数据,不删除cookie)
request.session.delete()
  
# 删除当前的会话数据并删除会话的Cookie。(将session数据以及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失效策略。

2.3 session 的流程

 

2.4 session版登录验证

from functools import wraps


def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.session.get("user"):
            return func(request, *args, **kwargs)
        else:
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        if user == "alex" and pwd == "alex1234":
            # 设置session
            request.session["user"] = user
            # 获取跳到登陆页面之前的URL
            next_url = request.GET.get("next")
            # 如果有,就跳转回登陆之前的URL
            if next_url:
                return redirect(next_url)
            # 否则默认跳转到index页面
            else:
                return redirect("/index/")
    return render(request, "login.html")


@check_login
def logout(request):
    # 删除所有当前请求相关的session
    request.session.delete()
    return redirect("/login/")

@check_login
def index(request):
    current_user = request.session.get("user", None)
    return render(request, "index.html", {"user": current_user})

Session版登录验证

 2.5 Django中的Session配置

1. 数据库Session
SESSION_ENGINE = ''django.contrib.sessions.backends.db''   # 引擎(默认)

2. 缓存Session
SESSION_ENGINE = ''django.contrib.sessions.backends.cache''  # 引擎
SESSION_CACHE_ALIAS = ''default''                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = ''django.contrib.sessions.backends.file''    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

4. 缓存+数据库
SESSION_ENGINE = ''django.contrib.sessions.backends.cached_db''        # 引擎

5. 加密Cookie Session
SESSION_ENGINE = ''django.contrib.sessions.backends.signed_cookies''   # 引擎

其他公用设置项:
SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)
Session配置

 

Django - Cookie、Session、自定义分页和Django分页器

Django - Cookie、Session、自定义分页和Django分页器

2. 今日内容
    https://www.cnblogs.com/liwenzhou/p/8343243.html
    1. Cookie和Session
        1. Cookie

        服务端:
            1. 生成字符串
            2. 随着响应将字符串回复给浏览器
            3. 从浏览器发送的请求中拿到字符串

        cookie就是保存在浏览器上的字符串!!!
        每一次请求都会携带着cookie

        把要保存的信息都保存在用户的浏览器上
        好处:
            服务端不用存,减轻了服务器压力
        坏处:
            信息不安全


    Session:
        搭配Cookie使用

        Session本质上,保存在服务端的键值对。
        好处:
            用户的信息都保存在服务端,安全
        坏处:
            数据都保存在服务端,存储压力比较大

    cookie和Session应用场景:
        登录
        刷票限制
        保存用户的浏览习惯

    Django中使用Session:
         获取、设置、删除Session中数据
        request.session[''k1'']
        request.session.get(''k1'',None)
        request.session[''k1''] = 123
        request.session.setdefault(''k1'',123) # 存在则不设置


        # 删除当前用户的所有Session数据
        request.session.delete()

        request.session.set_expiry(value)
        * 如果value是个整数,session会在些秒数后失效。
        * 如果value是个datatime或timedelta,session就会在这个时间后失效。
        * 如果value是0,用户关闭浏览器session就会失效。
        * 如果value是None,session会依赖全局session失效策略。

    CBV加装饰器注意事项:
        要将函数装饰器转成方法装饰器
        from django.utils.decorators import method_decorator
        @method_decorator(check_login)

    2. 分页
        第几页  数据  索引
        1     1-10   0-10
        2     11-20  10-20
        3     21-30

----------------------------------------------
笔记
day 70 内容回顾

1.内容回顾
    https://www.cnblogs.com/liwenzhou/p/8343243.html
    1.cookie
        本质上就是保存在浏览器上得键值对
        为了解决HTTP请求是无状态得

        可以用来做登录 7天免登录 浏览习惯 (每页显示多少条)
        Django 操作Cookie
            1.设置Cookie 是在response对象
                1.明文的
                    rep = 响应对象(基础必备三件套)
                    rep.set_cookie(key,value,..)
                2.加盐的
                    rep = 响应对象(基础必备三件套)
                    rep.set_signed_cookie(key,value,salt=''加密盐)

            2.获取Cookie 是在request对象
                1.明文的
                    request.COOKIES.get(''key'') / request.COOKIES[''key'']
                2.加盐的
                   request.get_signed_cookie(key, default="默认值", salt='''', max_age=None)

    2.session
        1.定义
            保存在服务器端的键值对,依赖与Cookie

        2.Django的session 操作
            1.设置session
                request.session[''k1'']
                request.session.setdefault(''k1'',123) # 存在则不设置
            2.获取session
                request.session.get(''k1'',None)
                request.session[''k1'']
            3.删除session
                del request.session[''k1'']
                注销之后删除用户所有的session数据
                request.session.delete()
            4.将所有Session失效日期小于当前日期的数据删除
                request.session.clear_expired()

            5.设置会话Session和Cookie的超时时间
                request.session.set_expiry(value)
                    * 如果value是个整数,session会在些秒数后失效。
                    * 如果value是个datatime或timedelta,session就会在这个时间后失效。
                    * 如果value是0,用户关闭浏览器session就会失效。
                    * 如果value是None,session会依赖全局session失效策略。

        3.FBV和CBV
            CBV要加装饰器需要用到method_decorator
            # 导入django 提供得工具 把函数装饰器变成方法装饰器
            from django.utils.decorators import method_decorator


    3.分页
        1.自定义的分页
            重在理解!
            编程思想的建立是一个积累的过程。不要着急!!,知道怎么用
        2.Djangon自带的分页
            注意几个属性
笔记

一、Cookie

Cookie的由来

大家都知道HTTP协议是无状态的。

无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。

状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。

什么是Cookie

Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

Cookie的原理

cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。

查看Cookie

我们使用Chrome浏览器,打开开发者工具。

 

Django中操作Cookie

获取Cookie

request.COOKIES[''key'']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='''', max_age=None)

参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间

设置Cookie

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'',...)

参数:

  • 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获取(不是绝对,底层抓包可以获取到也可以被覆盖)

删除Cookie

def logout(request):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 删除用户浏览器上之前设置的usercookie值
    return rep

 

Cookie版登陆校验

def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
            # 已经登录的用户...
            return func(request, *args, **kwargs)
        else:
            # 没有登录的用户,跳转刚到登录页面
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    if request.method == "POST":
        username = request.POST.get("username")
        passwd = request.POST.get("password")
        if username == "xxx" and passwd == "123":
            next_url = request.GET.get("next")
            if next_url and next_url != "/logout/":
                response = redirect(next_url)
            else:
                response = redirect("/class_list/")
            response.set_signed_cookie("login", "yes", salt="SSS")
            return response
    return render(request, "login.html")

二、Session

Session的由来

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

问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就起到桥接的作用。

我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等。

总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。

另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架。

Django中Session相关方法

# 获取、设置、删除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的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失效策略。

Session流程解析

 

Session版登陆验证

from functools import wraps


def check_login(func):
    @wraps(func)
    def inner(request, *args, **kwargs):
        next_url = request.get_full_path()
        if request.session.get("user"):
            return func(request, *args, **kwargs)
        else:
            return redirect("/login/?next={}".format(next_url))
    return inner


def login(request):
    if request.method == "POST":
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")

        if user == "alex" and pwd == "alex1234":
            # 设置session
            request.session["user"] = user
            # 获取跳到登陆页面之前的URL
            next_url = request.GET.get("next")
            # 如果有,就跳转回登陆之前的URL
            if next_url:
                return redirect(next_url)
            # 否则默认跳转到index页面
            else:
                return redirect("/index/")
    return render(request, "login.html")


@check_login
def logout(request):
    # 删除所有当前请求相关的session
    request.session.delete()
    return redirect("/login/")


@check_login
def index(request):
    current_user = request.session.get("user", None)
    return render(request, "index.html", {"user": current_user})

Django中的Session配置

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用。

1. 数据库Session
SESSION_ENGINE = ''django.contrib.sessions.backends.db''   # 引擎(默认)

2. 缓存Session
SESSION_ENGINE = ''django.contrib.sessions.backends.cache''  # 引擎
SESSION_CACHE_ALIAS = ''default''                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

3. 文件Session
SESSION_ENGINE = ''django.contrib.sessions.backends.file''    # 引擎
SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() 

4. 缓存+数据库
SESSION_ENGINE = ''django.contrib.sessions.backends.cached_db''        # 引擎

5. 加密Cookie Session
SESSION_ENGINE = ''django.contrib.sessions.backends.signed_cookies''   # 引擎

其他公用设置项:
SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

三、CBV加装饰器

 CBV实现的登录视图

path(''book_list/'', views.BookList.as_view(),name=''book_list''),

from django.views import View

from django.utils.decorators import method_decorator
class LoginView(View):

    def get(self, request):
        """
        处理GET请求
        """
        return render(request, ''login.html'')

    def post(self, request):
        """
        处理POST请求 
        """
        user = request.POST.get(''user'')
        pwd = request.POST.get(''pwd'')
        if user == ''alex'' and pwd == "alex1234":
            next_url = request.GET.get("next")
            # 生成随机字符串
            # 写浏览器cookie -> session_id: 随机字符串
            # 写到服务端session:
            # {
            #     "随机字符串": {''user'':''alex''}
            # }
            request.session[''user''] = user
            if next_url:
                return redirect(next_url)
            else:
                return redirect(''/index/'')
        return render(request, ''login.html'')

要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:

from django.utils.decorators import method_decorator

1. 加在CBV视图的get或post方法上

from django.utils.decorators import method_decorator


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")
    
    @method_decorator(check_login)
    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

2. 加在dispatch方法上

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/")

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

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

如果get方法和post方法都需要登录校验的话就写两个装饰器。

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相关装饰器在CBV只能加到dispatch方法上

备注:

  • csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
from django.views.decorators.csrf import csrf_exempt, csrf_protect


class HomeView(View):

    @method_decorator(csrf_exempt)
    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/")

四、分页

1.自定义分页

data = []

for i in range(1, 302):
    tmp = {"id": i, "name": "alex-{}".format(i)}
    data.append(tmp)

print(data)


def user_list(request):

    # user_list = data[0:10]
    # user_list = data[10:20]
    try:
        current_page = int(request.GET.get("page"))
    except Exception as e:
        current_page = 1

    per_page = 10

    # 数据总条数
    total_count = len(data)
    # 总页码
    total_page, more = divmod(total_count, per_page)
    if more:
        total_page += 1

    # 页面最多显示多少个页码
    max_show = 11
    half_show = int((max_show-1)/2)

    if current_page <= half_show:
        show_start = 1
        show_end = max_show
    else:
        if current_page + half_show >= total_page:
            show_start = total_page - max_show
            show_end = total_page
        else:
            show_start = current_page - half_show
            show_end = current_page + half_show

    # 数据库中获取数据
    data_start = (current_page - 1) * per_page
    data_end = current_page * per_page

    user_list = data[data_start:data_end]

    # 生成页面上显示的页码
    page_html_list = []
    # 加首页
    first_li = ''<li><a href="/user_list/?page=1">首页</a></li>''
    page_html_list.append(first_li)
    # 加上一页
    if current_page == 1:
        prev_li = ''<li><a href="#">上一页</a></li>''
    else:
        prev_li = ''<li><a href="/user_list/?page={}">上一页</a></li>''.format(current_page - 1)
    page_html_list.append(prev_li)
    for i in range(show_start, show_end+1):
        if i == current_page:
            li_tag = ''<li><a href="/user_list/?page={0}">{0}</a></li>''.format(i)
        else:
            li_tag = ''<li><a href="/user_list/?page={0}">{0}</a></li>''.format(i)
        page_html_list.append(li_tag)

    # 加下一页
    if current_page == total_page:
        next_li = ''<li><a href="#">下一页</a></li>''
    else:
        next_li = ''<li><a href="/user_list/?page={}">下一页</a></li>''.format(current_page+1)
    page_html_list.append(next_li)

    # 加尾页
    page_end_li = ''<li><a href="/user_list/?page={}">尾页</a></li>''.format(total_page)
    page_html_list.append(page_end_li)

    page_html = "".join(page_html_list)

    return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})
class Pagination(object):
    def __init__(self, current_page, total_count, base_url, per_page=10, max_show=11):
        """
        :param current_page: 当前页
        :param total_count: 数据库中数据总数
        :param per_page: 每页显示多少条数据
        :param max_show: 最多显示多少页
        """
        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        self.current_page = current_page
        self.total_count = total_count
        self.base_url = base_url
        self.per_page = per_page
        self.max_show = max_show

        # 总页码
        total_page, more = divmod(total_count, per_page)
        if more:
            total_page += 1
        
        half_show = int((max_show - 1) / 2)
        self.half_show = half_show
        self.total_page = total_page

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page

    @property
    def end(self):
        return self.current_page * self.per_page

    def page_html(self):

        if self.current_page <= self.half_show:
            show_start = 1
            show_end = self.max_show
        else:
            if self.current_page + self.half_show >= self.total_page:
                show_start = self.total_page - self.max_show
                show_end = self.total_page
            else:
                show_start = self.current_page - self.half_show
                show_end = self.current_page + self.half_show

                # 生成页面上显示的页码
        page_html_list = []
        # 加首页
        first_li = ''<li><a href="{}?page=1">首页</a></li>''.format(self.base_url)
        page_html_list.append(first_li)
        # 加上一页
        if self.current_page == 1:
            prev_li = ''<li><a href="#">上一页</a></li>''
        else:
            prev_li = ''<li><a href="{0}?page={1}">上一页</a></li>''.format(self.base_url, self.current_page - 1)
        page_html_list.append(prev_li)
        for i in range(show_start, show_end + 1):
            if i == self.current_page:
                li_tag = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.base_url, i)
            else:
                li_tag = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.base_url, i)
            page_html_list.append(li_tag)

        # 加下一页
        if self.current_page == self.total_page:
            next_li = ''<li><a href="#">下一页</a></li>''
        else:
            next_li = ''<li><a href="{0}?page={1}">下一页</a></li>''.format(self.base_url, self.current_page + 1)
        page_html_list.append(next_li)

        # 加尾页
        page_end_li = ''<li><a href="{0}?page={1}">尾页</a></li>''.format(self.base_url, self.total_page)
        page_html_list.append(page_end_li)

        return "".join(page_html_list)
def user_list(request):
    pager = Pagination(request.GET.get("page"), len(data), request.path_info)
    user_list = data[pager.start:pager.end]
    page_html = pager.page_html()
    return render(request, "user_list.html", {"user_list": user_list, "page_html": page_html})

2.Django内置分页

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

L = []
for i in range(999):
    L.append(i)

def index(request):
    current_page = request.GET.get(''p'')

    paginator = Paginator(L, 10)
    # per_page: 每页显示条目数量
    # count:    数据总个数
    # num_pages:总页数
    # page_range:总页数的索引范围,如: (1,10),(1,200)
    # page:     page对象
    try:
        posts = paginator.page(current_page)
        # has_next              是否有下一页
        # next_page_number      下一页页码
        # has_previous          是否有上一页
        # previous_page_number  上一页页码
        # object_list           分页之后的数据列表
        # number                当前页
        # paginator             paginator对象
    except PageNotAnInteger:
        posts = paginator.page(1)
    except EmptyPage:
        posts = paginator.page(paginator.num_pages)
    return render(request, ''index.html'', {''posts'': posts})
<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<ul>
    {% for item in posts %}
        <li>{{ item }}</li>
    {% endfor %}
</ul>

<div class="pagination">
      <span class="step-links">
        {% if posts.has_previous %}
            <a href="?p={{ posts.previous_page_number }}">Previous</a>
        {% endif %}
          <span class="current">
            Page {{ posts.number }} of {{ posts.paginator.num_pages }}.
          </span>
          {% if posts.has_next %}
              <a href="?p={{ posts.next_page_number }}">Next</a>
          {% endif %}
      </span>

</div>
</body>
</html>

五、示例

       

 

BMS settings.py

"""
Django settings for BMS project.

Generated by ''django-admin startproject'' using Django 2.0.1.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = ''nk!!3wd)(-d!@0(^3+xr_2+1xucs01mj5m$lw%t0z@^c*@_#an''

# SECURITY WARNING: don''t run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
    ''django.contrib.admin'',
    ''django.contrib.auth'',
    ''django.contrib.contenttypes'',
    ''django.contrib.sessions'',
    ''django.contrib.messages'',
    ''django.contrib.staticfiles'',
    ''app01.apps.App01Config'',
]

MIDDLEWARE = [
    ''django.middleware.security.SecurityMiddleware'',
    ''django.contrib.sessions.middleware.SessionMiddleware'',
    ''django.middleware.common.CommonMiddleware'',
    ''django.middleware.csrf.CsrfViewMiddleware'',
    ''django.contrib.auth.middleware.AuthenticationMiddleware'',
    ''django.contrib.messages.middleware.MessageMiddleware'',
    ''django.middleware.clickjacking.XFrameOptionsMiddleware'',
]

ROOT_URLCONF = ''BMS.urls''

TEMPLATES = [
    {
        ''BACKEND'': ''django.template.backends.django.DjangoTemplates'',
        ''DIRS'': [os.path.join(BASE_DIR, ''templates'')]
        ,
        ''APP_DIRS'': True,
        ''OPTIONS'': {
            ''context_processors'': [
                ''django.template.context_processors.debug'',
                ''django.template.context_processors.request'',
                ''django.contrib.auth.context_processors.auth'',
                ''django.contrib.messages.context_processors.messages'',
            ],
        },
    },
]

WSGI_APPLICATION = ''BMS.wsgi.application''


# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

# DATABASES = {
#     ''default'': {
#         ''ENGINE'': ''django.db.backends.sqlite3'',
#         ''NAME'': os.path.join(BASE_DIR, ''db.sqlite3''),
#     }
# }
DATABASES = {
    ''default'': {
        ''ENGINE'': ''django.db.backends.mysql'',
        ''NAME'': ''bms69'',
        ''HOST'':''127.0.0.1'',
        ''PORT'':3306,
        ''USER'':''root'',
        ''PASSWORD'':''123'',
    }
}



# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {
        ''NAME'': ''django.contrib.auth.password_validation.UserAttributeSimilarityValidator'',
    },
    {
        ''NAME'': ''django.contrib.auth.password_validation.MinimumLengthValidator'',
    },
    {
        ''NAME'': ''django.contrib.auth.password_validation.CommonPasswordValidator'',
    },
    {
        ''NAME'': ''django.contrib.auth.password_validation.NumericPasswordValidator'',
    },
]


# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = ''en-us''

TIME_ZONE = ''UTC''

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = ''/static/''
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,''static'')
]

LOGGING = {
    ''version'': 1,
    ''disable_existing_loggers'': False,
    ''handlers'': {
        ''console'':{
            ''level'':''DEBUG'',
            ''class'':''logging.StreamHandler'',
        },
    },
    ''loggers'': {
        ''django.db.backends'': {
            ''handlers'': [''console''],
            ''propagate'': True,
            ''level'':''DEBUG'',
        },
    }
}
settings

BMS urls.py

"""BMS URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/2.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('''', views.home, name=''home'')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('''', Home.as_view(), name=''home'')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path(''blog/'', include(''blog.urls''))
"""
from django.contrib import admin
from django.urls import path,re_path

from app01 import views

urlpatterns = [
    re_path(r"^login/",views.login,name=''login''),
    re_path(r"^logout/",views.logout,name=''logout''),
    re_path(r''^publisher_list/'',views.publisher_list,name=''publisher_list''),
    re_path(r''^delete_publisher/'',views.delete_publisher,name=''delete_publisher''),
    re_path(r''^home/'',views.home,name="home"),
    # re_path(r''^book_list/'',views.book_list,name="book_list"),
    re_path(r''^book_list/'',views.BookList.as_view(),name="book_list"),
    # 类视图 要调用as_view()

    # 以ip和端口后面什么都没有,就能匹配上url
    re_path(r''^$'',views.publisher_list),
]
urls

BMS __init__.py

import pymysql
pymysql.install_as_MySQLdb()
init

app01 models.py

from django.db import models


# 出版社类
class Publisher(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name


# 书类
class Book(models.Model):
    id = models.AutoField(primary_key=True)
    title = models.CharField(max_length=32)
    # 书的价格
    price = models.DecimalField(max_digits=8, decimal_places=2)  # 999999.99
    # 出版日期
    publish_date = models.DateTimeField(auto_now=True)  # datetime.date()
    # 书只能关联一个出版社, 外键通常建在多的那一边
    publisher = models.ForeignKey(to="Publisher", on_delete=models.CASCADE)

    def __str__(self):
        return self.title


# 作者类
class Author(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    # 多对多, 建在哪边都可以
    books = models.ManyToManyField(to="Book", related_name="authors")  # 多对多关联

    detail = models.OneToOneField(to="AuthorDetail", null=True,on_delete=models.CASCADE)  # 作者详情数据的id在这张表是唯一的

    def __str__(self):
        return self.name


# 作者详情
class AuthorDetail(models.Model):
    age = models.IntegerField()
    addr = models.TextField()


# python manage.py makemigrations
# python manage.py migrate
#
# 在项目的bms __init__ 下设置
# import pymysql
# pymysql.install_as_MySQLdb()
models

app01 views.py

from django.shortcuts import render,redirect,HttpResponse
from django.urls import reverse

from app01.models import *

# 判断用户有没有登录得装饰器 ,
def check_login(func):
    def inner(request,*args,**kwargs):
        # 把当前访问得网址拿到
        url = request.get_full_path()

        # login_user = request.COOKIES.get(''login'', None)
        # login_user = request.get_signed_cookie(''login'',default=None,salt=''hehe'')

        login_status = request.session.get(''login'')
        login_user = request.session.get(''user'')
        if login_status == ''1'':  # 登录成功
            print(''验证通过''.center(120,''*''))
            return func(request,*args,**kwargs)  # 执行被装饰得函数
        else:
            print(''验证失败''.center(120, ''*''))
            return redirect(''/login/?next={}''.format(url))
    return inner


# 登录
# def login(request):
#     # /login/?next=/book_list/
#     # /login/?next=/publisher_list/
#     if request.method == ''POST'':
#         next_url = request.GET.get(''next'')
#
#         username = request.POST.get(''user'')
#         password = request.POST.get(''pwd'')
#
#         if username == ''alex'' and password == ''123'':
#             # 登录成功,跳转到首页
#             # 给用户生成一个字符串,让它保存在里游览器上(这个字符串就是Cookie)
#             rep = redirect(next_url)
#             # 生成字符串 并且随着响应返回给浏览器
#
#             # rep.set_cookie("login",''alex'')
#             rep.set_signed_cookie("login",''alex'',salt=''hehe'',max_age = 7)
#             # 7s 之后失效 加密过得cookie
#
#             print(''===='',rep)
#             # <HttpResponseRedirect status_code=302, "text/html; charset=utf-8", url="/home/">
#             return rep
#
#     return render(request,''login.html'')


# session版登录
def login(request):
    if request.method == ''POST'':
        next_url = request.GET.get(''next'')

        username = request.POST.get(''user'')
        password = request.POST.get(''pwd'')

        if username == ''alex'' and password == ''123'':
            # 利用session 保存一个login=alex
            request.session[''user''] = ''alex''
            request.session[''login''] = ''1''
            request.session.set_expiry(86400)
            # 7s 之后失效 设置浏览器失效时间
            rep = redirect(next_url)
            return rep

    return render(request,''login.html'')

def logout(request):
    # 把当前用户得session 都清掉
    request.session.delete()
    return redirect(''/login'')


# 首页
def home(request):
    return render(request,''home.html'')


# 出版社列表
@check_login
def publisher_list(request):

    # # 判断用户有没有 登录
    # # 实际上就是判断请求得cookie中有没有login 1
    # print(request.COOKIES)
    # # {''csrftoken'': ''NtrDhwNbXcnTSqmxa7wITT1UqccZYu2Z8ywHdf2rYhyURwdtaOAf702tsLkVfqD7'', ''login'': ''1''}
    #
    #
    # if login_user == ''alex'': # 登录成功
    #     publisher_list = Publisher.objects.all()
    #     return render(request,''publisher_list.html'',{''publisher_list'':publisher_list,''user'':login_user})
    # else:
    #     return redirect(reverse(''login''))

    # 查询出所有数据

    # data = Publisher.objects.all()
    # # 这里斌不会查询数据库,在对data 操作时,才会查询数据库 data[3:10]
    # # 总共需要多少页
    # # 每页显示10条
    # per_page = 10
    # data_num = data.count()  # 数据得总数
    # # page_num,more = divmod(data_num,per_page)
    # # if more:
    # #     page_num += 1
    # current_page = request.GET.get(''page'',1)
    #
    # # try:
    # #     current_page = int(current_page)
    # # except Exception as e:
    # #     current_page = 1
    # # if current_page <= 0:    # 如果页面数是  负数
    # #     current_page = 1
    # # elif current_page > page_num:   # 如果页面 大于 总页面
    # #     current_page = page_num
    #
    # # 页面最多显示11个页面 , 当前页数 左 + 5   右 + 5
    # max_show = 7
    # # half_show = max_show//2
    # # # 页面最左边显示多少
    # # if current_page - half_show <= 1:
    # #     page_start = 1
    # #     page_end = max_show
    # # elif current_page + half_show >= page_num:  # 如果右边 越界了
    # #     page_start = page_num - max_show + 1
    # #     page_end = page_num
    # # else:
    # #     page_start = current_page - half_show
    # #     page_end = current_page + half_show

    # from utils import mypage
    # obj = mypage.Pagination(data_num,current_page)

    # 当前页是第3页  (3-1)*10  - 3*10
    # date_start = (current_page-1) * per_page   # 数据从哪开始切
    # data_end = current_page * per_page         # 数据切到哪

    # publisher_list = Publisher.objects.all()
    # publisher_list = Publisher.objects.all()[20:30]
    # publisher_list = data[obj.start:obj.end]

    # # 生成页码
    # li = []
    # # 加一个首页
    # li.append(''<li><a href="/publisher_list/?page=1">首页</a></li>'')
    # # 加一个上一页
    # if current_page == 1:
    #     li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&laquo;</span></a></li>''.format(
    #         current_page))
    # else:
    #     li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&laquo;</span></a></li>''.format(
    #         current_page - 1))
    # for i in range(page_start,page_end+1):
    #     if i == current_page:
    #         tmp = ''<li><a href="/publisher_list/?page={0}">{0}</a></li>''.format(i)
    #     else:
    #         tmp = ''<li><a href="/publisher_list/?page={0}">{0}</a></li>''.format(i)
    #     li.append(tmp)
    # # 加一个下一页
    # if current_page == page_num:
    #     li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&raquo;</span></a></li>''.format(
    #         current_page))
    # else:
    #     li.append(''<li><a href="/publisher_list/?page={0}"><span aria-hidden="true">&raquo;</span></a></li>''.format(
    #         current_page + 1))
    # li.append(''<li><a href="/publisher_list/?page={0}">尾页</a></li>''.format(page_num))
    # page_html = "".join(li)

    data = Publisher.objects.all()
    data_num = data.count()  # 数据得总数
    current_page = request.GET.get(''page'', 1)
    from utils import mypage
    obj = mypage.Pagination(data_num,current_page,request.path)
    publisher_list = data[obj.start:obj.end]
    page_html = obj.page_html()
    return render(  
        request,
        ''publisher_list.html'',
        {''publisher_list'': publisher_list,''page_html'':page_html}
    )

# # 书籍列表页
# @check_login
# def book_list(request):
#     return render(request,''book_list.html'')


# FBV(function base views) 就是在视图里使用函数处理请求。

# CBV版书籍列表
# CBV(class base views)就是在视图里使用类处理请求。

from django.views import View
# 导入django 提供得工具 把函数装饰器变成方法装饰器
from django.utils.decorators import method_decorator

''''''三个地方可加装饰器''''''

#
# # @method_decorator(check_login,name=''get'')
# class BookList(View):
#     # @method_decorator(check_login)
#     # def dispatch(self, request, *args, **kwargs):
#     #     super(BookList, self).dispatch(request,*args,**kwargs)
#
#     @method_decorator(check_login)
#     def get(self,request):
#         current_page = request.GET.get(''page'',1)
#         data = Book.objects.all()
#         from utils import mypage
#         obj = mypage.Pagination(data.count(),current_page,request.path)
#
#         book_list = data[obj.start:obj.end]
#         page_html = obj.page_html()
#         return render(request,''book_list.html'',{''book_list'':book_list,''page_html'':page_html})
#

# 使用django 内置得分页

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

class BookList(View):

    @method_decorator(check_login)
    def get(self,request):
        current_page = request.GET.get(''page'',1)
        data = Book.objects.all()

        # 用内置得分页类 得到一个分页对象
        page_obj = Paginator(data,10)
        try:
            # 尝试去取 current_page
            ret = page_obj.page(current_page)
        except PageNotAnInteger:
            ret = page_obj.page(1)  # 返回第一页
        except EmptyPage:
            ret = page_obj.page(page_obj.num_pages)  # 返回最后一页

        return render(request,''book_list2.html'',{''book_list'':ret,})



def  delete_publisher(request):
    delete_id = request.POST.get(''publisher_id'')
    try:
        Publisher.objects.filter(id = delete_id).delete()
        ret = {''status'':0}
    except Exception as e:
        ret = {''status'':1,"msg":''删除失败''}

    import json
    json_ret = json.dumps(ret)
    return HttpResponse(json_ret)
views

app01 tests.py

from django.test import TestCase

from functools import wraps

#
# def my_decorator(func):
#     def wrapper(*args, **kwargs):
#         ''''''''''decorator''''''
#         print(''Calling decorated function...'')
#         return func(*args, **kwargs)
#
#     return wrapper
#
# @my_decorator
# def example():
#     """Docstring"""
#     print(''Called example function'')
#
#
# print(example.__name__, example.__doc__)
# # wrapper ''''decorator

# coding=utf-8
# -*- coding=utf-8 -*-
# from functools import wraps
#
#
# def my_decorator(func):
#     @wraps(func)
#     def wrapper(*args, **kwargs):
#         ''''''''''decorator''''''
#         print(''Calling decorated function...'')
#         return func(*args, **kwargs)
#
#     return wrapper
#
#
# @my_decorator
# def example():
#     """Docstring"""
#     print(''Called example function'')
#
#
# print(example.__name__, example.__doc__)
# example Docstring
tests

templates book_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>book_list</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>这是书籍列表页</h1>
<a href="/logout">注销</a>

<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>ID</th>
            <th>书籍名称</th>
        </tr>
        </thead>
        <tbody>
        {% for book in book_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.id }}</td>
                <td>{{ book.title }}</td>
            </tr>
        {% endfor %}

        </tbody>
    </table>
    <nav aria-label="...">
        <ul class="pagination">
            {{ page_html|safe }}
         </ul>
    </nav>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
book_list

templates book_list2.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>book_list</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
</head>
<body>
<h1>这是书籍列表页</h1>
<a href="/logout">注销</a>

<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>ID</th>
            <th>书籍名称</th>
        </tr>
        </thead>
        <tbody>
        {% for book in book_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ book.id }}</td>
                <td>{{ book.title }}</td>
            </tr>
        {% endfor %}

        </tbody>
    </table>
    <nav aria-label="...">
        <ul class="pagination">
            {% if book_list.has_previous %}
                <li><a href="/book_list?page={{ book_list.previous_page_number }}">«</a></li>
            {% else %}
                 <li class="disabled"><a href="#">«</a></li>
            {% endif %}
            <li class="active"><a href="/book_list?page={{ book_list.number }}">{{ book_list.number }}</a></li>
            {% if book_list.has_next %}
                <li><a href="/book_list?page={{ book_list.next_page_number}}">»</a></li>
            {% else %}
                 <li class="disabled"><a href="#">»</a></li>
            {% endif %}
         </ul>
    </nav>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
</body>
</html>
book_list2

templates home.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home</title>
</head>
<body>
<h1>这是home页面!!!</h1>
</body>
</html>
home

templates login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>login</title>
</head>
<body>
{# action 为空 表示往当前url 提交  #}
{#<form action="" method="post">#}
<form action="{{ request.get_full_path }}" method="post">
    {% csrf_token %}
    <input type="text" name="user">
    <input type="password" name="pwd">
    <input type="submit" value="登录">
</form>
</body>
</html>
login

templates publisher_list.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>publisher_list</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/plugins/sweetalert/sweetalert.css">
    <style type="text/css">
        .sweet-alert h2{padding-top: 20px;}
    </style>
</head>
<body>
<a href="/logout">注销</a>
<div class="container">
    <table class="table table-bordered">
        <thead>
        <tr>
            <th>#</th>
            <th>ID</th>
            <th>出版社名称</th>
            <th>操作</th>
        </tr>
        </thead>
        <tbody>
        {% for publisher in publisher_list %}
            <tr>
                <td>{{ forloop.counter }}</td>
                <td>{{ publisher.id }}</td>
                <td>{{ publisher.name }}</td>
                <td>
                    {#  https://github.com/lipis/bootstrap-sweetalert        #}
                    <button class="btn btn-danger delete">删除</button>
                </td>
            </tr>
        {% endfor %}

        </tbody>
    </table>
    <nav aria-label="...">
        <ul class="pagination">
            {{ page_html|safe }}
         </ul>
    </nav>
</div>



<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/init_ajax.js"></script>
<script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
<script src="/static/plugins/sweetalert/sweetalert.min.js"></script>

<script type="text/javascript">
    //给删除按钮绑定事件
    $(''.delete'').click(function () {
        var id = $(this).parent().prev().prev().text();
        var $currentTr = $(this).parent().parent();
            swal({
              title: "确定要删除吗? ",
              text: "删了就找不回来了",
              type: "warning",
              showCancelButton: true,  // 显不显示取消按钮
              confirmButtonClass: "btn-danger",
              confirmButtonText: "是,就是删除",  //取消按钮上的文字
              closeOnConfirm: false
            },
            function(){
                $.ajax({
                        url:''/delete_publisher/'',
                        type:''post'',
                        data:{''publisher_id'':id},
                        success:function (arg) {
                            var ret = JSON.parse(arg);
                            if(ret.status === 0){
                                $currentTr.remove();
                                swal("删除成功!", "你可以跑路了", "success");
                            }else{
                                swal(ret.msg, "你可以尝试在删一次", "error");
                            }
                        }
                });
            });
    });

</script>

</body>
</html>

{# 下载 dist css js 引入 #}
{# https://github.com/lipis/bootstrap-sweetalert  #}
{#   https://lipis.github.io/bootstrap-sweetalert/  #}
publisher_list

utils mypage.py

''''''
自定义分页组件

''''''
class Pagination(object):

    def __init__(self, data_num, current_page,url_prefix, per_page = 10, max_show = 11):
        """
        进行初始化
        :param data_num:  数据总数
        :param current_page: 当前页
        :param url_prefix: 生成得页码得链接前缀
        :param per_page: 每页显示多少条数据
        :param max_show: 页面最多显示多少个页码
        """
        self.data_num = data_num
        self.per_page = per_page
        self.max_show = max_show
        self.url_prefix = url_prefix

        # 把页码数算出来
        self.page_num, more = divmod(self.data_num, self.per_page)
        if more:
            self.page_num += 1

        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1
        if current_page <= 0:  # 如果页面数是  负数
            current_page = 1
        elif current_page > self.page_num:  # 如果页面 大于 总页面
            current_page = self.page_num
        self.current_page = current_page

        # 页码数得一半
        self.half_show = self.max_show // 2

        if self.current_page - self.half_show <= 1:
            self.page_start = 1
            self.page_end = self.max_show
        elif self.current_page + self.half_show >= self.page_num:  # 如果右边 越界了
            self.page_start = self.page_num - self.max_show + 1
            self.page_end = self.page_num
        else:
            self.page_start = self.current_page - self.half_show
            self.page_end = self.current_page + self.half_show

    @property
    def start(self):
        return (self.current_page-1) * self.per_page   # 数据从哪开始切

    @property
    def end(self):
        return self.current_page * self.per_page  # 数据切到哪

    def page_html(self):
        # 生成页码
        li = []
        # 加一个首页
        li.append(''<li><a href="{}?page=1">首页</a></li>''.format(self.url_prefix))
        # 加一个上一页
        if self.current_page == 1:
            li.append(
                ''<li><a href="#"><span aria-hidden="true">&laquo;</span></a></li>'')
        else:
            li.append(''<li><a href="{0}?page={1}"><span aria-hidden="true">&laquo;</span></a></li>''.format(
                self.url_prefix,self.current_page - 1))
        for i in range(self.page_start, self.page_end + 1):
            if i == self.current_page:
                tmp = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.url_prefix,i)
            else:
                tmp = ''<li><a href="{0}?page={1}">{1}</a></li>''.format(self.url_prefix,i)
            li.append(tmp)
        # 加一个下一页
        if self.current_page == self.page_num:
            li.append(
                ''<li><a href="#"><span aria-hidden="true">&raquo;</span></a></li>'')
        else:
            li.append(''<li><a href="{0}?page={1}"><span aria-hidden="true">&raquo;</span></a></li>''.format(self.url_prefix,
                self.current_page + 1))
        li.append(''<li><a href="{0}?page={1}">尾页</a></li>''.format(self.url_prefix,self.page_num))

        return "".join(li)
mypage

myscript.py

# -*- coding:utf-8 -*-
import os

if __name__ == ''__main__'':
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings")
    import django
    django.setup()

    # 创建300个出版社
    from app01 import models

    # Publisher.objects.create(name=''水星第{}出版社''.format(i))

    # obj = Publisher(name=''火星出版社'')
    # obj.save()

    # ret = []
    # for i in range(300):
    #     obj = Publisher(name=''水星第{}出版社''.format(i))
    #     ret.append(obj)

    # ret = [models.Publisher(name=''水星第{}出版社''.format(i)) for i in range(300)]

    # 批量创建300个出版社对象
    # models.Publisher.objects.bulk_create(ret)  # 只提交一次


    # 创建300本书
    import random
    ret = [models.Book(title=''番茄物语{}''.format(i),price=random.randint(10, 90),publisher_id=1) for i in range(300)]
    models.Book.objects.bulk_create(ret)
myscript

 

https://github.com/alice-bj/BMS

 

六、线上 - Django分页器

view

from django.shortcuts import render,HttpResponse

# Create your views here.
from app01.models import *
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def index(request):

    ''''''
    批量导入数据:

    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    ''''''

    ''''''
分页器的使用:

    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #数据总数
    print("num_pages",paginator.num_pages)    #总页数
    print("page_range",paginator.page_range)  #页码的列表



    page1=paginator.page(1) #第1页的page对象
    for i in page1:         #遍历第1页的所有数据对象
        print(i)

    print(page1.object_list) #第1页的所有数据


    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一页
    print(page2.next_page_number())    #下一页的页码
    print(page2.has_previous())        #是否有上一页
    print(page2.previous_page_number()) #上一页的页码



    # 抛错
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger

    ''''''


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)
    page = request.GET.get(''page'',1)
    currentPage=int(page)


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 
    integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h4>分页器</h4>
    <ul>

        {% for book in book_list %}
             <li>{{ book.title }} -----{{ book.price }}</li>
        {% endfor %}

     </ul>


    <ul class="pagination" id="pager">

                 {% if book_list.has_previous %}
                    <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
                 {% else %}
                    <li class="previous disabled"><a href="#">上一页</a></li>
                 {% endif %}


                 {% for num in paginator.page_range %}

                     {% if num == currentPage %}
                       <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
                     {% else %}
                       <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>

                     {% endif %}
                 {% endfor %}



                 {% if book_list.has_next %}
                    <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
                 {% else %}
                    <li class="next disabled"><a href="#">下一页</a></li>
                 {% endif %}

            </ul>
</div>



</body>
</html>
index
def index(request):


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 15)
    page = request.GET.get(''page'',1)
    currentPage=int(page)

    #  如果页数十分多时,换另外一种显示方式
    if paginator.num_pages>11:

        if currentPage-5<1:
            pageRange=range(1,11)
        elif currentPage+5>paginator.num_pages:
            pageRange=range(currentPage-5,paginator.num_pages+1)

        else:
            pageRange=range(currentPage-5,currentPage+5)

    else:
        pageRange=paginator.page_range


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",locals())
index

 

示例:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>index</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">

</head>
<body>
<ul>
    {% for book in current_page %}
        <li>{{ book.title }} - {{ book.price }}</li>
    {% endfor %}

</ul>

<nav aria-label="Page navigation">
    <ul class="pagination">
        <li><a href="?page=1">首页</a></li>
        {% if current_page.has_previous %}
            <li>
                <a href="?page={{ current_page.previous_page_number }}" aria-label="Previous">
                    <span aria-hidden="true">上一页</span>
                </a>
            </li>
        {% else %}
            <li class="disabled">
                <a href="" aria-label="Previous">
                    <span aria-hidden="true">上一页</span>
                </a>
            </li>
        {% endif %}

        {% for item in page_range %}
            {% if current_page_num == item %}
                <li class="active"><a href="?page={{ item }}">{{ item }}</a></li>
            {% else %}
                <li><a href="?page={{ item }}">{{ item }}</a></li>
            {% endif %}
        {% endfor %}

        {% if current_page.has_next %}
            <li>
                <a href="?page={{ current_page.next_page_number }}" aria-label="Next">
                    <span aria-hidden="true">下一页</span>
                </a>
            </li>
        {% else %}
            <li class="disabled">
                <a href="" aria-label="Next">
                    <span aria-hidden="true">下一页</span>
                </a>
            </li>
        {% endif %}
        <li><a href="?page={{ paginator.num_pages }}">尾页</a></li>

    </ul>
</nav>

</body>
</html>

views.py

from django.shortcuts import render,HttpResponse

# Create your views here.

from django.core.paginator import Paginator,EmptyPage,PageNotAnInteger
from app01.models import Book

def index(request):
    ''''''
    批量导入
    book_list = []
    for i in range(100):
        book = Book(title=''book_%s''%i,price=i*i)  # 单条插入
        book_list.append(book)
    Book.objects.bulk_create(book_list)
    ''''''
    book_list = Book.objects.all()

    paginator = Paginator(book_list,6)  # 20显示20个数据
    print(paginator.count)      # 数据总数  100
    print(paginator.num_pages)  # 总页数   13
    print(paginator.page_range) # 页码的列表 range(1,14)

    current_page_num = int(request.GET.get(''page'', 1))

    show_page = 7
    half_show_page = int(show_page/2)
    if paginator.num_pages > show_page:  # 11 表示显示11个页码
        if current_page_num - half_show_page < 1:
            page_range = range(1,show_page+1)
        elif current_page_num + half_show_page > paginator.num_pages:
            page_range = range(paginator.num_pages-show_page+1,paginator.num_pages+1)
        else:
            page_range = range(current_page_num-half_show_page,current_page_num+half_show_page+1)
    else:
        page_range = paginator.page_range


    try:
        # 显示某一页具体数据
        current_page = paginator.page(current_page_num)
        print(current_page.object_list)

        for i in current_page:
            print(i)
    except EmptyPage as e:
        current_page = paginator.page(paginator.num_pages)
    except PageNotAnInteger as e:
        current_page = paginator.page(1)


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

''''''
http://www.cnblogs.com/yuanchenqi/articles/9036515.html
批量插入
   
    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    
分页器:
    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #数据总数
    print("num_pages",paginator.num_pages)    #总页数
    print("page_range",paginator.page_range)  #页码的列表        

    page1=paginator.page(1) #第1页的page对象
    for i in page1:         #遍历第1页的所有数据对象
        print(i)

    print(page1.object_list) #第1页的所有数据

    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一页
    print(page2.next_page_number())    #下一页的页码
    print(page2.has_previous())        #是否有上一页
    print(page2.previous_page_number()) #上一页的页码
    
    
    # 抛错
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger
    
''''''

models.py

from django.db import models

# Create your models here.

class Book(models.Model):
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8,decimal_places=2)

urls.py

from django.contrib import admin
from django.urls import path

from app01 import views

urlpatterns = [
    path(''admin/'', admin.site.urls),
    path(''index/'', views.index),
]

七、线上 - cookie session

线上 Cookie session
http://www.cnblogs.com/yuanchenqi/articles/9036467.html

Cookie : 一个浏览器 针对 一个服务器 存储得 key value 值!
在浏览器端得磁盘上存储
默认时间是2周,可设置失效时间! 就算关机开机,cookie任然存在!!


设置Cookie 用响应体 利用cookie 维持会话得记录保存状态!
response = HttpResponse(''登录成功'')

HttpResponse() render() redirect() 三个response 都可设置cookie

# 1. 设置失效时间
response.set_cookie(''is_login'', True, max_age = 15) # 时间 15s 后

import datetime # 固定在哪个时刻 过期
date = datetime.datetime(year=2018,month=5,day=29,hour=14,minute=32,seconds=10)
response.set_cookie(''username'',username,expires=date)

# 2. 有效路径
response.set_cookie(''username'',username,path=''/index/'')

# 3. 清cookie 浏览器
ctrl + shift + delete

# 4. 设置上次访问时间
import datetime
now = datetime.datetime.now().strftime(''%Y-%m-%d %H:%M:%S'')
设置为北京时间
TIME_ZONE = ''UTC''
TIME_ZONE = ''Asia/Shanghai''

last_time = request.COOKIE.get(''last_visit_time'','''')
response.set_cookie(''last_visit_time'',now)
return render(request,''index.html'',{''username'':username,''last_time'':last_time})

# 5.利用cookie设置 上次访问得商品
。。。
return response


is_login = request.COOKIE.get(''is_login'')
if is_login:
username = request.COOKIE.get(''username'')
return render(request,''index.html'',{''username'':username})
else:
return redirect(''/login/'')

-------------------------------------
session:

写:
request.session[''is_login''] = True
request.session[''username''] = "yuan"
import datetime
now = datetime.datetime.now().strftime(''%Y-%m-%d %H:%M:%S'')
request.session[''last_visit_time''] = now

if request.COOKIE.get(''sessionid''):
在django-session表中更新一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''alice''}
else:
1. 生成随机字符串
2. response.set_cookie(''sessionid'',2312312sadasdasdas2312)
3. 在django-session表中创建一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}


读:
request.session.get(''is_login'')
username = request.session.get(''username'')
last_visit_time = request.session.get(''last_visit_time'')

1. request.COOKIE.get(''sessionid'') # 2312312sadasdasdas2312
2. django-session表中得记录过滤
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
obj = djsngo-session.object.filter(session-key="2312312sadasdasdas2312").first()
3. obj.session-data.get(''is_login'')


注销:
del request.session[''is_login''] # 不建议这么做; 要删就要删整条记录
request.session.flush()

1. session_str = request.COOKIE.get(''sessionid'')
2. django-session.object.filter(session-key=session-str).delete()
3. response.delete_cookie(''sessionid'')

session 配置:
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
配置 settings.py

SESSION_ENGINE = ''django.contrib.sessions.backends.db'' # 引擎(默认)

SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认)
SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认)
SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认)
SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认)
SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)


总结:
1. 写cookie:
response.set_cookie(key,value)
2, 读cookie:
request.COOKIE.get(key)
3. 写session
request.session[key] = value
注意django对应得操作
if request.COOKIE.get(''sessionid''):
在django-session表中更新一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''alice''}
else:
1. 生成随机字符串
2. response.set_cookie(''sessionid'',2312312sadasdasdas2312)
3. 在django-session表中创建一条记录:
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
4. 读session:
request.session[key]
1. request.COOKIE.get(''sessionid'') # 2312312sadasdasdas2312
2. django-session表中得记录过滤
session-key session-data
2312312sadasdasdas2312 {"is_login":True,"username":''yuan''}
obj = djsngo-session.object.filter(session-key="2312312sadasdasdas2312").first()
3. obj.session-data.get(''is_login'')
5. 删session:
request.session.flush()
1. session_str = request.COOKIE.get(''sessionid'')
2. django-session.object.filter(session-key=session-str).delete()
3. response.delete_cookie(''sessionid'')

 

关于Django;如何更改django.contrib.sessions使用的表名?django修改admin页面的问题就给大家分享到这里,感谢你花时间阅读本站内容,更多关于12 Django cooking与session、25 Jun 18 Django,Cookie,Session,分页(自定义,Django自带)、Django - cookie & session、Django - Cookie、Session、自定义分页和Django分页器等相关知识的信息别忘了在本站进行查找喔。

本文标签: