一. Admin的配置
1.Admin基礎設置
admin是django強大功能之一,它能夠從數據庫中讀取數據,呈現在頁面中,進行管理。默認情況下,它的功能已經非常強大,如果你不需要復雜的功能,它已經夠用,但是有時候,一些特殊的功能還需要定制,比如搜索功能,下面這一系列文章就逐步深入介紹如何定制適合自己的admin應用。
<1> 在settings中設置Admin界面顯示語言
LANGUAGE_CODE = 'en-us' #LANGUAGE_CODE = 'zh-hans'
<2> 認識ModelAdmin,管理界面的定制類,如需擴展特定的model界面需從該類繼承。
<3>注冊model類到admin的兩種方式:
1) 使用register的方法
admin.site.register(Book,MyAdmin)
2) 使用register的裝飾器
@admin.register(Book)
<4>掌握一些常用的設置技巧
list_display:指定要顯示的字段
search_fields:指定搜索的字段
list_filter:指定列表過濾器
ordering:指定排序字段
list_per_page:設置每頁顯示多少條記錄,默認是100條
list_editable:設置默認可編輯字段
fk_fields: 設置顯示外鍵字段
date_hierarchy:按Admin自制表中的時間字段過濾


from django.contrib import admin from ORM_Study.models import * # Register your models here. # @admin.register(book)#----->單給某個表加一個定制 class MyAdmin(admin.ModelAdmin): list_display = ("title", "price","publish") search_fields = ("title","publish__name") list_filter = ("publish",) ordering = ("price",) list_per_page = 3 date_hierarchy ="date" admin.site.register(book,MyAdmin)
<5>Admin常用設置詳解
在admin.py中只需要講Mode中的某個類注冊,即可在Admin中實現增刪改查的功能,如:
admin.site.register(models.UserInfo)
但是,這種方式比較簡單,如果想要進行更多的定制操作,需要利用ModelAdmin進行操作,如:
方式一: class UserAdmin(admin.ModelAdmin): list_display = ('user', 'pwd',) admin.site.register(models.UserInfo, UserAdmin) # 第一個參數可以是列表 方式二: @admin.register(models.UserInfo) # 第一個參數可以是列表 class UserAdmin(admin.ModelAdmin): list_display = ('user', 'pwd',)
ModelAdmin中提供了大量的可定制功能,如
1. list_display,列表時,定制顯示的列。
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): list_display = ('user', 'pwd', 'xxxxx') def xxxxx(self, obj): return "xxxxx"
2. list_display_links,列表時,定制列可以點擊跳轉。
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): list_display = ('user', 'pwd', 'xxxxx') list_display_links = ('pwd',)
3. list_filter,列表時,定制右側快速篩選。
4. list_select_related,列表時,連表查詢是否自動select_related
5. list_editable,列表時,可以編輯的列
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): list_display = ('user', 'pwd','ug',) list_editable = ('ug',)
6. search_fields,列表時,模糊搜索的功能
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): search_fields = ('user', 'pwd')
7. date_hierarchy,列表時,對Date和DateTime類型進行搜索
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): date_hierarchy = 'ctime'
8 inlines,詳細頁面,如果有其他表和當前表做FK,那么詳細頁面可以進行動態增加和刪除
class UserInfoInline(admin.StackedInline): # TabularInline extra = 0 model = models.UserInfo class GroupAdminMode(admin.ModelAdmin): list_display = ('id', 'title',) inlines = [UserInfoInline, ]
9 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
10 定制HTML模板
add_form_template = None change_form_template = None change_list_template = None delete_confirmation_template = None delete_selected_confirmation_template = None object_history_template = None
11 raw_id_fields,詳細頁面,針對FK和M2M字段變成以Input框形式
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): raw_id_fields = ('FK字段', 'M2M字段',)
12 fields,詳細頁面時,顯示字段的字段
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): fields = ('user',)
13 exclude,詳細頁面時,排除的字段
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): exclude = ('user',)
14 readonly_fields,詳細頁面時,只讀字段
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): readonly_fields = ('user',)
15 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'), }), )
16 詳細頁面時,M2M顯示時,數據移動選擇(方向:上下和左右)
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)
17 ordering,列表時,數據排序規則
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): ordering = ('-id',) 或 def get_ordering(self, request): return ['-id', ]
18. radio_fields,詳細頁面時,使用radio顯示選項(FK默認使用select)
radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTAL
19 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
20 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 = "指定列數據為空時,默認顯示"
二. Cookie和Session
1.Cookie和Session的基本介紹
cookie不屬于http協議范圍,由于http協議無法保持狀態,但實際情況,我們卻又需要“保持狀態”,因此cookie就是在這樣一個場景下誕生。cookie的工作原理是:由服務器產生cookie內容,瀏覽器收到請求響應后保存在本地;當瀏覽器再次訪問該服務器時,瀏覽器會自動帶上cookie,這樣服務器就能通過cookie的內容來判斷這個是“誰”。簡明來說,基于http協議的無狀態特征,服務器根本就不知道訪問者是“誰”,那么上述的cookie就起到橋接的作用,我們可以給每個客戶端的cookie分配一個唯一的id,這樣用戶在訪問時,通過cookie,服務器就知道來的人是“誰”,然后我們再根據不同的cookie的id,在服務器上保存一段時間的私密資料,如“賬號密碼”等等。cookie雖然在一定程度上解決了“保持狀態”的需求,但是由于cookie本身最大支持4096字節,以及cookie本身保存在客戶端,可能被攔截或竊取,因此就需要有一種新的東西,它能支持更多的字節,并且他保存在服務器,有較高的安全性,這便出現了session。
cookie的格式:
Set-Cookie: NAME=VALUE;Expires/Max-age=DATE;Path=PATH;Domain=DOMAIN_NAME;SECURE
參數意義:
- NAME:cookie的名字。
- VALUE:cookie的值。
- Expires:cookie的過期時間。
- Path:cookie作用的路徑。
- Domain:cookie作用的域名。
- SECURE:是否只在https協議下起作用。
總結:cookie彌補了http無狀態的不足,讓服務器知道來的人是“誰”;但是cookie以文本的形式保存在本地,自身安全性較差;所以我們就通過cookie識別不同的用戶,對應的在session里保存私密的信息以及超過4096字節的文本。
經過前面的學習我們已經有能力制作一個登陸頁面,在驗證了用戶名和密碼的正確性后跳轉到后臺的頁面。但是測試后也發現,如果繞過登陸頁面,直接輸入后臺的url地址也可以直接訪問。這個顯然是不合理的。其實我們缺失的就是cookie和session配合的驗證。有了這個驗證過程,我們就可以實現和其他網站一樣必須登錄才能進入后臺頁面了。
先說一下這種認證的機制。每當我們使用一款瀏覽器訪問一個登陸頁面的時候,一旦我們通過了認證。服務器端就會發送一組隨機唯一的字符串(假設是123abc)到瀏覽器端,這個被存儲在瀏覽器端的東西就叫cookie。而服務器端也會自己存儲一下用戶當前的狀態,比如login=true,username=hahaha之類的用戶信息。但是這種存儲是以字典形式存儲的,字典的唯一key就是剛才發給用戶的唯一的cookie值。那么如果在服務器端查看session信息的話,理論上就會看到如下樣子的字典
{'123abc':{'login':true,'username:hahaha'}}
因為每個cookie都是唯一的,所以我們在電腦上換個瀏覽器再登陸同一個網站也需要再次驗證。那么為什么說我們只是理論上看到這樣子的字典呢?因為處于安全性的考慮,其實對于上面那個大字典不光key值123abc是被加密的,value值{'login':true,'username:hahaha'}在服務器端也是一樣被加密的。所以我們服務器上就算打開session信息看到的也是類似與以下樣子的東西{'123abc':dasdasdasd1231231da1231231}
借用一張別的大神畫的圖,可以更直觀的看出來cookie和session的關系
cookie和session的應用實例:
<1>先在templates目錄下創建兩個html,login.html負責登錄頁面,backend頁面代表后臺頁面


