一、logging配置
Django项目常用的logging配置
settings.py
LOGGING = { \'version\': 1, \'disable_existing_loggers\': False, \'formatters\': { \'standard\': { \'format\': \'[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]\' \'[%(levelname)s][%(message)s]\' }, \'simple\': { \'format\': \'[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s\' }, \'collect\': { \'format\': \'%(message)s\' } }, \'filters\': { \'require_debug_true\': { \'()\': \'django.utils.log.RequireDebugTrue\', }, }, \'handlers\': { \'console\': { \'level\': \'DEBUG\', \'filters\': [\'require_debug_true\'], # 只有在Django debug为True时才在屏幕打印日志 \'class\': \'logging.StreamHandler\', \'formatter\': \'simple\' }, \'default\': { \'level\': \'INFO\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,自动切 \'filename\': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 \'maxBytes\': 1024 * 1024 * 50, # 日志大小 50M \'backupCount\': 3, \'formatter\': \'standard\', \'encoding\': \'utf-8\', }, \'error\': { \'level\': \'ERROR\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,自动切 \'filename\': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件 \'maxBytes\': 1024 * 1024 * 50, # 日志大小 50M \'backupCount\': 5, \'formatter\': \'standard\', \'encoding\': \'utf-8\', }, \'collect\': { \'level\': \'INFO\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,自动切 \'filename\': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), \'maxBytes\': 1024 * 1024 * 50, # 日志大小 50M \'backupCount\': 5, \'formatter\': \'collect\', \'encoding\': "utf-8" } }, \'loggers\': { # 默认的logger应用如下配置 \'\': { \'handlers\': [\'default\', \'console\', \'error\'], # 上线之后可以把\'console\'移除 \'level\': \'DEBUG\', \'propagate\': True, }, # 名为 \'collect\'的logger还单独处理 \'collect\': { \'handlers\': [\'console\', \'collect\'], \'level\': \'INFO\', } }, }
Python logger流示图
使用:
settings.py
""" Django settings for about_middleware 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 = \'s011rs!(ga_n!j#*1@!-c2is3)xaw()87bpj=ffjhel^$vzi5v\' # SECURITY WARNING: don\'t run with debug turned on in production! DEBUG = True # 真正上线 这是 false 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\', # 注册两个自定义的中间件 \'my_middleware.MD1\', \'my_middleware.MD2\', ] # 中间件 https://www.cnblogs.com/liwenzhou/p/8761803.html from django.middleware.security import SecurityMiddleware from django.middleware.csrf import CsrfViewMiddleware from django.middleware.clickjacking import XFrameOptionsMiddleware # process_request(self,request) # process_view(self, request, view_func, view_args, view_kwargs) # process_template_response(self,request,response) # process_exception(self, request, exception) # process_response(self, request, response) ROOT_URLCONF = \'about_middleware.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 = \'about_middleware.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\'), } } # 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/\' # https://www.cnblogs.com/liwenzhou/p/8763264.html # django 的日志配置项 BASE_LOG_DIR = os.path.join(BASE_DIR,\'log\') LOGGING = { \'version\': 1, # 保留字 \'disable_existing_loggers\': False, # 禁用已经存在的 logger 实例 \'formatters\': { # 详细的日志格式 \'standard\': { \'format\': \'[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]\' \'[%(levelname)s][%(message)s]\' }, # 简单的日志格式 \'simple\': { \'format\': \'[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s\' }, # 定义一个特殊的日志格式 \'collect\': { \'format\': \'%(message)s\' } }, # 过滤器 \'filters\': { # DEBUG = True 的情况 才过滤 \'require_debug_true\': { \'()\': \'django.utils.log.RequireDebugTrue\', }, }, # 处理器 \'handlers\': { # 在终端打印 \'console\': { \'level\': \'DEBUG\', \'filters\': [\'require_debug_true\'], # 只有在Django debug为True时才在屏幕打印日志 \'class\': \'logging.StreamHandler\', \'formatter\': \'simple\' }, # 默认 \'default\': { \'level\': \'INFO\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,自动切 \'filename\': os.path.join(BASE_LOG_DIR, "xxx_info.log"), # 日志文件 \'maxBytes\': 1024 * 1024 * 50, # 日志大小 50M 一般配500M \'backupCount\': 3, # 最多备份3个 \'formatter\': \'standard\', \'encoding\': \'utf-8\', }, # 专门用来记 错误日志 \'error\': { \'level\': \'ERROR\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,自动切 \'filename\': os.path.join(BASE_LOG_DIR, "xxx_err.log"), # 日志文件 \'maxBytes\': 1024 * 1024 * 50, # 日志大小 50M \'backupCount\': 5, \'formatter\': \'standard\', \'encoding\': \'utf-8\', }, # 专门 定义一个 收集特定信息的日志 \'collect\': { \'level\': \'INFO\', \'class\': \'logging.handlers.RotatingFileHandler\', # 保存到文件,自动切 \'filename\': os.path.join(BASE_LOG_DIR, "xxx_collect.log"), \'maxBytes\': 1024 * 1024 * 50, # 日志大小 50M \'backupCount\': 5, \'formatter\': \'collect\', \'encoding\': "utf-8" } }, \'loggers\': { # 默认的logger应用如下配置 \'\': { \'handlers\': [\'default\', \'console\', \'error\'], # 上线之后可以把\'console\'移除 \'level\': \'DEBUG\', \'propagate\': True, # 向不向更高级别的logger传递 }, # 名为 \'collect\'的logger还单独处理 \'collect\': { \'handlers\': [\'console\', \'collect\'], \'level\': \'INFO\', } }, }
views.py
from django.shortcuts import render,HttpResponse # Create your views here. import logging # 生成一个以当前文件名为名字的logger实例 logger = logging.getLogger(__name__) collect_logger = logging.getLogger(\'collect\') # 生成一个名为collect的实例 def index(requset): logger.debug(\'一个debug萌萌的请求...\') logger.info(\'一个info萌萌的请求...\') \'\'\' 这是视图函数index的doc信息 :param requset: :return: \'\'\' print(\'@\'*120) print(\'这是app01里面的index函数\') # print(requset.s9) # raise ValueError(\'hehe,抛异常\') # return HttpResponse(\'OK\') rep = HttpResponse(\'OK\') collect_logger.info(\'这是collect_logger日志\') collect_logger.info(\'hello:collect\') # def render(): # return HttpResponse(\'不常用\') # # rep.render = render return rep
二、静态文件配置
settings.py
STATIC_URL = \'/static/\' STATICFILES_DIRS = [ os.path.join(BASE_DIR,\'static\') ]
项目/static
/plugins/sweetalert # 插件
下载 dist css js 引入
https://github.com/lipis/bootstrap-sweetalert
https://lipis.github.io/bootstrap-sweetalert/
/bootstrap-3.3.7/css. fonts. js. # 下载
js ... # 下载
css ...
使用:
<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>
三、mysql配置
settings.py
DATABASES = { \'default\': { \'ENGINE\': \'django.db.backends.mysql\', \'NAME\': \'bms\', \'HOST\':\'127.0.0.1\', \'PORT\':3306, \'USER\':\'root\', \'PASSWORD\':\'123\', } }
在项目bms __init__ 下设置
import pymysql
pymysql.install_as_MySQLdb()python manage.py makemigrations
python manage.py migrate
四、ajax post (csrf-token)请求前配置
项目/static/init_ajax.js
// 从cooikie 取 csft token 的值 function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== \'\') { var cookies = document.cookie.split(\';\'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + \'=\')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie(\'csrftoken\'); // 将csrftoken 设置到ajax 请求头中,后续的ajax请求就会自动携带这个csrf token function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/init_ajax.js"></script>
五、事务
import os if __name__ == \'__main__\': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django django.setup() import datetime from app01 import models try: from django.db import transaction with transaction.atomic(): new_publisher = models.Publisher.objects.create(name="火星出版社") models.Book.objects.create(title="橘子物语", publish_date=datetime.date.today(), publisher_id=10) # 指定一个不存在的出版社id except Exception as e: print(str(e))
六、Django终端打印SQL语句
settings.py
LOGGING = { \'version\': 1, \'disable_existing_loggers\': False, \'handlers\': { \'console\':{ \'level\':\'DEBUG\', \'class\':\'logging.StreamHandler\', }, }, \'loggers\': { \'django.db.backends\': { \'handlers\': [\'console\'], \'propagate\': True, \'level\':\'DEBUG\', }, } }
七、在Python脚本中调用Django环境
项目/myscript.py
import os if __name__ == \'__main__\': os.environ.setdefault("DJANGO_SETTINGS_MODULE", "BMS.settings") import django django.setup() from app01 import models books = models.Book.objects.all() print(books)
测试数据,批量插入数据:
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)
八、自定义分页组件
项目/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">«</span></a></li>\') else: li.append(\'<li><a href="{0}?page={1}"><span aria-hidden="true">«</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">»</span></a></li>\') else: li.append(\'<li><a href="{0}?page={1}"><span aria-hidden="true">»</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)
views.py
def publisher_list(request): 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} )
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>
九、django分页组件(CBV)
re_path(r\'^book_list/\',views.BookList.as_view(),name="book_list"),
# 类视图 要调用as_view()
# 以ip和端口后面什么都没有,就能匹配上url
re_path(r\'^$\',views.publisher_list),
views.py
# 使用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,})
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>
十、django缓存 - redis
http://www.cnblogs.com/wupeiqi/articles/5246483.html
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
1、配置
a、开发调试
# 此为开始调试用,实际内部不做任何操作
# 配置:
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)
},
\'KEY_PREFIX\': \'\', # 缓存key的前缀(默认空)
\'VERSION\': 1, # 缓存key的版本(默认1)
\'KEY_FUNCTION\' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
}
}
# 自定义key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys.
Constructs the key used by all other methods. By default it prepends
the `key_prefix\'. KEY_FUNCTION can be used to specify an alternate
function 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_func
else:
return import_string(key_func)
return default_key_func
b、内存
# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.locmem.LocMemCache\',
\'LOCATION\': \'unique-snowflake\',
}
}
# 注:其他配置同开发调试版本
c、文件
# 此缓存将内容保存至文件
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.filebased.FileBasedCache\',
\'LOCATION\': \'/var/tmp/django_cache\',
}
}
# 注:其他配置同开发调试版本
d、数据库
# 此缓存将内容保存至数据库
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.db.DatabaseCache\',
\'LOCATION\': \'my_cache_table\', # 数据库表
}
}
# 注:执行创建表命令 python manage.py createcachetable
e、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\',
]
}
}
f、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\',
]
}
}
g. Redis缓存(依赖:pip3 install django-redis)
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}
# "PASSWORD": "密码",
}
}
}
from django_redis import get_redis_connection
conn = get_redis_connection("default")
2、应用
a. 全站使用
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
MIDDLEWARE = [
\'django.middleware.cache.UpdateCacheMiddleware\',
# 其他中间件...
\'django.middleware.cache.FetchFromCacheMiddleware\',
]
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = ""
CACHE_MIDDLEWARE_KEY_PREFIX = ""
b. 单独视图缓存
方式一:
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
方式二:
from django.views.decorators.cache import cache_page
urlpatterns = [
url(r\'^foo/([0-9]{1,2})/$\', cache_page(60 * 15)(my_view)),
]
c、局部视图使用
a. 引入TemplateTag
{% load cache %}
b. 使用缓存
{% cache 5000 缓存key %}
缓存内容
{% endcache %}
更多:猛击这里
django缓存配置
由于Django是动态网站,所有每次请求均会去数据进行相应的操作,当程序访问量大时,耗时必然会更加明显,最简单解决方式是使用:缓存,缓存将一个某个views的返回值保存至内存或者memcache中,5分钟内再有人来访问时,则不再去执行view中的操作,而是直接从内存或者Redis中之前缓存的内容拿到,并返回。
Django中提供了6种缓存方式:
- 开发调试
- 内存
- 文件
- 数据库
- Memcache缓存(python-memcached模块)
- Memcache缓存(pylibmc模块)
通用配置
\'TIMEOUT\': 300, # 缓存超时时间(默认300,None表示永不过期,0表示立即过期)
\'OPTIONS\':{
\'MAX_ENTRIES\': 300, # 最大缓存个数(默认300)
\'CULL_FREQUENCY\': 3, # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
},
\'KEY_PREFIX\': \'\', # 缓存key的前缀(默认空)
\'VERSION\': 1, # 缓存key的版本(默认1)
\'KEY_FUNCTION\' 函数名 # 生成key的函数(默认函数会生成为:【前缀:版本:key】)
以上六中模式都可以使用
自定义key
def default_key_func(key, key_prefix, version):
"""
Default function to generate keys.
Constructs the key used by all other methods. By default it prepends
the `key_prefix\'. KEY_FUNCTION can be used to specify an alternate
function 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_func
else:
return import_string(key_func)
return default_key_func
开发调试
# 此为开始调试用,实际内部不做任何操作
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.dummy.DummyCache\', # 引擎
通用配置
}
}
内存
# 此缓存将内容保存至内存的变量中
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.locmem.LocMemCache\',
\'LOCATION\': \'unique-snowflake\',
通用配置
}
}
# 注:其他配置同开发调试版本
文件
# 此缓存将内容保存至文件
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.filebased.FileBasedCache\',
\'LOCATION\': \'/var/tmp/django_cache\',
通用配置
}
}
# 注:其他配置同开发调试版本
数据库
# 此缓存将内容保存至数据库
# 配置:
CACHES = {
\'default\': {
\'BACKEND\': \'django.core.cache.backends.db.DatabaseCache\',
\'LOCATION\': \'my_cache_table\', # 数据库表
通用配置
}
}
# 注:执行创建表命令 python manage.py createcachetable
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\',
]
}
}
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\',
]
}
}
缓存的应用
单独视图缓存
from django.views.decorators.cache import cache_page
@cache_page(60 * 15)
def my_view(request):
...
即通过装饰器的方式实现,导入模块之后,在需要缓存的函数前加@cache_page(60 * 15) 60*15表示缓存时间是15分钟
例子如下:
from django.views.decorators.cache import cache_page
@cache_page(10)
def cache(request):
import time
ctime = time.time()
return render(request,"cache.html",{"ctime":ctime})
前端页面如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ ctime }}</h1>
<h1>{{ ctime }}</h1>
<h1>{{ ctime }}</h1>
</body>
</html>
这样在前端页面在获取的ctime的时候就会被缓存10秒钟,10秒钟之后才会变化,但是这样的话就相当月所有的调用ctime的地方都被缓存了
局部缓存
引入TemplateTag
{% load cache %}
使用缓存
{% cache 5000 缓存key %}
缓存内容
{% endcache %}
更改前端代码如下:
{% load cache %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>{{ ctime }}</h1>
<h1>{{ ctime }}</h1>
{% cache 10 c1 %}
<h1>{{ ctime }}</h1>
{% endcache %}
</body>
</html>
这样就实现了最后一个ctime缓存,其他两个不缓存
全站缓存
全站缓存的时候,需要在中间件的最上面添加:
\'django.middleware.cache.UpdateCacheMiddleware\',
在中间件的最下面添加:
\'django.middleware.cache.FetchFromCacheMiddleware\',
其中\'django.middleware.cache.UpdateCacheMiddleware\'里面只有process_response方法,在\'django.middleware.cache.FetchFromCacheMiddleware\'中只有process_request方法,所以最开始是直接跳过UpdateCacheMiddleware,然后从第一个到最后一个中间件的resquest,第一次没有缓存座椅匹配urls路由关系依次进过中间件的process_view,到达views函数,再经过process_exception最后经过response,到达FetchFromCacheMiddleware
使用中间件,经过一系列的认证等操作,如果内容在缓存中存在,则使用FetchFromCacheMiddleware获取内容并返回给用户,当返回给用户之前,判断缓存中是否已经存在,如果不存在则UpdateCacheMiddleware会将缓存保存至缓存,从而实现全站缓存
MIDDLEWARE = [
\'django.middleware.cache.UpdateCacheMiddleware\',#放到第一个中间件位置
# 其他中间件...
\'django.middleware.cache.FetchFromCacheMiddleware\',#放到最后一个
]
CACHE_MIDDLEWARE_ALIAS = ""
CACHE_MIDDLEWARE_SECONDS = "" # 可设置缓存时间 CACHE_MIDDLEWARE_KEY_PREFIX = ""