Python入门自学进阶-Web框架——20Django其他相关知识2

Posted kaoa000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python入门自学进阶-Web框架——20Django其他相关知识2相关的知识,希望对你有一定的参考价值。

三、缓存

 

缓存是可以在任何地方,如内存、文件、数据库、其他机器的内存等。

Django提供的缓存机制:

1、开发调试(虚拟缓存)
2、内存  (本地内存)
3、文件
4、数据库
5、Memcache缓存(python-memcached模块)    (分布式内存)
6、Memcache缓存(pylibmc模块)                   (分布式内存)

设置缓存:

缓存系统需要少量的设置。必须知道缓存数据应该放在哪里 —— 是在数据库中,还是在文件系统上,或者直接放在内存中。这是一个重要的决定,会影响你的缓存的性能;有些缓存类型比其他类型快。

缓存设置项位于配置文件的缓存配置中。

在settings.py中增加:

CACHES = 
    'default': 
        'BACKEND': 'django.core.cache.backends.dummy.DummyCache',    # 引擎
        'TIMEOUT': 300,                                              # 缓存超时时间,默认300,None表示永不过期,0表示立即过期
        'OPTIONS': 
            'MAX_ENTRIES': 300,                                      # 最大缓存条数,默认300
            'CULL_FREQUENCY': 3,                                     # 当达到 MAX_ENTRIES 时,被删除的条目的比例。实际比例是 1 / CULL_FREQUENCY
        ,
        'KEY_PREFIX': '',                                            # 缓存key的前缀(默认空
        'VERSION': 1,                                                # 缓存key的版本,默认1
        'KEY_FUNCTION': hanshu_函数名,                                # 生成key的函数,默认函数会生成:【前缀:版本:key】
    

上面是开发调试,即虚拟缓存的配置,其他的缓存,主要是BACKEND的不同:

'django.core.cache.backends.db.DatabaseCache'
'django.core.cache.backends.dummy.DummyCache'
'django.core.cache.backends.filebased.FileBasedCache'
'django.core.cache.backends.locmem.LocMemCache'
'django.core.cache.backends.memcached.PyMemcacheCache'
'django.core.cache.backends.memcached.PyLibMCCache'

另外还有一个重要的配置项是LOCATION,指定缓存的位置。

对于内存缓存,'django.core.cache.backends.locmem.LocMemCache',其LOCATION指定缓存的名字,相当于一个变量名,内存缓存就是内存中的一块区域,可以看成是一个字典,这里的LOCATION就是这个字典的名字,‘LOCATION’:‘unique-snowflake’,

对于文件缓存,'django.core.cache.backends.filebased.FileBasedCache',其LOCATION指定缓存的文件夹位置,如'LOCATION': '/var/tmp/django_cache',

对于数据库缓存,'django.core.cache.backends.db.DatabaseCache',其LOCATION指定缓存的数据库表名,如‘LOCATION’:‘my_cache_table’,需要执行创建表命令:python manage.py createcachetable

对于Memcache——python-memcached,'django.core.cache.backends.memcached.PyMemcacheCache',其LOCATION指定另外一台机器:

1)‘LOCATION’:‘127.0.0.1:11211’,  以IP和端口方式连接

2)‘LOCATION’:‘unix:/tmp/memcached.sock’,以socket方式连接,一个文件,文件中写了连接信息,只能连本机。

3)'LOCATION':['172.1.1.1:12211','172.1.1.2:12211',],一个列表指定多台机器,就是集群了,还可以列表中是元组项,指定权重:
'LOCATION':[('172.1.1.1:12211',10),('172.1.1.2:12211',20),],

对于'django.core.cache.backends.memcached.PyLibMCCache'同上面。

应用:主要有全站使用、单独视图缓存、局部视图使用

1、单独视图缓存

首先配置settings,然后使用装饰器cache_page:

# settings中的配置
CACHES = 
    'default': 
        'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
        'LOCATION': os.path.join(BASE_DIR,'cache'),
    

单独的视图函数使用装饰器来使用缓存:

# 后台视图函数,引入装饰器,对单独函数使用缓存
from django.views.decorators.cache import cache_page
@cache_page(20)    # 参数代表超时时间,单位是秒
def cache(req):
    import time
    v = time.time()
    print(v)
    return HttpResponse(v)

