Django之缓存、信号和图片验证码
生活随笔
收集整理的這篇文章主要介紹了
Django之缓存、信号和图片验证码
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、 緩存
1、 介紹
緩存通俗來說:就是把數(shù)據(jù)先保存在某個地方,下次再讀取的時候不用再去原位置讀取,讓訪問速度更快。
緩存機制圖解
?
2、Django中提供了6種緩存方式
1. 開發(fā)調試
2. 內存
3. 文件
4. 數(shù)據(jù)庫
5. Memcache緩存(python-memcached模塊)
6. Memcache緩存(pylibmc模塊)
?
3、 配置緩存(在setting中配置)
配置緩存1. 開發(fā)調試# 此為開始調試用,實際內部不做任何操作CACHES = {'default': {'BACKEND': 'django.core.cache.backends.dummy.DummyCache', # 引擎'TIMEOUT': 300, # 緩存超時時間(默認300,None表示永不過期,0表示立即過期)'OPTIONS':{'MAX_ENTRIES': 300, # 最大緩存?zhèn)€數(shù)(默認300)'CULL_FREQUENCY': 3, # 緩存到達最大個數(shù)之后,剔除緩存?zhèn)€數(shù)的比例,即:1/CULL_FREQUENCY(默認3) },'KEY_PREFIX': '', # 緩存key的前綴(默認空)'VERSION': 1, # 緩存key的版本(默認1)'KEY_FUNCTION' 函數(shù)名 # 生成key的函數(shù)(默認函數(shù)會生成為:【前綴:版本:key】) }}# 自定義keydef default_key_func(key, key_prefix, version):"""Default function to generate keys.Constructs the key used by all other methods. By default it prependsthe `key_prefix'. KEY_FUNCTION can be used to specify an alternatefunction with custom key making behavior."""return '%s:%s:%s' % (key_prefix, version, key)def get_key_func(key_func):"""Function to decide which key function to use.Defaults to ``default_key_func``."""if key_func is not None:if callable(key_func):return key_funcelse:return import_string(key_func)return default_key_func2. 內存# 此緩存將內容保存至內存的變量中CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache','LOCATION': 'unique-snowflake','TIMEOUT': 300, # 緩存超時時間(默認300,None表示永不過期,0表示立即過期)'OPTIONS': {'MAX_ENTRIES': 300, # 最大緩存?zhèn)€數(shù)(默認300)'CULL_FREQUENCY': 3, # 緩存到達最大個數(shù)之后,剔除緩存?zhèn)€數(shù)的比例,即:1/CULL_FREQUENCY(默認3) },}}3. 文件# 此緩存將內容保存至文件# 配置: CACHES = {'default': {'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache','LOCATION': '/var/tmp/django_cache', # 文件路徑 }}# 注:其他配置同開發(fā)調試版本4. 數(shù)據(jù)庫# 此緩存將內容保存至數(shù)據(jù)庫# 配置:CACHES = {'default': {'BACKEND': 'django.core.cache.backends.db.DatabaseCache','LOCATION': 'my_cache_table', # 數(shù)據(jù)庫表 }}# 注:執(zhí)行創(chuàng)建表命令 python manage.py createcachetable5. Memcache緩存(python-memcached模塊)# 此緩存使用python-memcached模塊連接memcache CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache','LOCATION': '127.0.0.1:11211',}}CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache','LOCATION': 'unix:/tmp/memcached.sock',}} CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache','LOCATION': ['172.19.26.240:11211','172.19.26.242:11211',]}}6. Memcache緩存(pylibmc模塊)# 此緩存使用pylibmc模塊連接memcache CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache','LOCATION': '127.0.0.1:11211',}}CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache','LOCATION': '/tmp/memcached.sock',}} CACHES = {'default': {'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache','LOCATION': ['172.19.26.240:11211','172.19.26.242:11211',]}}?
4、 簡單的應用
1. 給單獨的視圖應用緩存: 粒度適中方式一:views.pyfrom django.views.decorators.cache import cache_page@cache_page(15) # 緩存15秒后失效def user_list(request):print('user_list')users = models.User.objects.all()return render(request, 'user_list.html', {'users': users})方式二:urls.pyfrom myapp.views import user_listfrom django.views.decorators.cache import cache_pageurlpatterns = [url(r'^user_list/$', cache_page(15)(user_list)),]2. 全站應用: 粒度最大(settings.py)使用中間件,經(jīng)過一系列的認證等操作,如果內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容并返回給用戶,當返回給用戶之前,判斷緩存中是否已經(jīng)存在,如果不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現(xiàn)全站緩存MIDDLEWARE = [# 站點緩存 , 注意必須在第一個位置'django.middleware.cache.UpdateCacheMiddleware',# 其他中間件...# 站點緩存 , 注意必須在最后一個位置'django.middleware.cache.FetchFromCacheMiddleware',]CACHE_MIDDLEWARE_ALIAS = ""CACHE_MIDDLEWARE_SECONDS = 300 # 緩存有效時間CACHE_MIDDLEWARE_KEY_PREFIX = ""3. 局部視圖(在HTML頁面設置哪些需要緩存):粒度最細a. 引入TemplateTag{% load cache %}b. 使用緩存{% cache 300 '緩存key' %} # 緩存key的名字可以是隨意的 緩存內容{% endcache %}?
二、 序列化
1、介紹
關于Django中的序列化主要應用在將數(shù)據(jù)庫中檢索的數(shù)據(jù)返回給客戶端用戶,特別的Ajax請求一般返回的為Json格式。
?
2、serializers
from django.core import serializers def get_value(request):users = models.User.objects.all()ret = serializers.serialize('json', users)return HttpResponse(ret)?
3、自定義序列化
由于json模塊并不能轉換時間類型的數(shù)據(jù),因此需要我們自定義一個類來處理時間類型的數(shù)據(jù)import json from datetime import datetime, datedata = [ # data數(shù)據(jù)中有datetime類型的值, json不能直接序列化{"pk": 1, "name": "\u83b9\u83b9", "age": 18, 'birth': datetime.now()},{"pk": 2, "name": "\u5c0f\u5fae", "age": 16, 'birth': datetime.now()},{"pk": 3, "name": "\u5c0f\u9a6c\u54e5", "age": 8, 'birth': datetime.now()},{"pk": 4, "name": "qqq", "age": 5, 'birth': datetime.now()},{"pk": 5, "name": "www", "age": 5, 'birth': datetime.now()} ] # json序列化的時候是調用JSONEncoder這個類的default方法進行序列化的 class JsonCustomEncoder(json.JSONEncoder): # 自定義一個類,重新json.dumps的default方法def default(self, field): # 循環(huán)每個字段的值if isinstance(field, datetime): # 如果這個值是datetime類型,我們自己把它轉成字符串類型的時間return field.strftime('%Y-%m-%d %H:%M:%S')elif isinstance(field, date): # 如果這個值是date類型,我們自己把它轉成字符串類型的時間return field.strftime('%Y-%m-%d')else:return json.JSONEncoder.default(self, field) # 如果這個值不是時間類型,調用其父類原本的default方法進行序列化print(json.dumps(data,cls=JsonCustomEncoder)) # cls指定序列化的時候去執(zhí)行這個類?
三、 信號
1、介紹
Django中提供了“信號調度”,用于在框架執(zhí)行操作時解耦。通俗來講,就是一些動作發(fā)生的時候,信號允許特定的發(fā)送者去提醒一些接受者。
?
2、內置信號
Model signalspre_init # django的model執(zhí)行其構造方法前,自動觸發(fā)post_init # django的model執(zhí)行其構造方法后,自動觸發(fā)pre_save # django的model對象保存前,自動觸發(fā)post_save # django的model對象保存后,自動觸發(fā)pre_delete # django的model對象刪除前,自動觸發(fā)post_delete # django的model對象刪除后,自動觸發(fā)m2m_changed # django的model中使用m2m字段操作第三張表(add,remove,clear)前后,自動觸發(fā)class_prepared # 程序啟動時,檢測已注冊的app中modal類,對于每一個類,自動觸發(fā) Management signalspre_migrate # 執(zhí)行migrate命令前,自動觸發(fā)post_migrate # 執(zhí)行migrate命令后,自動觸發(fā) Request/response signalsrequest_started # 請求到來前,自動觸發(fā)request_finished # 請求結束后,自動觸發(fā)got_request_exception # 請求異常后,自動觸發(fā) Test signalssetting_changed # 使用test測試修改配置文件時,自動觸發(fā)template_rendered # 使用test測試渲染模板時,自動觸發(fā) Database Wrappersconnection_created # 創(chuàng)建數(shù)據(jù)庫連接時,自動觸發(fā)?
3、使用
1. 場景:數(shù)據(jù)庫增加一條數(shù)據(jù)時,就記錄一條日志,若不使用信號,則需要在每個創(chuàng)建語句下面寫記錄日志的語句。2. 介紹 對于Django內置的信號,僅需注冊指定信號,當程序執(zhí)行相應操作時,自動觸發(fā)注冊函數(shù) 注冊信號,寫入與project同名的文件夾下的_init_.py文件中,也是換數(shù)據(jù)庫引擎的地方。3. 注冊信號步驟 1. 導入需要的信號模塊(這里列出全部模塊,實際開發(fā)的時候需要哪個就導入哪個) from django.core.signals import request_finished from django.core.signals import request_started from django.core.signals import got_request_exceptionfrom 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_migratefrom django.test.signals import setting_changed from django.test.signals import template_renderedfrom django.db.backends.signals import connection_created2. 定義函數(shù)來處理信號 # 方法一 from django.db.models.signals import post_save # 函數(shù)名可隨意,但是參數(shù)(sender, **kwargs)是固定的,就這兩個參數(shù) def callback(sender, **kwargs): print("xxoo_callback")print(sender, kwargs)post_save.connect(callback) # 注冊post_save信號:django的model對象保存后,自動觸發(fā)callback函數(shù) # post_save信號中,render就是觸發(fā)信號的那一個ORM類(表) # kwargs就是這個類的一些參數(shù):instance是這個類的實例,created:是否是創(chuàng)建操作# 方法二 from django.db.models.signals import post_save from django.dispatch import receiver @receiver(post_save) def my_callback(sender, **kwargs):print("xxoo_callback")print(sender, kwargs)# 方法三:指定觸發(fā)者 from django.db.models.signals import post_save from django.dispatch import receiver from myapp.models import MyModel # 指定只有MyModel這個類才能觸發(fā)這個函數(shù) @receiver(post_save, sender=MyModel) def my_callback(sender, **kwargs):print("xxoo_callback")print(sender, kwargs)# 或者 post_save.connect(callback, sender=MyModel)?
4、自定義信號
a. 定義信號 在某py文件中定義信號。import django.dispatch # pizza_done是信號名 # providing_args是傳給信號綁定的函數(shù)的kwargs pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])b. 注冊信號 在_init_.py 中注冊信號 from 路徑 import pizza_donedef callback(sender, **kwargs):print("callback")print(sender,kwargs)pizza_done.connect(callback)c. 觸發(fā)信號 from 路徑 import pizza_donepizza_done.send(sender='seven',toppings=123, size=456) 由于內置信號的觸發(fā)者已經(jīng)集成到Django中,所以其會自動調用,而對于自定義信號則需要開發(fā)者在任意位置觸發(fā)。?
?
四、 ORM性能相關
0、 表結構class Role(models.Model):name = models.CharField(max_length=32)class User(models.Model):name = models.CharField(max_length=32)age = models.IntegerField()role = models.ForeignKey('Role', null=True, blank=True)1、 直接查詢--> [ 對象 ]用的時候注意,只拿自己表中的字段,別跨表,比如all_users有3條數(shù)據(jù),user表通過外鍵關聯(lián)role表,如果要跨表拿到role表的name字段:all_users = models.User.objects.all()for user in all_users:print(user.name, user.age, user.role.name)其實一個進行了四次查詢,第一次查詢出all_users,然后每次的user.role.name都去role表查2、 要用到跨表字段的時候,使用values或values_list查詢速度更快,只需一次查詢即可--> [{}]all_users = models.User.objects.all().values('name','age','role__name')for user in all_users:print(user['name'], user['age'], user['role__name'])3、 select_related:連表較少的時候使用,如:外鍵、一對一查詢的時候把關聯(lián)的表也一起查了,也是一次查詢出結果,跟values不同的是,可以直接用點取字段all_users = models.User.objects.all().select_related('role')for user in all_users:print(user.name, user.age, user.role.name)4、 prefetch_related:連表較多的時候使用,如:多對多字段和一對多字段all_users = models.User.objects.all().prefetch_related('role')for user in all_users:print(user.name, user.age, user.role.name)5、 only:將指定的字段查詢加載出來,后續(xù)再訪問指定的字段就不需要再查詢數(shù)據(jù)庫all_users = models.User.objects.all().only('name')用的時候注意,只拿自己指定的字段6、 defer:將除了指定的字段查詢加載出來,后續(xù)再訪問指定的字段就不需要再查詢數(shù)據(jù)庫(only的反義詞)all_users = models.User.objects.all().defer('name')?
五、 驗證碼
1、隨機驗證碼python代碼
import randomdef get_code():code = ''for i in range(6):num = str(random.randint(0, 9)) # 數(shù)字lower = chr(random.randint(97, 122)) # 小寫字母upper = chr(random.randint(65, 90)) # 大寫字母c = random.choice([num, lower, upper]) # 隨機選取一個code += str(c)return code?
2、如何生成圖片
1. 驗證碼的形式 回想一下,平時我們輸入驗證碼的時候,是不是都是看著一張圖片,圖片上顯示驗證碼,我們看著圖片輸入驗證碼。 當然現(xiàn)在還有滑動的,點擊等等,這里我們先學習圖片的形式。2. 實現(xiàn)步驟 1, 準備一張沒有任何內容的圖片2, 安裝python專門處理圖片的第三方包 pip install Pillow3, 包的導入 from PIL import Image, ImageDraw, ImageFont4, Image:生成一張圖片 ImageDraw:生成一個畫筆,用于在圖片上畫驗證碼 ImageFont:字體的格式和大小5,示例 from PIL import Image, ImageDraw, ImageFont# 返回隨機的RGB數(shù)字 def random_color():return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)def get_code():with open('1.png', 'wb') as f:# 第一步:生成一張圖片(畫布)# 創(chuàng)建一個隨機顏色的圖片對象# 參數(shù):顏色模式,圖片大小,圖片顏色img_obj = Image.new('RGB', (250, 35), random_color())# 第二步:在該圖片對象上生成一個畫筆對象draw_obj = ImageDraw.Draw(img_obj)# 使用什么字體,字體大小font_obj = ImageFont.truetype('static/font/kumo.ttf', 28)# 生成驗證碼code = ''for i in range(6):num = str(random.randint(0, 9)) # 數(shù)字lower = chr(random.randint(97, 122)) # 小寫字母upper = chr(random.randint(65, 90)) # 大寫字母c = random.choice([num, lower, upper]) # 隨機選取一個code += str(c)# 用畫筆把驗證碼畫到圖片上# 參數(shù):xy:坐標,畫在哪個位置;text:畫的內容;fill:畫什么顏色;font:字體格式draw_obj.text((35 + i*30, 0), c, fill=random_color(), font=font_obj)# 保存圖片 img_obj.save(f)get_code()6,缺點 上面的代碼是在你的硬盤上存了一張圖片,如果要在頁面上展示,你還得進行文件的讀, 這樣的話不僅浪費硬盤空間,效率還不夠高,因此我們應該把圖片寫到內存,從內存中取,效率就快很多了, 然后把圖片的驗證碼數(shù)據(jù)存到session,這樣登錄的時候就可以校驗了。?
?
3、在視圖中使用驗證碼
1. urls urlpatterns = [# 獲取圖片的路由url(r'^login/', views.login),url(r'^v_code/', views.v_code), ]2. 在頁面中點擊驗證碼圖片,刷新驗證碼 <!DOCTYPE html> <html lang="zh-CN"> <head><meta http-equiv="content-Type" charset="UTF-8"><meta http-equiv="x-ua-compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1"><title>Title</title> </head> <body><form action='' method='POST'>{% csrf_token %}<input type='text' name='username'>用戶名<input type='password' name='password'>密碼<img src="/v_code/" alt="圖片加載失敗" id="v_code"><button type="submit">登錄</button> </form><script>img = document.getElementById('v_code');img.onclick = function () {img.src += '?'} </script></body> </html>3. 驗證碼視圖函數(shù) from PIL import Image, ImageDraw, ImageFont import randomdef random_color():return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)def v_code(request):# 第一步:生成一張圖片(畫布)# 創(chuàng)建一個隨機顏色的圖片對象# 參數(shù):顏色模式,圖片大小,圖片顏色img_obj = Image.new('RGB', (250, 35), random_color())# 第二步:在該圖片對象上生成一個畫筆對象draw_obj = ImageDraw.Draw(img_obj)# 使用什么字體,字體大小font_obj = ImageFont.truetype('static/font/kumo.ttf', 28)# 生成驗證碼code = ''for i in range(6):num = str(random.randint(0, 9)) # 數(shù)字lower = chr(random.randint(97, 122)) # 小寫字母upper = chr(random.randint(65, 90)) # 大寫字母c = random.choice([num, lower, upper]) # 隨機選取一個code += str(c)# 用畫筆把驗證碼畫到圖片上# 參數(shù):xy:坐標,畫在哪個位置;text:畫的內容;fill:畫什么顏色;font:字體格式draw_obj.text((35 + i*30, 0), c, fill=random_color(), font=font_obj)# 把圖片里面的驗證碼的內容寫到session,且忽略大小寫request.session['v_code'] = code.upper()# 把圖片寫到內存from io import BytesIOf1 = BytesIO() # 類似于文件的文件句柄:f1 = open()# 把圖片保存到內存img_obj.save(f1, format="PNG")# 從內存中取數(shù)據(jù)img_data = f1.getvalue()return HttpResponse(img_data, content_type='image/png')4. 登錄視圖函數(shù) def login(request):err_msg = ''if request.method == 'POST':username = request.POST.get('username')password = request.POST.get('password')v_code = request.POST.get('v_code', '').upper()if v_code == request.session.get('v_code'):obj = auth.authenticate(request, username=username, password=password)if obj:auth.login(request, obj)# 認證成功 初始化權限信息ret = init_permission(request, obj)if ret:return retreturn redirect(reverse('my_customer'))err_msg = '用戶名或密碼錯誤'else:err_msg = '驗證碼錯誤'return render(request, 'login.html', {'err_msg': err_msg})?
4、驗證碼的額外小知識
畫完驗證碼后,可以添加一些干擾 就是在 draw_obj.text((35 + i*30, 0), c, fill=random_color(), font=font_obj)之后加1. 加干擾線 width = 250 # 圖片寬度(防止越界) height = 35 for i in range(5):x1 = random.randint(0, width)x2 = random.randint(0, width)y1 = random.randint(0, height)y2 = random.randint(0, height)draw_obj.line((x1, y1, x2, y2), fill=random_color())2. 加干擾點 for i in range(40):draw_obj.point([random.randint(0, width), random.randint(0, height)], fill=random_color())x = random.randint(0, width)y = random.randint(0, height)draw_obj.arc((x, y, x+4, y+4), 0, 90, fill=random_color())?
轉載于:https://www.cnblogs.com/Zzbj/p/10127624.html
總結
以上是生活随笔為你收集整理的Django之缓存、信号和图片验证码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据结构课程设计:基于有序表的仓库管理系
- 下一篇: 文件辅助类封装