Django - 經常使用配置

1、logging配置

Django項目經常使用的logging配置javascript

settings.pycss

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流示圖html

使用:前端

settings.pyjava

"""
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',
        }
    },
}
settings

views.pypython

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
views

2、靜態文件配置

settings.pymysql

STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR,'static')
]

項目/staticjquery

    /plugins/sweetalert    # 插件     git

 下載 dist css js 引入 github

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> 

3、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

4、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>

5、事務

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))

6、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',
        },
    }
}

7、在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)

8、自定義分頁組件

項目/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">&laquo;</span></a></li>')
        else:
            li.append('<li><a href="{0}?page={1}"><span aria-hidden="true">&laquo;</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">&raquo;</span></a></li>')
        else:
            li.append('<li><a href="{0}?page={1}"><span aria-hidden="true">&raquo;</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>

9、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>

 

10、django緩存 - redis

http://www.cnblogs.com/wupeiqi/articles/5246483.html

因爲Django是動態網站,全部每次請求均會去數據進行相應的操做,當程序訪問量大時,耗時必然會更加明顯,最簡單解決方式是使用:緩存,緩存將一個某個views的返回值保存至內存或者memcache中,5分鐘內再有人來訪問時,則再也不去執行view中的操做,而是直接從內存或者Redis中以前緩存的內容拿到,並返回。

Django中提供了6種緩存方式:

  • 開發調試
  • 內存
  • 文件
  • 數據庫
  • Memcache緩存(python-memcached模塊)
  • Memcache緩存(pylibmc模塊)

一、配置

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")

二、應用

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 = ""
相關文章
相關標籤/搜索