✘ list_viewhtml
處理表格(默認是顯示錶結構的全部字段)數據庫
1 list_display = self.get_list_display() 2 # 4.1處理表頭 3 header_list = [] 4 if list_display: 5 for multi_key in list_display: 6 if isinstance(multi_key,FunctionType): #判斷 傳入值是否爲函數 7 verbose_name = multi_key(self,obj=None,is_header=True) 8 else: 9 verbose_name = self.model_class._meta.get_field(multi_key).verbose_name 10 header_list.append(verbose_name) 11 else: 12 header_list.append(self.model_class._meta.model_name) 13 14 # 4.2處理表的內容 15 data_list = queryset[pager.start:pager.end] 16 17 body_list = [] 18 for row in data_list: #row 是UserInfo object (1) 19 row_list = [] 20 21 if list_display: 22 for multi_key in list_display: 23 if isinstance(multi_key,FunctionType): 24 row_list.append(multi_key(self,row,is_header=False,*args,**kwargs)) 25 else: 26 row_list.append(getattr(row,multi_key)) #獲取UserInfo object (1)的屬性 27 else: 28 row_list.append(row) 29 30 body_list.append(row_list)
爲了可以擴展之後業務的功能(推出新的業務,高級用戶可能要顯示多的列或者新的功能),咱們能夠針對某張表進行自定義修改定製。只需在本身的Handler子類重寫此方法django
這是StarkHandler類的方法
1 list_display = [] 2 def get_list_display(self): 3 """ 4 獲取頁面上應該顯示的列,預留自定義擴展 5 :return: 6 """ 7 field_list = [] 8 field_list.extend(self.list_display) 9 return field_list
在上面方法的架構基礎下,實現以往對錶〔編輯〕〔刪除〕的基本功能,一樣放在基類中架構
如圖 app
1 def display_edit(self,obj=None,is_header=None): 2 """ 3 生成<編輯>a標籤 4 :param obj: 5 :param is_header: 6 :return: 7 """ 8 if is_header: 9 return "編輯操做" 10 change_url = self.reverse_change_url(pk=obj.pk) 11 return mark_safe('<a href="%s">編輯</a>'%change_url) 12 13 def display_delete(self,obj=None,is_header=None): 14 """ 15 生成<刪除>a標籤 16 :param obj: 17 :param is_header: 18 :return: 19 """ 20 if is_header: 21 return "刪除操做" 22 delete_url = self.reverse_delete_url(pk=obj.pk) 23 return mark_safe('<a href="%s">刪除</a>'% delete_url)
示例:ide
1 #models.py下的Major類: 2 #class Major(models.Model): 3 # title = models.CharField(verbose_name='專業',max_length=32) 4 # 5 # def __str__(self): 6 # return self.title 7 8 #該model類view函數下,繼承StarkHanler,list_display[字段+方法]: 9 from stark.service.v1 import StarkHandler 10 11 class MajorHandler(StarkHandler): 12 list_display = ['title',StarkHandler.display_edit,StarkHandler.display_delete]
可是,若是表結構裏有choice字段呢?函數
則須要使用obj.get_字段名_display 獲取orm對象的信息。解決的話,一樣寫一個方法放在基類,之後提取choice字段的信息直接使用url
這裏不是StarkHandler類。
1 def get_choice_text(title,field): 2 """ 3 對於Stark組件中定義列時,choice若是想要顯示中文信息,調用此方法便可 4 :param title: 表頭名稱(自定義) 5 :param field: 字段名稱(須要提取的) 6 :return: 7 """ 8 def inner(self,obj=None,is_header=None): 9 if is_header: 10 return title 11 method = "get_%s_display" %field 12 return getattr(obj,method)() 13 14 return inner
Exa: list_display=[get_choice_text('性別','gender')]
表結構裏有manytomany的字段呢?spa
1 def get_m2m_text(title, field): 2 """ 3 對於Stark組件中定義列時,顯示m2m文本信息 4 :param title: 表頭名稱 5 :param field: 字段名稱 6 :return: 7 """ 8 9 def inner(self, obj=None, is_header=None, *args, **kwargs): 10 if is_header: 11 return title 12 queryset = getattr(obj, field).all() 13 text_list = [str(row) for row in queryset] 14 return ','.join(text_list) 15 16 return inner
Exa: list_display=[get_m2m_text('授課老師','teacher')]
當存儲數據多了呢?滾動查找全部數據?code
這邊借鑑了前輩所寫的分頁組件
1 """ 2 分頁組件 3 """ 4 from django.utils.safestring import mark_safe 5 6 class Pagination(object): 7 def __init__(self, current_page, all_count, base_url, query_params, per_page=20, pager_page_count=11): 8 """ 9 分頁初始化 10 :param current_page: 當前頁碼 11 :param per_page: 每頁顯示數據條數 12 :param all_count: 數據庫中總條數 13 :param base_url: 基礎URL 14 :param query_params: QueryDict對象,內部含全部當前URL的原條件 15 :param pager_page_count: 頁面上最多顯示的頁碼數量 16 """ 17 self.base_url = base_url 18 try: 19 self.current_page = int(current_page) 20 if self.current_page <= 0: 21 raise Exception() 22 except Exception as e: 23 self.current_page = 1 24 self.query_params = query_params 25 self.per_page = per_page 26 self.all_count = all_count 27 self.pager_page_count = pager_page_count 28 pager_count, b = divmod(all_count, per_page) 29 if b != 0: 30 pager_count += 1 31 self.pager_count = pager_count 32 33 half_pager_page_count = int(pager_page_count / 2) 34 self.half_pager_page_count = half_pager_page_count 35 36 @property 37 def start(self): 38 """ 39 數據獲取值起始索引 40 :return: 41 """ 42 return (self.current_page - 1) * self.per_page 43 44 @property 45 def end(self): 46 """ 47 數據獲取值結束索引 48 :return: 49 """ 50 return self.current_page * self.per_page 51 52 def page_html(self): 53 """ 54 生成HTML頁碼 55 :return: 56 """ 57 # 若是數據總頁碼pager_count<11 pager_page_count 58 if self.pager_count < self.pager_page_count: 59 pager_start = 1 60 pager_end = self.pager_count 61 else: 62 # 數據頁碼已經超過11 63 # 判斷: 若是當前頁 <= 5 half_pager_page_count 64 if self.current_page <= self.half_pager_page_count: 65 pager_start = 1 66 pager_end = self.pager_page_count 67 else: 68 # 若是: 當前頁+5 > 總頁碼 69 if (self.current_page + self.half_pager_page_count) > self.pager_count: 70 pager_end = self.pager_count 71 pager_start = self.pager_count - self.pager_page_count + 1 72 else: 73 pager_start = self.current_page - self.half_pager_page_count 74 pager_end = self.current_page + self.half_pager_page_count 75 76 page_list = [] 77 78 if self.current_page <= 1: 79 prev = '<li><a href="#">上一頁</a></li>' 80 else: 81 self.query_params['page'] = self.current_page - 1 82 prev = '<li><a href="%s?%s">上一頁</a></li>' % (self.base_url, self.query_params.urlencode()) 83 page_list.append(prev) 84 for i in range(pager_start, pager_end + 1): 85 self.query_params['page'] = i 86 if self.current_page == i: 87 tpl = '<li class="active"><a href="%s?%s">%s</a></li>' % ( 88 self.base_url, self.query_params.urlencode(), i,) 89 else: 90 tpl = '<li><a href="%s?%s">%s</a></li>' % (self.base_url, self.query_params.urlencode(), i,) 91 page_list.append(tpl) 92 93 if self.current_page >= self.pager_count: 94 nex = '<li><a href="#">下一頁</a></li>' 95 else: 96 self.query_params['page'] = self.current_page + 1 97 nex = '<li><a href="%s?%s">下一頁</a></li>' % (self.base_url, self.query_params.urlencode(),) 98 page_list.append(nex) 99 page_str = "".join(page_list) 100 return mark_safe(page_str)
Combine▼
list_view下的分頁功能:
1 all_count = queryset.count() 2 query_params = request.GET.copy() # ?=page=1&name='李四' 3 query_params._mutable = True #query_params['page']默認是不能夠修改的 4 5 pager = Pagination( 6 current_page=request.GET.get('page'), 7 all_count=all_count, 8 base_url=request.path_info, 9 query_params=query_params, 10 per_page=self.per_page_count, 11 )
✘ add_view
如圖,
爲了可以在模板循環展現表單數據、錯誤信息等,咱們得建立forms.ModelForm對象,而後把form對象傳遞過去。
可是每張表model_class所產生的form對象是不同的,所以不一樣請求進來都得建立一個ModelForm,這樣就太不方便了
解決:
1 class DynamicModelForm(forms.ModelForm): 2 class Meta: 3 model = self.model_class 不把model表寫死了,應該是動態的,即須要訪問的model類 4 fields = "__all__"
在這基礎下,封裝成爲一個方法,日後須要產生form對象時,代入model類,直接調用。
1 model_form = False 2 def get_model_form(self): 3 if self.model_form: #預留勾子,拓展或者自定義定製覆蓋便可 4 return self.model_form 5 6 class DynamicModelForm(forms.ModelForm): 7 class Meta: 8 model = self.model_class 9 fields = "__all__" 10 11 def __init__(self, *args, **kwargs): 12 super(DynamicModelForm, self).__init__(*args, **kwargs) 13 # 統一給ModelForm生成字段添加樣式 14 for name, field in self.fields.items(): 15 field.widget.attrs['class'] = 'form-control' 16 17 return DynamicModelForm
若是有需求想讓form對象多一行確認密碼,或者控制顯示的行呢?
前者能夠在子類重寫ModelForm,然後者咱們則需爲form.save()預留勾子,方便拓展或重寫覆蓋。
1 def save(self,request,form,is_update,*args,**kwargs):
2 form.save()
實現save基操下,想到若是在點擊添加按鈕的時候,URL自己帶有 /?page=1的參數下,執行添加操做後,理應返回原來頁面的時候帶回這個參數。
這裏,簡單地理一下。
1.在進入添加路由時,咱們先把參數部分urlencode(),而後把數據做爲鍵值"_filter"的value值,最後urlencode() 做爲新的參數。
1 def reverse_add_url(self,**kwargs): 2 name = "%s:%s" % (self.site.namespace, self.get_add_url_name) #stark:Web_customer_public_list 3 url = reverse(name,kwargs=kwargs) 4 5 if not self.request.GET: 6 add_url = url 7 else: 8 param = self.request.GET.urlencode() # page=1 9 10 new_query_dict = QueryDict(mutable=True) 11 new_query_dict['_filter'] = param # <QueryDict: {'_filter': ['page=1']}> 12 13 add_url = "%s?%s" % (url, new_query_dict.urlencode(())) 14 15 return add_url
2.相似地,添加完後 redirect 回原來頁面並帶回參數
1 def reverse_list_url(self,**kwargs): 2 name = "%s:%s" % (self.site.namespace, self.get_list_url_name) 3 url = reverse(name,kwargs=kwargs) 4 if not self.request.GET: 5 list_url = url 6 else: 7 param = self.request.GET.get('_filter') 8 # print(param) #page=1 9 if not param: 10 return redirect(url) 11 list_url = "%s?%s" % (url, param) 12 13 return list_url
全部的鋪墊下,添加視圖方法基本完成。
1 def add_view(self,request,*args,**kwargs): 2 """ 3 添加視圖 4 :param request: 5 :return: 6 """ 7 model_form = self.get_model_form() 8 if request.method == 'GET': 9 form = model_form 10 return render(request, 'change.html', {'form': form}) 11 12 form = model_form(data=request.POST) 13 if form.is_valid(): 14 response = self.save(request,form,False,*args,**kwargs) 15 return response or redirect(self.reverse_list_url(**kwargs)) 16 return render(request,'change.html',{'form':form})
✘ change_view
基本跟添加視圖同樣,只是form對象在表單默認顯示數據
1 def get_change_object(self, request, pk, *args, **kwargs): 2 return self.model_class.objects.filter(pk=pk).first() 3 4 def change_view(self,request,pk,*args,**kwargs): 5 """ 6 編輯視圖 7 :param request: 8 :param pk: 9 :return: 10 """ 11 checked_obj = self.get_change_object(request, pk, *args, **kwargs) 12 13 if not checked_obj: 14 return render(request,'rbac\error.html') 15 16 model_form = self.get_model_form() 17 if request.method == 'GET': 18 form = model_form(instance=checked_obj) 19 return render(request, 'change.html', {'form': form}) 20 21 form = model_form(data=request.POST,instance=checked_obj) 22 if form.is_valid(): 23 response = self.save(request, form, True, *args, **kwargs) 24 return response or redirect(self.reverse_list_url(**kwargs)) 25 return render(request, 'change.html', {'form': form})
✘ delete_view
基本跟添加視圖同樣。
這裏繼承以往爲了防止用戶刪除數據時小手一抖,作出的確認選擇按鈕
1 def delete_object(self, request, pk, *args, **kwargs): 2 self.model_class.objects.filter(pk=pk).delete() 3 4 def delete_view(self,request,pk,*args,**kwargs): 5 """ 6 刪除視圖 7 :param request: 8 :param pk: 9 :return: 10 """ 11 checked_obj = self.model_class.objects.filter(pk=pk).first() 12 if not checked_obj: 13 return render(request,'rbac\error.html',) 14 15 list_url = self.reverse_list_url(**kwargs) 16 if request.method == 'GET': 17 return render(request,'delete.html',{'list_url':list_url}) 18 19 response = self.delete_object(request, pk, *args, **kwargs) 20 return response or redirect(list_url)