django之中間件、緩存、信號、admin內置後臺

django之中間件、緩存、信號、admin內置後臺

目錄:html

  • 中間件
  • 緩存
  • 信號
  • admin後臺

1、中間件

一、什麼是中間件?python

  • 中間件是一個、一個的管道,若是相對任何全部的經過Django的請求進行管理都須要自定義中間件數據庫

  • 中間件能夠對進來的請求和出去的請求進行控制django

  • 中間件是一類。緩存

由上圖可知,中間件是位於wsgi和路由系統中間的環節。用戶請求和和迴應請求都會通過中間件。session

看下面的代碼在settings裏中間件的類:app

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

  

當有請求過來的時候,默認從上倒下執行!而後在返回的時候從下面在返回回去框架

二、自定義中間件ide

中間件中能夠定義四個方法,分別是:memcached

  • process_request(self,request)
  • process_view(self, request, callback, callback_args, callback_kwargs)
  • process_exception(self, request, exception) 這個方法只有在出現錯誤的時候纔會觸發
  • process_response(self, request, response)
  • process_template_response(self,request,response) 這個方法只有在返回對象中有render方法的時候才執行,如render_to_response('/index/')

以上方法的返回值能夠是None和HttpResonse對象,若是是None,則繼續按照django定義的規則向下執行,若是是HttpResonse對象,則直接將該對象返回給用戶。

  • 建立中間件腳本

在django的的project目錄下建立一個middleware目錄,並建立一個md.py的腳本,內容以下:

class Testmiddle:
    def process_request(self,request):
        print 'Testmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Testmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Testmiddle process_response'
        return response
    
class Nextmiddle:
    def process_request(self,request):
        print 'Nextmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Nextmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Nextmiddle process_response'
        return response

  

  • 註冊中間件

修改settings.py文件,在MIDDLEWARE_CLASSES中添加咱們建立的中間件

MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'middleware.middle.Testmiddle',
    'middleware.middle.Nextmiddle',
]

  

  • 設置url 略
  • 測試:
  • 1 Testmiddle process_request
    2 Nextmiddle process_request
    3 Testmiddle process_view
    4 Nextmiddle process_view
    5 This app01 Views.index
    6 Nextmiddle process_response
    7 Testmiddle process_response
    

      

從輸出結果能夠看出:

他是先執行Testmiddle 的request 方法又執行了Nextmiddle的 process_request方法, 而後在執行Testmiddle的view方法,Nextmiddle的view方法

注意:django版本1.10之後,會報以下錯誤:

解決以下:

from django.utils.deprecation import MiddlewareMixin
class Testmiddle(MiddlewareMixin):
    def process_request(self,request):
        print 'Testmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Testmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Testmiddle process_response'
        return response
    
class Nextmiddle(MiddlewareMixin):
    def process_request(self,request):
        print 'Nextmiddle process_request'
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print 'Nextmiddle process_view'
    def process_exception(self, request, exception):
        pass
    def process_response(self, request, response):
        print 'Nextmiddle process_response'
        return response

  

注意:
* 老版本中在中間件中若是某個中間件類的方法返回的不是none,則後面的中間件不會再處理請求,也不會到達路由系統,而是直接到第一個process_response,開始全部的process_response處理
* 新版本中在中間件中若是某個中間件類的方法返回的不是none,則後面的中間件不會再處理請求,也不會到達路由系統,而是直接到最後一個process_response處理,而後返回給客戶端

2、緩存

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

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

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

一、開發調試

# 此爲開始調試用,實際內部不作任何操做
    # 配置:
        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

二、內存

# 此緩存將內容保存至內存的變量中
    # 配置:
        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

五、Memcach緩存(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',
            ]
        }
    }

七、應用方式:

  • 全站使用
使用中間件,通過一系列的認證等操做,若是內容在緩存中存在,則使用FetchFromCacheMiddleware獲取內容並返回給用戶,當返回給用戶以前,判斷緩存中是否已經存在,若是不存在則UpdateCacheMiddleware會將緩存保存至緩存,從而實現全站緩存
MIDDLEWARE = [
        'django.middleware.cache.UpdateCacheMiddleware',
        # 其餘中間件...
        'django.middleware.cache.FetchFromCacheMiddleware',
    ]

    CACHE_MIDDLEWARE_ALIAS = ""
    CACHE_MIDDLEWARE_SECONDS = ""
    CACHE_MIDDLEWARE_KEY_PREFIX = ""
  • 單獨視圖緩存