运行后,在文件夹中出现内容了:

 看运行结果:

 第一次请求时,视图函数运行打印了时间,后来的请求都没有运行,20秒后,缓存过期,函数又运行了,打印。

2、局部缓存使用,(前端页面的部分缓存)

使用在模板上,在模板中,先引入模板标签,即引入TemplateTag:% load cache %

然后使用缓存:% cache 10 缓存key % 缓存内容 % endcache %

视图函数:

def part(req):
    import time
    v = time.time()
    print(v)
    return render(req,'part.html','v':v)

前端模板:

% load cache %
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1> v </h1>
    % cache 20 key-11 %
    <h3> v </h3>
    % endcache %
</body>
</html>

这里会缓存<h3>的内容,在缓存中,其键的值会是“:1:key-11”。

访问时:在缓存时间内,H1数据一直变化,H3是不变的,这个数据从缓存中来。

 后台的打印结果:

每次请求都打印,即都执行了函数,说明函数没有缓存。 

3、全站使用,(要使用中间件)

一般使用两个中间件,一个放在中间件链的开始,一个放在最后,放在最后的中间件,执行process_request,放在第一个的中间件,执行process_response。

这样放的理由:一个请求的到来,是需要经过所有process_request的,相当于过安检,安检过后,才能判断是否在缓存中,也就是在执行视图函数前判断缓存,如果不放在最后一个,有可能安检不通过也能获取数据了,这是放在最后中间件的原因,这个中间件是取缓存的功能,还要有一个中间件放在第一位置,主要执行数据的缓存功能,是执行process_response,这是因为对于返回的内容,其他中间件有可能会进行修改,如果不是第一个,就不是最后执行process_response的中间件,所缓存的内容可能不是最终的内容。(一定要与前面中间件的执行顺序相结合进行理解)。

这两个中间件一个是'django.middleware.cache.UpdateCacheMiddleware'——更新缓存内容,实现内容的缓存和'django.middleware.cache.FetchFromCacheMiddleware'——从缓存中获取内容。

配置如下:

MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其他中间件。。。
        'django.middleware.cache.FetchFromCacheMiddleware',
]

这样配置后,全站缓存就启用了。

这时再访问前面的part页面时,H1和H3的内容都不变了,都进行了缓存。

 四、信号(Django预留的钩子)

Django有一个“信号调度器(signal dispatcher)”,用来帮助解耦的应用获知框架内任何其他地方发生了操作。简单地说,信号允许某些 发送器 去通知一组 接收器 某些操作发生了。当许多代码段都可能对同一事件感兴趣时,信号特别有用。

内置信号集 使用户代码能够获得 Django 自身某些操作的通知

内置信号:

Model signals
    pre_init                 # django的model执行其构造方法前,自动触发
    post_init               # django的model执行其构造方法后,自动触发
    pre_save             # django的model对象保存前,自动触发
    post_save            # django的model对象保存后,自动触发
    pre_delete            # django的model对象删除前,自动触发
    post_delete          # django的model对象删除后,自动触发
    m2m_changed     # django的model中使用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内置的信号,仅需注册指定信号,当程序执行相应操作时,自动触发注册函数:

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("xxoo_callback")
    print(sender,kwargs)

xxoo.connect(callback)
# xxoo指上述导入的内容,即pre_init、post_init等,如pre_init.connect(callback)

注册的时机,因为是要对所有的一类操作进行信号处理,所有要程序一运行就要注册上去。所以一般写在应用的__init__.py中。

启动项目,会打印:

xxoo_callback
<class 'django.db.backends.sqlite3.base.DatabaseWrapper'> 'signal': <django.dispatch.dispatcher.Signal object at 0x000000000B796160>, 'connection': <django.db.backends.sqlite3.base.DatabaseWrapper object at 0x000000000AD99C50> 

测试model的信号pre_init和post_init:

创建models类:

from django.db import models

# Create your models here.
from  django.db import models

class User(models.Model):
    username = models.CharField(max_length=32)
    pwd = models.CharField(max_length=32)

注册信号:

from django.db.backends.signals import connection_created
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

def callback(sender,**kwargs):
    print("xxoo_callback")
    print(sender,"-----",kwargs)

def callback2(sender,**kwargs):
    print("xxoo_callback2")
    print(sender,"-----",kwargs)

