Sansa组件
訴求
仿照admin組件,實(shí)現(xiàn)對(duì)表的URL分配管理。
實(shí)現(xiàn)思路
1.在settings.py文件中注冊(cè)APP,注冊(cè)示例為:
'app01.apps.App01Config', 'app02.apps.App02Config', ‘stark_demo.apps.StarkDemoConfig',2. 在每一個(gè)APP中的apps.py 文件中添加
1 from django.apps import AppConfig 2 from django.utils.module_loading import autodiscover_modules 3 4 class App01Config(AppConfig): 5 name = 'app01' 6 7 def ready(self): 8 autodiscover_modules('stark',)實(shí)現(xiàn)在Django項(xiàng)目啟動(dòng)時(shí),掃描每個(gè)APP項(xiàng)目下的stark.py文件的文件,執(zhí)行其中的代碼,注冊(cè)每個(gè)APP下的model,為每一個(gè)model生成增刪改查四條URL。
來(lái)一張流程圖進(jìn)行說(shuō)明。
Starksite類(lèi)和Modelstark類(lèi)的創(chuàng)建
1 from django.conf.urls import url 2 from django.shortcuts import HttpResponse, render, reverse,redirect 3 from django.utils.safestring import mark_safe 4 from django.forms import ModelForm 5 from app01.models import * 6 from app02.models import * 7 8 # 針對(duì)使用stark組件的默認(rèn)樣式類(lèi) 9 10 11 class Modelstark(object): 12 list_display = ["__str__"] 13 list_display_link = ["__str__"] 14 model_form = None 15 # init 方法在實(shí)例化類(lèi)的時(shí)候執(zhí)行 16 17 def __init__(self, model, site): 18 self.model = model 19 self.site = site 20 self.label_model = (self.model._meta.app_label, self.model._meta.model_name) 21 ''' 22 功能: 23 將顯示、編輯、刪除、增加頁(yè)面的url 封裝到函數(shù)中。 24 函數(shù)名: 25 def get_add_url(self) 26 def get_del_url(self,obj) 27 def get_edit_url(self,obj) 28 def get_list_url(self) 29 ''' 30 def get_add_url(self): 31 add_url = reverse("%s_%s_add" % self.label_model, ) 32 return add_url 33 34 def get_del_url(self,obj): 35 del_url = reverse("%s_%s_del" % self.label_model, args=(obj.pk,)) 36 return del_url 37 38 def get_edit_url(self,obj): 39 edit_url = reverse("%s_%s_edit"% self.label_model,args=(obj.pk,)) 40 return edit_url 41 42 def get_list_url(self): 43 list_url = reverse("%s_%s_show"%self.label_model,) 44 return list_url 45 ''' 46 功能: 47 為顯示頁(yè)面右側(cè)的添加按鈕生成動(dòng)態(tài)的URL 48 函數(shù)名: 49 def add_btn(self,obj=None,header=False) 50 ''' 51 def add_btn(self,obj=None,header=False): 52 if header: 53 pass 54 return mark_safe("<a href='%s' type='button' class='btn btn-success btn-lg pull-right'>添加</a>"%self.get_add_url()) 55 ''' 56 功能: 57 為顯示頁(yè)面生成編輯、刪除和復(fù)選框的標(biāo)簽 58 函數(shù)名: 59 def edit(self,obj=None,header=False) 60 def delete(self,obj=None,header=False) 61 def checkbox(self,obj=None,header=False) 62 ''' 63 def edit(self,obj=None,header=False): 64 if header: 65 return "操作" 66 return mark_safe("<a href='%s''>編輯</a>"%self.get_edit_url(obj)) 67 68 def delete(self,obj=None,header=False): 69 if header: 70 return "操作" 71 return mark_safe("<a href='%s''>刪除</a>" %self.get_del_url(obj)) 72 73 def checkbox(self,obj=None,header=False): 74 if header: 75 return mark_safe("<input type='checkbox' id='action-toggle'>") 76 pass 77 78 return mark_safe("<input type='checkbox' value='%s'>"%obj.pk) 79 80 pass 81 ''' 82 功能: 83 為每一個(gè)類(lèi)生成modelform,用于渲染標(biāo)簽 84 判斷用戶(hù)是否定義了model_form,如果定義了則用用戶(hù)自己的類(lèi),沒(méi)有則用默認(rèn)的modelForm 85 備注: 86 顯示中文錯(cuò)誤提示信息的解決思想是: 87 在樣式類(lèi)中定義一個(gè) model_form = None 的靜態(tài)變量,在 def default_modelform(self) 函數(shù)中判斷 model_form = None的bool值,若為False, 88 則表明用戶(hù)沒(méi)有自定義 model_form ,因此走默認(rèn)的modelForm. 89 若model_form 為T(mén)rue,則表明用戶(hù)對(duì)要注冊(cè)的表定義了modelForm,因此用戶(hù)會(huì)在自己的 XXXConfig類(lèi)中聲明 model_form = 自定義的modelForm, 90 此時(shí)用用戶(hù)自定義的 modelForm 91 函數(shù)名: 92 def mdelform(self) 93 ''' 94 def default_modelform(self): 95 class modelForm(ModelForm): 96 class Meta: 97 model = self.model 98 fields = "__all__" 99 if not self.model_form: 100 return modelForm 101 else: 102 return self.model_form 103 ''' 104 功能: 105 顯示、編輯、增加、刪除4個(gè)視圖函數(shù) 106 函數(shù)名: 107 def show_list(self, request) 108 def add_list(self, request) 109 def edit_list(self, request,id) 110 def del_list(self, request,id) 111 ''' 112 def show_list(self, request): 113 data_list = self.model.objects.all() 114 # 顯示表頭名稱(chēng) 115 header_list = [] 116 for i in self.real_list_display(): 117 if callable(i): 118 # 獲取函數(shù)名:函數(shù)名.__name__ 119 # header_list.append(i.__name__) -----> low版 120 header_list.append(i(self, header=True)) 121 else: 122 if i == "__str__": 123 header_list.append(self.model._meta.model_name.upper()) 124 else: 125 header_list.append(self.model._meta.get_field(i).verbose_name) 126 127 # print(self.list_display) 128 # 首先循環(huán)每一條記錄 129 """ 130 需要構(gòu)建的樣式為: 131 [ 132 ["id1","name1"], 133 ["id2","name2"], 134 ["id3","name3"], 135 ] 136 """ 137 # 顯示數(shù)據(jù) 138 ret_data_list = [] 139 for obj in data_list: 140 tmp_list = [] 141 # 遍歷顯示的字段,i 指的是字段名稱(chēng) 142 for i in self.real_list_display(): 143 if callable(i): 144 val = i(self, obj) 145 else: 146 # val 為反射后的value 147 val = getattr(obj, i) 148 # 判斷當(dāng)前的 字段名稱(chēng) 是否在 list_display_link 中,在的話(huà)讓該字段對(duì)應(yīng)的值作為a標(biāo)簽 149 if i in self.list_display_link: 150 val = mark_safe("<a href='%s'>%s</a>"%(self.get_edit_url(obj),val)) 151 tmp_list.append(val) 152 ret_data_list.append(tmp_list) 153 # 顯示添加按鈕 154 btn_list = [] 155 # 使用類(lèi).函數(shù) 的方式需要傳self,但是使用類(lèi)的對(duì)象.方法的方式不需要傳self 156 val = Modelstark.add_btn(self) 157 btn_list.append(val) 158 159 return render(request, "show_list.html", locals()) 160 161 def add_list(self, request): 162 modelForm = self.default_modelform() 163 errors = {} 164 if request.method == "POST": 165 form = modelForm(request.POST) 166 if form.is_valid(): 167 form.save() 168 return redirect(self.get_list_url()) 169 else: 170 return render(request,"add.html",locals()) 171 form = modelForm() 172 return render(request,"add.html",locals()) 173 174 def edit_list(self, request,id): 175 obj = self.model.objects.filter(id=id).first() 176 modelForm = self.default_modelform() 177 if request.method == "POST": 178 form = modelForm(request.POST,instance=obj) 179 if form.is_valid(): 180 form.save() 181 return redirect(self.get_list_url()) 182 else: 183 pass 184 form = modelForm(instance=obj) 185 return render(request,"edit.html",locals()) 186 187 def del_list(self, request,id): 188 if request.method == "POST": 189 self.model.objects.filter(id=id).delete() 190 return redirect(self.get_list_url()) 191 list_url = self.get_list_url() 192 return render(request,"delete.html",locals()) 193 ''' 194 功能: 195 在顯示頁(yè)面要真正顯示的字段,對(duì)list_display進(jìn)行擴(kuò)展 196 函數(shù)名: 197 def real_list_display(self) 198 ''' 199 def real_list_display(self): 200 new_list_display = [] 201 new_list_display.extend(self.list_display) 202 new_list_display.append(Modelstark.edit) 203 new_list_display.append(Modelstark.delete) 204 new_list_display.insert(0,Modelstark.checkbox) 205 return new_list_display 206 ''' 207 功能: 208 為沒(méi)一個(gè)注冊(cè)的model生成增刪改查四條URL 209 函數(shù)名: 210 def get_url_func(self) 211 ''' 212 def get_url_func(self): 213 tmp = [] 214 app_name = self.model._meta.app_label 215 model_name = self.model._meta.model_name 216 ret = (app_name, model_name) 217 tmp.append(url("^$", self.show_list, name="%s_%s_show" %ret)) 218 tmp.append(url("^add/$", self.add_list, name="%s_%s_add" %ret)) 219 tmp.append(url("^edit/(\d+)/$", self.edit_list, name="%s_%s_edit" %ret)) 220 tmp.append(url("^del/(\d+)/$", self.del_list, name="%s_%s_del" %ret)) 221 ''' 222 在訪問(wèn)URL之前就已經(jīng)分別為每張表創(chuàng)建了4條URL 223 ''' 224 return tmp 225 226 227 # 創(chuàng)建stark類(lèi),實(shí)例化Starksite,用于注冊(cè)model 228 229 230 231 class Starksite(object): 232 233 def __init__(self): 234 # 保存表的注冊(cè)信息,保存的格式為:以model類(lèi)為鍵,以該model實(shí)例化樣式對(duì)象為值 235 self._registry = {} 236 237 # 類(lèi)的注冊(cè)函數(shù) 238 def register(self, model, modelconfig=None): 239 ''' 240 實(shí)現(xiàn)model的注冊(cè) 241 :param model: 要注冊(cè)的類(lèi) 242 :param modelconfig: 該注冊(cè)類(lèi)的樣式對(duì)象 243 :return: None 244 ''' 245 246 ''' 247 判斷用戶(hù)是否自己定義了樣式類(lèi),如果沒(méi)有,此時(shí)的modelconfig為None,則用默認(rèn)的ModelStark樣式類(lèi)進(jìn)行實(shí)例化注冊(cè); 248 若用戶(hù)自定義了注冊(cè)類(lèi)的樣式對(duì)象,則使用用于自定的樣式對(duì)象 249 ''' 250 if not modelconfig: 251 modelconfig = Modelstark 252 # model是每次循環(huán)注冊(cè)的表,self是實(shí)例化的Startksite類(lèi)的實(shí)例化對(duì)象 253 ''' 254 在對(duì)注冊(cè)的model進(jìn)行樣式實(shí)例化的時(shí)候,modelconfig類(lèi)實(shí)際上是Modelstark類(lèi)的實(shí)例化,實(shí)例化要執(zhí)行類(lèi)的__init__函數(shù),init函數(shù)的定義為: 255 def __init__(self, model, site): 256 self.model = model 257 self.site = site 258 self.label_model = (self.model._meta.app_label, self.model._meta.model_name) 259 此時(shí)實(shí)例化的方式為:類(lèi)名.__init__() 方式,因此需要傳self。 260 另外需要注意的是modelconfig(model,self)中的self是哪個(gè)類(lèi)的實(shí)例化對(duì)象 261 當(dāng)在注冊(cè)類(lèi)的時(shí)候沒(méi)有傳入制定的樣式類(lèi),那么這里的self是Modelstark類(lèi)的實(shí)例化, 262 但是,當(dāng)用戶(hù)傳入定制的樣式類(lèi)時(shí),此時(shí)的self是modelconfig類(lèi)的實(shí)例化 263 ''' 264 self._registry[model] = modelconfig(model, self) 265 266 def get_urls(self): 267 ''' 268 生成表的一級(jí)和二級(jí)URL 269 :return: tmp 270 ''' 271 tmp = [] 272 ''' 273 item():使字典中的鍵值對(duì)以元組的形式顯示 274 model: 注冊(cè)的model類(lèi) 275 model_config:該類(lèi)對(duì)應(yīng)的樣式類(lèi)對(duì)象 276 app_label:以字符串形式獲取類(lèi)所在的APP 277 model_name:以字符串的獲取類(lèi)名 278 ''' 279 for model, model_config in self._registry.items(): 280 app_label = model._meta.app_label 281 model_name = model._meta.model_name 282 # 為什么不能去掉None 283 u = url("^%s/%s/" % (app_label, model_name), (model_config.get_url_func(), None, None)) 284 tmp.append(u) 285 return tmp 286 ''' 287 把urls函數(shù)做成靜態(tài)方法,urls.py 中執(zhí)行urls函數(shù)不需要加() 288 ''' 289 @property 290 def urls(self): 291 return self.get_urls(), None, None 292 293 294 # 創(chuàng)建單例對(duì)象,在每一個(gè)app中的stark文件中調(diào)用 295 site = Starksite()各功能的實(shí)現(xiàn)思路
一級(jí)與二級(jí)URL的設(shè)計(jì)思路
在注冊(cè)完表后,執(zhí)行urls.py文件,執(zhí)行
1 urlpatterns = [ 2 url(r'^admin/', admin.site.urls), 3 url(r'^stark/', site.urls), 4 ]site為類(lèi)Starksite的單例實(shí)例化對(duì)象,site.urls 調(diào)用類(lèi)下的urls方法,而urls方法實(shí)際上是執(zhí)行g(shù)et_urls(self) 方法,為每一個(gè)model首先生成一級(jí)URL,其次調(diào)用類(lèi)的樣式對(duì)象下的get_url_func(self)
函數(shù),生成二級(jí)URL,同時(shí)為每一個(gè)增刪改查URL創(chuàng)建別名,用于反向解析。
顯示頁(yè)面的數(shù)據(jù)顯示
1.數(shù)據(jù)顯示的思路
首先類(lèi)中定義一個(gè) list_display = ["__str__"]的靜態(tài)變量,此靜態(tài)變量在用于沒(méi)有重寫(xiě)該變量時(shí),則默認(rèn)顯示該對(duì)象的 def __str__(self) 方法的返回值。?
將顯示的數(shù)據(jù)以?[?[1,"python",12,"<a>編輯</a>"],[2,"java",23,"<a>編輯</a>"],[3,"php",111,"<a>編輯</a>"],]的形式在后后臺(tái)處理成功后,循環(huán)判斷要顯示的數(shù)據(jù)是一個(gè)字符串還是可執(zhí)行函數(shù),若是可執(zhí)行函數(shù)則執(zhí)行函數(shù)后追加保存到列表中,若是字符串則直接追加保存在列表中。
PS:
1.getattr(obj,str) 函數(shù)用于反射,實(shí)現(xiàn)通過(guò)對(duì)象的字段名名稱(chēng)找到該字段對(duì)應(yīng)的值。
2.要循環(huán)的字段實(shí)際上是new_list_display, 即對(duì)list_display進(jìn)行擴(kuò)展,是默認(rèn)顯示的字段有復(fù)選框、對(duì)象名稱(chēng)、編輯、刪除
def real_list_display(self):new_list_display = []new_list_display.extend(self.list_display)new_list_display.append(Modelstark.edit)new_list_display.append(Modelstark.delete)new_list_display.insert(0,Modelstark.checkbox)return new_list_display?
2.編輯和刪除a標(biāo)簽的實(shí)現(xiàn)
把編輯和刪除的a標(biāo)簽分別作為一個(gè)函數(shù),使該函數(shù)的返回值為 mark_safe("<a>編輯</a>"),在循環(huán)要顯示的字段對(duì)象的數(shù)據(jù)時(shí),執(zhí)行該函數(shù)。
PS:
mark_safe()函數(shù)實(shí)現(xiàn)前端safe相同的功能,使django不轉(zhuǎn)移標(biāo)簽對(duì)象。
3.表頭的實(shí)現(xiàn)
根據(jù)list_display 循環(huán)顯示表頭,當(dāng)遇到“__str__”時(shí),找到該該對(duì)象的“__str__“”方法的返回值,當(dāng)遇到制定的字段名稱(chēng),如public時(shí),則使用?self.model._meta.get_field(i).verbose_name獲取該字段的verbose_name,追加到列表中。
PS:
get_field(arg) 可以獲取到model表中該arg字段對(duì)象,該對(duì)象可以調(diào)用字段的屬性,如verbose_name。
4.讓字段作為a標(biāo)簽,實(shí)現(xiàn)跳轉(zhuǎn)到編輯頁(yè)面的實(shí)現(xiàn)
在循環(huán)顯示數(shù)據(jù)的時(shí)候, 判斷通過(guò)getattr()方法獲取的字段值是否在list_display_link中,如果在,則使用mark_safe()使該value成為a標(biāo)簽。
5.?ModelForm 組件實(shí)現(xiàn)頁(yè)面的增刪改查
只需要為要進(jìn)行form渲染的類(lèi)繼承ModelForm,即可。
6.使用ModelForm實(shí)現(xiàn)顯示中文錯(cuò)誤信息
在樣式類(lèi)中創(chuàng)建一個(gè)model_form = None的靜態(tài)變量,在創(chuàng)建?ModelForm 類(lèi)的函數(shù)?def default_modelform(self)中判斷model_form的值,值為None,則使用默認(rèn)的modelform,如果為T(mén)rue,則使用用戶(hù)stark.py中定義的樣式類(lèi)。
在每個(gè)APP中stark.py文件的創(chuàng)建
1 from .models import * 2 # 對(duì)單例對(duì)象的調(diào)用 3 from stark_demo.service.sites import site,Modelstark 4 from django.forms import ModelForm 5 6 7 class BookModelForm(ModelForm): 8 ''' 9 重寫(xiě)model的modelform類(lèi) 10 ''' 11 class Meta: 12 model = Book 13 fields = "__all__" 14 error_messages = { 15 "title":{"required":"不能為空"}, 16 "public":{"required":"不能為空"} 17 } 18 19 20 class BookConfig(Modelstark): 21 22 list_display = ["id","title","public"] 23 list_display_link = ["id","title",] 24 model_form = BookModelForm 25 26 27 site.register(Book,BookConfig)?
轉(zhuǎn)載于:https://www.cnblogs.com/liuyinzhou/p/8576144.html
總結(jié)
- 上一篇: 非科班的秋招攻略贴
- 下一篇: 5G 学习笔记 - NSA - ENDC