方式一:
        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)),
        ]
  • 局部視圖緩存
a. 引入TemplateTag

        {% load cache %}

b. 使用緩存

        {% cache 5000 緩存key %}
            緩存內容
        {% endcache %}

  

參考L:https://docs.djangoproject.com/en/1.9/topics/cache/

3、信號

Django中提供了「信號調度」,用於在框架執行操做時解耦。通俗來說,就是一些動做發生的時候,信號容許特定的發送者去提醒一些接受者。

一、django內置信號

1 Model signals
 2     pre_init                    # django的modal執行其構造方法前,自動觸發
 3     post_init                   # django的modal執行其構造方法後,自動觸發
 4     pre_save                    # django的modal對象保存前,自動觸發
 5     post_save                   # django的modal對象保存後,自動觸發
 6     pre_delete                  # django的modal對象刪除前,自動觸發
 7     post_delete                 # django的modal對象刪除後,自動觸發
 8     m2m_changed                 # django的modal中使用m2m字段操做第三張表(add,remove,clear)先後,自動觸發
 9     class_prepared              # 程序啓動時,檢測已註冊的app中modal類,對於每個類,自動觸發
10 Management signals
11     pre_migrate                 # 執行migrate命令前,自動觸發
12     post_migrate                # 執行migrate命令後,自動觸發
13 Request/response signals
14     request_started             # 請求到來前,自動觸發
15     request_finished            # 請求結束後,自動觸發
16     got_request_exception       # 請求異常後,自動觸發
17 Test signals
18     setting_changed             # 使用test測試修改配置文件時,自動觸發
19     template_rendered           # 使用test測試渲染模板時,自動觸發
20 Database Wrappers
21     connection_created          # 建立數據庫鏈接時,自動觸發

二、對於Django內置的信號,僅需註冊指定信號,當程序執行相應操做時,自動觸發註冊函數:

1 from django.core.signals import request_finished
 2 from django.core.signals import request_started
 3 from django.core.signals import got_request_exception
 4 
 5 from django.db.models.signals import class_prepared
 6 from django.db.models.signals import pre_init, post_init
 7 from django.db.models.signals import pre_save, post_save
 8 from django.db.models.signals import pre_delete, post_delete
 9 from django.db.models.signals import m2m_changed
10 from django.db.models.signals import pre_migrate, post_migrate
11 
12 from django.test.signals import setting_changed
13 from django.test.signals import template_rendered
14 
15 from django.db.backends.signals import connection_created
16 
17 
18 def callback(sender, **kwargs):
19     print("xxoo_callback")
20     print(sender,kwargs)
21 
22     xxoo.connect(callback)
23     # xxoo指上述導入的內容
24 from django.core.signals import request_finished
25 from django.dispatch import receiver
26 
27 @receiver(request_finished)
28 def my_callback(sender, **kwargs):
29     print("Request finished!") 

三、django自定義信號

  • 定義信號
1 import django.dispatch
2 pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"]
  • 註冊信號
1 def callback(sender, **kwargs):
2     print("callback")
3     print(sender,kwargs)
4  
5 pizza_done.connect(callback)
  • 觸發信號
1 from 路徑 import pizza_done
  
2 pizza_done.send(sender='seven',toppings=123, size=456)

  

因爲內置信號的觸發者已經集成到Django中,因此其會自動調用,而對於自定義信號則須要開發者在任意位置觸發。

參考L:https://docs.djangoproject.com/en/dev/topics/signals/

4、admin後臺

一、admin簡介:

Django內置的Admin是對於model中對應的數據表進行增刪改查提供的組件,使用方式有:

依賴APP:
        django.contrib.auth
        django.contrib.contenttypes
        django.contrib.messages
        django.contrib.sessions

    模板的context_processors:
        django.contrib.auth.context_processors.auth
        django.contrib.messages.context_processors.messages

    中間件:
        django.contrib.auth.middleware.AuthenticationMiddleware 
        django.contrib.messages.middleware.MessageMiddleware
