• Django 分页器 缓存 信号 序列化


    阅读目录

    Django分页器  (paginator)

    导入

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

    view

    from django.shortcuts import render,HttpResponse
    from app01.models import *
    from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
    
    def index(request):
    
    
        currentPage = request.GET.get("page",1)
        currentPage = int(currentPage)
    
        book_list = foo.objects.all()
        paginator = Paginator(book_list, 10)  # 每页显示10条数据
    
        # print("count:",paginator.count)           #数据总数
        # print("num_pages",paginator.num_pages)    #总页数
        # print("page_range",paginator.page_range)  #页码的列表
    
        if paginator.num_pages>10:
    
            if currentPage-5<1:
                pageRange=range(1,10)
            elif currentPage+5>paginator.num_pages:
                pageRange=range(currentPage-5,paginator.num_pages+1)
    
            else:
                pageRange=range(currentPage-4,currentPage+5)
    
        else:
            pageRange=paginator.page_range
    
    
        try:
            book_list = paginator.page(currentPage)  # 第num页的page对象
        except EmptyPage:  # 如果大于总页数
            book_list = paginator.page(paginator.num_pages)
        except PageNotAnInteger:  # 如果num不是数字
            book_list = paginator.page(1)
    
    
        # print(book_list.object_list) #第1页的所有数据  QuerySet
        # print(book_list.has_next())            #是否有下一页
        # print(book_list.next_page_number())    #下一页的页码
        # print(book_list.has_previous())        #是否有上一页
        # print(book_list.previous_page_number()) #上一页的页码
    
    
        # 抛错
        # page=paginator.page(12)   # error:EmptyPage
        # page=paginator.page("z")   # error:PageNotAnInteger
    
    
        return render(request,"inde.html",locals())

     模版

    <!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 pageRange %}
    
                         {% 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>

    自定义分页器组件

    """
    分页组件使用示例:
    
        obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info,request.GET)
        page_user_list = USER_LIST[obj.start:obj.end]
        page_html = obj.page_html()
    
        return render(request,'index.html',{'users':page_user_list,'page_html':page_html})
        #基于bootstarp样式,需要引入bootstrap的css文件。
    
    """
    
    
    class Pagination(object):
        def __init__(self,current_page,all_count,base_url,params,per_page_num=10,pager_count=11):
            """
            封装分页相关数据
            :param current_page: 当前页
            :param all_count:    数据库中的数据总条数
            :param per_page_num: 每页显示的数据条数
            :param base_url: 分页中显示的URL前缀
            :param pager_count:  最多显示的页码个数
            """
    
            try:
                current_page = int(current_page)
            except Exception as e:
                current_page = 1
            if current_page <1:
                current_page = 1
    
            self.current_page = current_page
    
            self.all_count = all_count
            self.per_page_num = per_page_num
            self.base_url = base_url
    
            # 总页码
            all_pager, tmp = divmod(all_count, per_page_num)
            if tmp:
                all_pager += 1
            self.all_pager = all_pager
    
    
            self.pager_count = pager_count
            self.pager_count_half = int((pager_count - 1) / 2)
    
            import copy
            params = copy.deepcopy(params)
            params._mutable = True
            self.params = params
    
        @property
        def start(self):
            return (self.current_page - 1) * self.per_page_num
    
        @property
        def end(self):
            return self.current_page * self.per_page_num
    
        def page_html(self):
            # 如果总页码 < 11个:
            if self.all_pager <= self.pager_count:
                pager_start = 1
                pager_end = self.all_pager + 1
            # 总页码  > 11
            else:
                # 当前页如果<=页面上最多显示11/2个页码
                if self.current_page <= self.pager_count_half:
                    pager_start = 1
                    pager_end = self.pager_count + 1
    
                # 当前页大于5
                else:
                    # 页码翻到最后
                    if (self.current_page + self.pager_count_half) > self.all_pager:
                        pager_end = self.all_pager + 1
                        pager_start = self.all_pager - self.pager_count + 1
                    else:
                        pager_start = self.current_page - self.pager_count_half
                        pager_end = self.current_page + self.pager_count_half + 1
    
            page_html_list = []
            page_html_list.append('<nav aria-label="Page navigation"><ul class="pagination">')
            self.params["page"] = 1
            first_page = '<li><a href="%s?%s">首页</a></li>' % (self.base_url,self.params.urlencode(),)
            page_html_list.append(first_page)
    
            if self.current_page <= 1:
                prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
            else:
                self.params["page"] = self.current_page - 1
                prev_page = '<li><a href="%s?%s">上一页</a></li>' % (self.base_url,self.params.urlencode(),)
    
            page_html_list.append(prev_page)
    
            for i in range(pager_start, pager_end):
                self.params["page"] = i
                if i == self.current_page:
                    temp = '<li class="active"><a href="%s?%s">%s</a></li>' % (self.base_url,self.params.urlencode(), i,)
                else:
                    temp = '<li><a href="%s?%s">%s</a></li>' % (self.base_url,self.params.urlencode(), i,)
                page_html_list.append(temp)
    
            if self.current_page >= self.all_pager:
                next_page = '<li class="disabled"><a href="#">下一页</a></li>'
            else:
                self.params["page"] = self.current_page + 1
                next_page = '<li><a href="%s?%s">下一页</a></li>' % (self.base_url,self.params.urlencode(),)
            page_html_list.append(next_page)
            self.params["page"] = self.all_pager
            last_page = '<li><a href="%s?%s">尾页</a></li>' % (self.base_url,self.params.urlencode(),)
            page_html_list.append(last_page)
    
            page_html_list.append('</ul></nav>')
    
            return ''.join(page_html_list)
    View Code

     

    Django 缓存机制

    1.1 缓存介绍

    1.缓存的简介

    在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面.

    当一个网站的用户访问量很大的时候,每一次的的后台操作,都会消耗很多的服务端资源,所以必须使用缓存来减轻后端服务器的压力.

    缓存是将一些常用的数据保存内存或者memcache中,在一定的时间内有人来访问这些数据时,则不再去执行数据库及渲染等操作,而是直接从内存或memcache的缓存中去取得数据,然后返回给用户.

    2.Django提供了6种huan存方式

    • 开发调试缓存
    • 内存缓存
    • 文件缓存
    • 数据库缓存
    • Memcache缓存(使用python-memcached模块)
    • Memcache缓存(使用pylibmc模块)

    经常使用的有文件缓存和Mencache缓存

    1.2 各种缓存配置

    1.2.1 开发调试(此模式为开发调试使用,实际上不执行任何操作)

    settings.py文件配置

    CACHES = {
     'default': {
      'BACKEND': 'django.core.cache.backends.dummy.DummyCache',  # 缓存后台使用的引擎
      'TIMEOUT': 300,            # 缓存超时时间(默认300秒,None表示永不过期,0表示立即过期)
      'OPTIONS':{
       'MAX_ENTRIES': 300,          # 最大缓存记录的数量(默认300)
       'CULL_FREQUENCY': 3,          # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      },
     }
    }
    View Code

    1.2.2 内存缓存(将缓存内容保存至内存区域中)

    settings.py文件配置

    CACHES = {
     'default': {
      'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',  # 指定缓存使用的引擎
      'LOCATION': 'unique-snowflake',         # 写在内存中的变量的唯一值 
      'TIMEOUT':300,             # 缓存超时时间(默认为300秒,None表示永不过期)
      'OPTIONS':{
       'MAX_ENTRIES': 300,           # 最大缓存记录的数量(默认300)
       'CULL_FREQUENCY': 3,          # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      }  
     }
    }
    View Code

    1.2.3 文件缓存(把缓存数据存储在文件中)

    settings.py文件配置

    CACHES = {
     'default': {
      'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', #指定缓存使用的引擎
      'LOCATION': '/var/tmp/django_cache',        #指定缓存的路径
      'TIMEOUT':300,              #缓存超时时间(默认为300秒,None表示永不过期)
      'OPTIONS':{
       'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
       'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      }
     }   
    }
    View Code

    1.2.4 数据库缓存(把缓存数据存储在数据库中)

    settings.py文件配置

    CACHES = {
     'default': {
      'BACKEND': 'django.core.cache.backends.db.DatabaseCache',  # 指定缓存使用的引擎
      'LOCATION': 'cache_table',          # 数据库表    
      'OPTIONS':{
       'MAX_ENTRIES': 300,           # 最大缓存记录的数量(默认300)
       'CULL_FREQUENCY': 3,          # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      }  
     }   
    }
    View Code

    注意,创建缓存的数据库表使用的语句:

    python manage.py createcachetable
    

    1.2.5 Memcache缓存(使用python-memcached模块连接memcache)

    Memcached是Django原生支持的缓存系统.要使用Memcached,需要下载Memcached的支持库python-memcached或pylibmc.

    settings.py文件配置

    CACHES = {
     'default': {
      'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', # 指定缓存使用的引擎
      'LOCATION': '192.168.10.100:11211',         # 指定Memcache缓存服务器的IP地址和端口
      'OPTIONS':{
       'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
       'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      }
     }
    }
    View Code

    LOCATION也可以配置成如下:

    'LOCATION': 'unix:/tmp/memcached.sock',   # 指定局域网内的主机名加socket套接字为Memcache缓存服务器
    'LOCATION': [         # 指定一台或多台其他主机ip地址加端口为Memcache缓存服务器
     '192.168.10.100:11211',
     '192.168.10.101:11211',
     '192.168.10.102:11211',
    ]
    View Code

    1.2.6 Memcache缓存(使用pylibmc模块连接memcache)

    settings.py文件配置
     CACHES = {
      'default': {
       'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',  # 指定缓存使用的引擎
       'LOCATION':'192.168.10.100:11211',         # 指定本机的11211端口为Memcache缓存服务器
       'OPTIONS':{
        'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
        'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
       },  
      }
     }
    View Code

    LOCATION也可以配置成如下:

    'LOCATION': '/tmp/memcached.sock',  # 指定某个路径为缓存目录
    'LOCATION': [       # 分布式缓存,在多台服务器上运行Memcached进程,程序会把多台服务器当作一个单独的缓存,而不会在每台服务器上复制缓存值
     '192.168.10.100:11211',
     '192.168.10.101:11211',
     '192.168.10.102:11211',
    ]
    View Code

    Memcached是基于内存的缓存,数据存储在内存中.所以如果服务器死机的话,数据就会丢失,所以Memcached一般与其他缓存配合使用

      

    1.3 Django中的缓存应用

    Django提供了不同粒度的缓存,可以缓存某个页面,可以只缓存一个页面的某个部分,甚至可以缓存整个网站.

    对一个视图函数设置缓存

    from django.views.decorators.cache import cache_page
    
    import time
    
    from .models import *
    
    
    
    @cache_page(15) #超时时间为15秒
    
    def index(request):
    
    
    
    t=time.time() #获取当前时间
    
    bookList=Book.objects.all()
    
    return render(request,"index.html",locals())

    上面的例子是基于内存的缓存配置,基于文件的缓存该怎么配置呢??

    更改settings.py的配置

    CACHES = {
     'default': {
      'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache', # 指定缓存使用的引擎
      'LOCATION': 'E:django_cache',          # 指定缓存的路径
      'TIMEOUT': 300,              # 缓存超时时间(默认为300秒,None表示永不过期)
      'OPTIONS': {
       'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
       'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
      }
     }
    }
    View Code

    然后再次刷新浏览器,可以看到在刚才配置的目录下生成的缓存文件

    通过实验可以知道,Django会以自己的形式把缓存文件保存在配置文件中指定的目录中. 

      

    全站使用缓存,配置中间件

    既然是全站缓存,当然要使用Django中的中间件.

    用户的请求通过中间件,经过一系列的认证等操作,如果请求的内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户

    当返回给用户之前,判断缓存中是否已经存在,如果不存在,则UpdateCacheMiddleware会将缓存保存至Django的缓存之中,以实现全站缓存

    缓存整个站点,是最简单的缓存方法
    
    
    
    在 MIDDLEWARE_CLASSES 中加入 “update” 和 “fetch” 中间件
    
    MIDDLEWARE_CLASSES = (
    
    ‘django.middleware.cache.UpdateCacheMiddleware’, #第一
    
    'django.middleware.common.CommonMiddleware',
    
    ‘django.middleware.cache.FetchFromCacheMiddleware’, #最后
    
    )
    
    “update” 必须配置在第一个
    
    “fetch” 必须配置在最后一个

    修改settings.py配置文件  

    MIDDLEWARE_CLASSES = (
        'django.middleware.cache.UpdateCacheMiddleware',   #响应HttpResponse中设置几个headers
        'django.contrib.sessions.middleware.SessionMiddleware',
        'django.middleware.common.CommonMiddleware',
        'django.middleware.csrf.CsrfViewMiddleware',
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
        'django.contrib.messages.middleware.MessageMiddleware',
        'django.middleware.clickjacking.XFrameOptionsMiddleware',
        'django.middleware.security.SecurityMiddleware',
        'django.middleware.cache.FetchFromCacheMiddleware',   #用来缓存通过GET和HEAD方法获取的状态码为200的响应
    
    )
    
    
    CACHE_MIDDLEWARE_SECONDS=10
    View Code

    模版局部缓存

    {% load cache %}
    
    <!DOCTYPE html>
    
    <html lang="en">
    
    <head>
    
    <meta charset="UTF-8">
    
    <title>Title</title>
    
    </head>
    
    <body>
    
    <h3 style="color: green">不缓存:-----{{ t }}</h3>
    
    
    
    {% cache 2 'name' %}
    
    <h3>缓存:-----:{{ t }}</h3>
    
    {% endcache %}
    
    
    
    </body>
    
    </html>

      

    Django 信号

    Django提供一种信号机制。其实就是观察者模式,又叫发布-订阅(Publish/Subscribe) 。当发生一些动作的时候,发出信号,然后监听了这个信号的函数就会执行。

    通俗来讲,就是一些动作发生的时候,信号允许特定的发送者去提醒一些接受者。用于在框架执行操作时解耦。

    2.1、Django内置信号 

    Model signals
    
    pre_init # django的modal执行其构造方法前,自动触发
    
    post_init # django的modal执行其构造方法后,自动触发
    
    pre_save # django的modal对象保存前,自动触发
    
    post_save # django的modal对象保存后,自动触发
    
    pre_delete # django的modal对象删除前,自动触发
    
    post_delete # django的modal对象删除后,自动触发
    
    m2m_changed # django的modal中使用m2m字段操作第三张表(add,remove,clear)前后,自动触发
    
    class_prepared # 程序启动时,检测已注册的app中modal类,对于每一个类,自动触发
    
    Management signals
    
    pre_migrate # 执行migrate命令前,自动触发
    
    post_migrate # 执行migrate命令后,自动触发
    
    Request/response signals
    
    request_started # 请求到来前,自动触发
    
    request_finished # 请求结束后,自动触发
    
    got_request_exception # 请求异常后,自动触发
    
    Test signals
    
    setting_changed # 使用test测试修改配置文件时,自动触发
    
    template_rendered # 使用test测试渲染模板时,自动触发
    
    Database Wrappers
    
    connection_created # 创建数据库连接时,自动触发
    Django 提供了一系列的内建信号,允许用户的代码获得DJango的特定操作的通知。这包含一些有用的通知:
    django.db.models.signals.pre_save & django.db.models.signals.post_save
    
    在模型 save()方法调用之前或之后发送。
    django.db.models.signals.pre_delete & django.db.models.signals.post_delete
    
    在模型delete()方法或查询集的delete() 方法调用之前或之后发送。
    django.db.models.signals.m2m_changed
    
    模型上的 ManyToManyField 修改时发送。
    django.core.signals.request_started & django.core.signals.request_finished
    
    Django建立或关闭HTTP 请求时发送。
    View Code

    对于Django内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

    方式1:

    from django.core.signals import request_finished
    
    from django.core.signals import request_started
    
    from django.core.signals import got_request_exception
    
    
    
    from django.db.models.signals import class_prepared
    
    from django.db.models.signals import pre_init, post_init
    
    from django.db.models.signals import pre_save, post_save
    
    from django.db.models.signals import pre_delete, post_delete
    
    from django.db.models.signals import m2m_changed
    
    from django.db.models.signals import pre_migrate, post_migrate
    
    
    
    from django.test.signals import setting_changed
    
    from django.test.signals import template_rendered
    
    
    
    from django.db.backends.signals import connection_created
    
    
    
    
    
    def callback(sender, **kwargs):
    
    print("pre_save_callback")
    
    print(sender,kwargs)
    
    
    
    pre_save.connect(callback) # 该脚本代码需要写到app或者项目的初始化文件中 init文件,当项目启动时执行注册代码

    方式2:  

    from django.core.signals import request_finished
    
    from django.dispatch import receiver
    
    
    
    @receiver(request_finished)
    
    def my_callback(sender, **kwargs):
    
    print("Request finished!")

      

    2.2、自定义信号 

    a. 定义信号  

    import django.dispatch
    
    pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

    b. 注册信号  

    def callback(sender, **kwargs):
    
    print("callback")
    
    print(sender,kwargs)
    
    
    
    pizza_done.connect(callback)

    c. 触发信号  

    from 路径 import pizza_done
    
    
    
    pizza_done.send(sender='seven',toppings=123, size=456)

    由于内置信号的触发者已经集成到Django中,所以其会自动调用,而对于自定义信号则需要开发者在任意位置触发。 

    练习:数据库添加一条记录时生成一个日志记录。

    Django 的序列化

    关于Django中的序列化主要应用在将数据库中检索的数据返回给客户端用户,特别的Ajax请求一般返回的为Json格式。

    1、serializers

    from django.core import serializers
    
    
    
    ret = models.BookType.objects.all()
    
    
    
    data = serializers.serialize("json", ret)

    2、json.dumps  

    import json
    
    
    
    #ret = models.BookType.objects.all().values('caption')
    
    ret = models.BookType.objects.all().values_list('caption')
    
    
    
    ret=list(ret)
    
    
    
    result = json.dumps(ret)

    由于json.dumps时无法处理datetime日期,所以可以通过自定义处理器来做扩展,如:

    import json
    from datetime import date
    from datetime import datetime
    
    d=datetime.now()
    
    class JsonCustomEncoder(json.JSONEncoder):
    
        def default(self, field):
    
            if isinstance(field, datetime):
                return field.strftime('%Y-%m-%d %H:%M---%S')
            elif isinstance(field, date):
                return field.strftime('%Y-%m-%d')
            else:
                return json.JSONEncoder.default(self, field)
    
    
    ds = json.dumps(d, cls=JsonCustomEncoder)
    
    print(ds)
    print(type(ds))
    
    
    
    '''
    Supports the following objects and types by default:
    
        +-------------------+---------------+
        | Python            | JSON          |
        +===================+===============+
        | dict              | object        |
        +-------------------+---------------+
        | list, tuple       | array         |
        +-------------------+---------------+
        | str               | string        |
        +-------------------+---------------+
        | int, float        | number        |
        +-------------------+---------------+
        | True              | true          |
        +-------------------+---------------+
        | False             | false         |
        +-------------------+---------------+
        | None              | null          |
        +-------------------+---------------+
    
    '''

      

    每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)
  • 相关阅读:
    AcWing 157. 树形地铁系统 (hash判断树同构)打卡
    AcWing 156. 矩阵 (哈希二维转一维查询)打卡
    AcWing 144. 最长异或值路径 01字典树打卡
    AcWing 143. 最大异或对 01字典树打卡
    AcWing 142. 前缀统计 字典树打卡
    AcWing 139. 回文子串的最大长度 hash打卡
    AcWing 138. 兔子与兔子 hash打卡
    常用C库函数功能及用法
    编程实现C库函数
    C语言面试题5
  • 原文地址:https://www.cnblogs.com/kylin5201314/p/13995909.html
Copyright © 2020-2023  润新知