/*---------------------------login.html-----------------------------*/ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="container"> <form action="login.html" method="post"> <div class="form-group"> <label class="sr-only">username</label> <input type="text" class="form-control" name="username" placeholder="用戶名"/> </div> <div class="form-group"> <label class="sr-only">Password</label> <input type="password" class="form-control" name="passwd" placeholder="密碼"/> </div> <div class="form-group"> <input class="btn btn-primary" type="submit" value="提交"> </div> </form> </div> </body> </html> /*---------------------------backend.html-----------------------*/ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div class="container"> <h2>cookie 內容是 {{ cookie_content }}</h2> <h2>session 內容是 {{ session_content }}</h2> <h2>登錄用戶名 :{{ username }}</h2> </div> </body> </html>
<2> 在應用下的views.py文件,編寫代碼邏輯部分


def login(request): print("COOKIES", request.COOKIES) print("SESSION", request.session) #------------首次進入login.html頁面cookies和session打印內容 #COOKIES {'csrftoken': 'x8OVNJyVE7SMVgPXTLSoJiNNr6KSTG7CyOwXHoKhBKsFwlCyCXh3UVfHExheoA0g', 'sessionid': '9s3jx5sb5euzdla2d1aq44yrehvun1e2'} #SESSION <django.contrib.sessions.backends.db.SessionStore object at 0x00000213ADA15DA0> if request.method == "POST": username = request.POST['username'] pwd = request.POST['passwd'] print('================================') if username == 'abc' and pwd == '123': #----------------cookie單獨使用--------------------- #cookie單獨使用時,設置cookiea內部字典的內容 # ret=redirect('/backend/') # ret.set_cookie("username",username) # return ret #----------cookie和sessions結合使用----------------- # 設置session內部的字典內容 request.session['is_login'] = 'true' request.session['username'] = 'abc' #登錄成功就將url重定向到后臺的url return redirect('/backend/') # 登錄不成功或第一訪問就停留在登錄頁面 return render(request,'login.html') def backend(request): print("COOKIES", request.COOKIES) print("SESSION", request.session) #-----------------------cookie單獨使用------------------ # if request.COOKIES.get("username", None): # username = request.COOKIES.get("username", None) # cookie_content = request.COOKIES # return render(request, "backend.html", locals()) # #返回值: # # cookie內容是{'username': 'abc'} # # session 內容是 # # 登錄用戶名 :abc #-----------------cookie和session結合使用----------------- """ 這里必須用讀取字典的get()方法把is_login的value缺省設置為False, 當用戶訪問backend這個url先嘗試獲取這個瀏覽器對應的session中的 is_login的值。如果對方登錄成功的話,在login里就已經把is_login 的值修改為了True,反之這個值就是False的 """ is_login = request.session.get('is_login', False) # 如果為真,就說明用戶是正常登陸的 if is_login: # 獲取字典的內容并傳入頁面文件 # 或者用if request.session.get("is_login",None): cookie_content = request.COOKIES session_content = request.session username = request.session['username'] return render(request, 'backend.html', { 'cookie_content': cookie_content, 'session_content': session_content, 'username': username }) #返回的值: # cookie 內容是 {'csrftoken': 'x8OVNJyVE7SMVgPXTLSoJiNNr6KSTG7CyOwXHoKhBKsFwlCyCXh3UVfHExheoA0g', 'sessionid': '9s3jx5sb5euzdla2d1aq44yrehvun1e2'} # session內容是 < django.contrib.sessions.backends.db.SessionStore object at 0x000001BF7D04DDD8 > # 登錄用戶名 :abc else: """ 如果訪問的時候沒有攜帶正確的session, 就直接被重定向url回login頁面 """ return redirect('/login/')
<3>編輯urls.py文件,設置函數與頁面的綁定關系