connection_created.connect(callback)
pre_init.connect(callback)
post_init.connect(callback2)

视图函数:

def signal(req):
    from midwares import models
    oo = models.User(username='root',pwd='123')
    return HttpResponse('ok')

urls中增加 : path('signal/',views.signal),

前端访问signal:打印结果

xxoo_callback
<class 'midwares.models.User'> ----- 'signal': <django.db.models.signals.ModelSignal object at 0x000000000AFF3198>, 'args': (), 'kwargs': 'username': 'root', 'pwd': '123'
xxoo_callback2
<class 'midwares.models.User'> ----- 'signal': <django.db.models.signals.ModelSignal object at 0x000000000AFF34A8>, 'instance': <User: User object (None)>

对于callback,是pre_init信息注册的,在实例化前执行,sender是<class 'midwares.models.User'>,说明是User类触发的信号,参数中args是位置参数,这里没有传递位置参数,kwargs是我们创建User类对象时传递的参数,username=root,pwd=123,这些就可以在实例化前进行记录。

对于callback2,是实例化后执行的,参数instance是实例化后的对象

以上是Django定义的内置信号,下面我们自定义自己的信号:

1)定义信号:
import django.dispatch
pizza_done = django.dispatch.Singnal(providing_args=["toppings","size"])

def mysignal(req):
    from midwares import pizza_done   # 从应用的__init__.py模块中引入,只需写应用的名,不必加__init__
    pizza_done.send(sender='调用者',toppings='123',size='456') # 自定义的信号,需要自己主动触发,触发就是调用send方法
    return HttpResponse('ok')

2)注册信号:
def callback(sender,**kwargs):
        print("callback")
        print(sender,kwargs)

pizza_done.connect(callback)

3)触发信号:
from 路径 import pizza_done
pizza_done.send(sender='seven',toppings=123,size=456)

示例测试:

在__init__.py中定义信号和注册信号:

# 以下是定义信号
import django.dispatch
pizza_done = django.dispatch.Signal(providing_args=['toppings','size'])
# 定义回调函数,注册信号
def callback3(sender,**kwargs):
    print("自定义信号callback3")
    print(sender,kwargs)

pizza_done.connect(callback3)

触发信号:在视图函数中需要自己触发

def mysignal(req):
    from midwares import pizza_done   # 从应用的__init__.py模块中引入,只需写应用的名,不必加__init__
    pizza_done.send(sender='调用者',toppings='123',size='456') # 自定义的信号,需要自己主动触发,触发就是调用send方法
    return HttpResponse('ok')

运行结果:

自定义信号callback3
调用者 'signal': <django.dispatch.dispatcher.Signal object at 0x000000000B786198>, 'toppings': '123', 'size': '456'

应用场景:预留插拔接口,如某操作后,需要发送提醒,一开始是短信,后来增加邮件,在增加微信、QQ等,这时使用信号,只要增加callback函数,注册信号就行。

五、BootStrap,集成了css、js一个文件夹  ---   响应式+模板

css:在前端网页中引入相应的css,在head中:<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css" >

响应式:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap-5.1.3-dist/css/bootstrap.css">
    <style>
        .pg-header
            height: 48px;
            background-color: black;
        
        @media (max-width: 700px) 
            .extra
                background-color: yellow;
            
        
    </style>
</head>
<body>
    <div class="pg-header extra"></div>
</body>
</html>

 

 上面的页面,随着浏览器窗口宽度的变化,在700px以上,div的背景是黑色,缩小的700px以下时,背景变为黄色。这就是响应式。主要是使用@media,bootstrap中的container就是响应式容器

bootstrap中提供了栅格的样式:col-sm-xx,col-md-xx

js:需要先引入jQuery,然后引入bootstrap.js

以上是关于Python入门自学进阶-Web框架——20Django其他相关知识2的主要内容,如果未能解决你的问题,请参考以下文章

Python入门自学进阶-Web框架——18FormModelForm

Python入门自学进阶-Web框架——18FormModelForm

Python入门自学进阶-Web框架——2Django初识

Python入门自学进阶-Web框架——3Django的URL配置

Python入门自学进阶-Web框架——21DjangoAdmin项目应用

Python入门自学进阶-Web框架——21DjangoAdmin项目应用