zoukankan      html  css  js  c++  java
  • 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 class="active"><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 class="active"><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 class="disabled"><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 class="active"><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 class="disabled"><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 class="disabled"><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 class="active"><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 class="disabled"><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')

     

  • 相关阅读:
    Binding to a Service
    UML类图几种关系的总结
    阿里云调试
    Serif和Sans-serif字体的区别
    从Log4j迁移到LogBack的理由
    logback
    java 解析json格式数据(转)
    开源Web测试工具介绍
    GET乱码以及POST乱码的解决方法
    单元测试框架TestNg使用总结
  • 原文地址:https://www.cnblogs.com/alice-bj/p/9091922.html
Copyright © 2011-2022 走看看