from django.contrib import admin from django.urls import path from ORM_Study import views from django.conf.urls import url urlpatterns = [ #path('admin/', admin.site.urls), url('^login/',views.login,name='login'), url('^backend/',views.backend,name='backend'), ]
<4>最后打開瀏覽器直接訪問/backend/頁面,檢測是否直接就被重定向到了/login/頁面
<5>總結
從上述步驟中我們看到有一下幾點:
(1)login頁面正確登錄的話,后臺頁面可以獲取到瀏覽器攜帶的cookie的。
(2)返回的sessionid其實就是cookie值
(3)session的內容是加密的,從客戶端獲取不到session的內容
(4)服務端可以通過預設的key值取出session的內容并打印到前段
(5)django的session默認是存儲在數據庫里的,我們可以到數據庫查看一下真正session內容,在表Django_session里
(6)session的好處:客戶端只有cookie值,始終沒有用戶信息
(7)session依賴于cookie,cookie保存在瀏覽器,session保存在服務器端。
<6>cookie和session的知識點總結:
操作cookie:


獲取cookie:request.COOKIES[key]
設置cookie:response.set_cookie(key,value)
操作session(session默認在服務器端保存15天):


獲取session:request.session[key] 設置session:reqeust.session[key] = value 刪除session:del request.session[key] 設置session時效: request.session.set_expiry(value) * 如果value是個整數,session會在這些秒數后失效。 * 如果value是個datatime或timedelta,session就會在這個時間后失效。 * 如果value是0,用戶關閉瀏覽器session就會失效。 * 如果value是None,session會依賴全局session失效策略。
>>>>>>>>>待續