Django - 常用配置
一、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
=
""