二、配置路由:
urlpatterns  =  [
         url(r '^admin/' , admin.site.urls),
     ]
三、當前配置的路由能夠建立一些路由映射關係:

/admin/
/admin/login/
/admin/logout/
/admin/password_change/
/admin/password_change/done/

/admin/app名稱/model名稱/
/admin/app名稱/model名稱/add/
/admin/app名稱/model名稱/ID值/history/
/admin/app名稱/model名稱/ID值/change/
/admin/app名稱/model名稱/ID值/delete/

四、定製Admin

在admin.py中只須要講Mode中的某個類註冊,便可在Admin中實現增刪改查的功能,如:

admin.site.register(models.UserInfo)

可是,這種方式比較簡單,若是想要進行更多的定製操做,須要利用ModelAdmin進行操做,如:

 1 方式一:
 2     class UserAdmin(admin.ModelAdmin):
 3         list_display = ('user', 'pwd',)
 4  
 5     admin.site.register(models.UserInfo, UserAdmin) # 第一個參數能夠是列表
 6      
 7  
 8 方式二:
 9     @admin.register(models.UserInfo)                # 第一個參數能夠是列表
10     class UserAdmin(admin.ModelAdmin):
11         list_display = ('user', 'pwd',)

ModelAdmin中提供了大量的可定製功能,如

  • list_display,列表時,定製顯示的列。
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     list_display = ('user', 'pwd', 'xxxxx')
4  
5     def xxxxx(self, obj):
6         return "xxxxx"
  • list_display_links,列表時,定製列能夠點擊跳轉。
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     list_display = ('user', 'pwd', 'xxxxx')
4     list_display_links = ('pwd',)
  • list_filter,列表時,定製右側快速篩選。
from django.utils.translation import ugettext_lazy as _
 
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    list_display = ('user', 'pwd')
 
    class Ugg(admin.SimpleListFilter):
        title = _('decade born')
        parameter_name = 'xxxxxx'
 
        def lookups(self, request, model_admin):
            """
            顯示篩選選項
            :param request:
            :param model_admin:
            :return:
            """
            return models.UserGroup.objects.values_list('id', 'title')
 
        def queryset(self, request, queryset):
            """
            點擊查詢時,進行篩選
            :param request:
            :param queryset:
            :return:
            """
            v = self.value()
            return queryset.filter(ug=v)
 
    list_filter = ('user',Ugg,)
  • list_select_related,列表時,連表查詢是否自動select_related
  • 分頁相關
# 分頁,每頁顯示條數
    list_per_page = 100
 
# 分頁,顯示所有(真實數據<該值時,纔會有顯示所有)
    list_max_show_all = 200
 
# 分頁插件
    paginator = Paginator
  •  list_editable,列表時,能夠編輯的列
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     list_display = ('user', 'pwd','ug',)
4     list_editable = ('ug',)
  • search_fields,列表時,模糊搜索的功能
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3      
4     search_fields = ('user', 'pwd')
  • date_hierarchy,列表時,對Date和DateTime類型進行搜索
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3  
4     date_hierarchy = 'ctime'
  • preserve_filters,詳細頁面,刪除、修改,更新後跳轉回列表後,是否保留原搜索條件
  • ave_as = False,詳細頁面,按鈕爲「Sava as new」 或 「Sava and add another」
  • save_as_continue = True,點擊保存並繼續編輯
1 save_as_continue = True
2  
3 # 若是 save_as=True,save_as_continue = True, 點擊Sava as new 按鈕後繼續編輯。
4 # 若是 save_as=True,save_as_continue = False,點擊Sava as new 按鈕後返回列表。
5  
6 New in Django 1.10.
  • save_on_top = False,詳細頁面,在頁面上方是否也顯示保存刪除等按鈕
  • inlines,詳細頁面,若是有其餘表和當前表作FK,那麼詳細頁面能夠進行動態增長和刪除
class UserInfoInline(admin.StackedInline): # TabularInline
    extra = 0
    model = models.UserInfo
 
 
class GroupAdminMode(admin.ModelAdmin):
    list_display = ('id', 'title',)
    inlines = [UserInfoInline, ]
  • action,列表時,定製action中的操做
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
 
    # 定製Action行爲具體方法
    def func(self, request, queryset):
        print(self, request, queryset)
        print(request.POST.getlist('_selected_action'))
 
    func.short_description = "中文顯示自定義Actions"
    actions = [func, ]
 
    # Action選項都是在頁面上方顯示
    actions_on_top = True
    # Action選項都是在頁面下方顯示
    actions_on_bottom = False
 
    # 是否顯示選擇個數
    actions_selection_counter = True
  • 定製HTML模板
1 add_form_template = None
2 change_form_template = None
3 change_list_template = None
4 delete_confirmation_template = None
5 delete_selected_confirmation_template = None
6 object_history_template = None
  • raw_id_fields,詳細頁面,針對FK和M2M字段變成以Input框形式
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     raw_id_fields = ('FK字段', 'M2M字段',)
  • fields,詳細頁面時,顯示字段的字段
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     fields = ('user',)
  • exclude,詳細頁面時,排除的字段
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     exclude = ('user',)
  • readonly_fields,詳細頁面時,只讀字段
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     readonly_fields = ('user',)
  • fieldsets,詳細頁面時,使用fieldsets標籤對數據進行分割顯示
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    fieldsets = (
        ('基本數據', {
            'fields': ('user', 'pwd', 'ctime',)
        }),
        ('其餘', {
            'classes': ('collapse', 'wide', 'extrapretty'),  # 'collapse','wide', 'extrapretty'
            'fields': ('user', 'pwd'),
        }),
    )
  • 詳細頁面時,M2M顯示時,數據移動選擇(方向:上下和左右)
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)
  • ordering,列表時,數據排序規則
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     ordering = ('-id',)
4     或
5     def get_ordering(self, request):
6         return ['-id', ]
  • view_on_site,編輯時,是否在頁面上顯示view on set
1 view_on_site = False
2 或
3 def view_on_site(self, obj):
4     return 'https://www.baidu.com'
  • radio_fields,詳細頁面時,使用radio顯示選項(FK默認使用select)
1 radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTAL
  • show_full_result_count = True,列表時,模糊搜索後面顯示的數據個數樣式
 1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3     # show_full_result_count = True # 1 result (12 total)
4     # show_full_result_count = False  # 1 result (Show all)
5     search_fields = ('user',)
  • formfield_overrides = {},詳細頁面時,指定現實插件
from django.forms import widgets
from django.utils.html import format_html
 
class MyTextarea(widgets.Widget):
    def __init__(self, attrs=None):
        # Use slightly better defaults than HTML's 20x2 box
        default_attrs = {'cols': '40', 'rows': '10'}
        if attrs:
            default_attrs.update(attrs)
        super(MyTextarea, self).__init__(default_attrs)
 
    def render(self, name, value, attrs=None):
        if value is None:
            value = ''
        final_attrs = self.build_attrs(attrs, name=name)
        return format_html('<textarea {}>\r\n{}</textarea>',final_attrs, value)
 
 
 
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
 
    formfield_overrides = {
        models.models.CharField: {'widget': MyTextarea},
    }
  • prepopulated_fields = {},添加頁面,當在某字段填入值後,自動會將值填充到指定字段。
1 @admin.register(models.UserInfo)
2 class UserAdmin(admin.ModelAdmin):
3  
4     prepopulated_fields = {"email": ("user","pwd",)} 

PS: DjangoAdmin中使用js實現功能,頁面email字段的值會在輸入:user、pwd時自動填充

  • form = ModelForm,用於定製用戶請求時候表單驗證
from app01 import models
from django.forms import ModelForm
from django.forms import fields
 
 
class MyForm(ModelForm):
    others = fields.CharField()
 
    class Meta:
        model = models = models.UserInfo
        fields = "__all__"
 
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
 
    form = MyForm
  • empty_value_display = "列數據爲空時,顯示默認值"
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
    empty_value_display = "列數據爲空時,默認顯示"
 
    list_display = ('user','pwd','up')
 
    def up(self,obj):
        return obj.user
    up.empty_value_display = "指定列數據爲空時,默認顯示"
相關文章
相關標籤/搜索