雖然我們基本實現了我們自定義組件stark的功能,接下來就是顯示數據了。
今天我們先來寫查。先來寫表單部分
我們如果需要顯示我們自己配置類中的字段,應該怎么做呢?
我們有這樣一個想法,將這些數據放在一個列表中,類似這樣[[‘python’,122],[‘linux’,110]],然后在頁面上依次循環這個列表,取值就行了。
self.model.objects.all()中里面有我們需要的對象,self.list_display中有我們需要的字段。所以:
def listview(self,request): # print(self)# 當前訪問摩星表的配置類對象 # print(self.model)# 當前訪問的模型表 data_list = self.model.objects.all() # 取到所有的對象 ['python','linux']# 構建數據表單部分 new_data_list = [] for obj in data_list: temp = [] for field in self.list_display: # ['price','title'] val = getattr(obj,field) # getattr通過字符串取值 temp.append(val) # ['python','100'] ['linux','120'] new_data_list.append(temp) # [['python','100'],['linux','120']] return render(request,'list.html',locals())
在頁面上我們這樣獲取數據:
<table class="table table-hover"> <thead> <tr></tr> </thead> <tody> {% for data in new_data_list %} <tr> {% for item in data %} <td>{{ item }}</td> {% endfor %} </tr> {% endfor %} </tody> </table>
但是這里面有一個bug,因為我們是以book為例 的,book是我們自己寫的配置類,所以list_display中有我們寫的字段,但是當我們訪問publish的時候,publish用的是默認的配置類,list_display里面是沒有字段的,所以在 for field in self.list_display: # ['price','title'] 這一步出錯。所以我們應該在默認配置類的最前面定義一個list_display = ['__str__'],如果使用的是默認的配置類,就讓他執行__str__方法。
我們都知道,在admin組件中,我們自己定義的配置類中,list_display中是可以放一對多字段,但是不能放多對多字段,,所以在我們寫的自定義組件中,也同樣不能放多對多字段,那我們就像顯示多對多的字段,該怎么做呢?
這里先說一個知識點:我們之前介紹過在我們自己寫的組件中,
model_name = self.model._meta.model_name
app_label = self.model._meta.app_label
這兩種方法可以獲得當前表的名字和當前app的名字。在介紹一種field_obj = self.model._meta.get_field(field)這種方法能夠取到表中具體的某一字段對象。
所以我們想要放多對多字段之前,先進行判斷,
def listview(self,request): # print(self)# 當前訪問摩星表的配置類對象 # print(self.model)# 當前訪問的模型表 data_list = self.model.objects.all()
# 構建數據表單部分 new_data_list = [] for obj in data_list: temp = [] for field in self.list_display:
from django.db.models.fields.related import ManyToManyField field_obj = self.model._meta.get_field(field) # 獲取表中某個字段 if isinstance(field_obj,ManyToManyField): # 判斷field_obj字段是否屬於多對多字段 many_data_list = getattr(obj, field).all() # 如果是多對多字段,book.author.all()取到所有作者對象 item = [str(item) for item in many_data_list] val = ','.join(item) else:# 如果不是多對多字段,獲取值 val = getattr(obj,field) temp.append(val) new_data_list.append(temp)
return render(request,'list.html',locals())
這樣就行了。這樣表單中的數據就處理完了。接下來我們來寫表頭部分。
我們想表頭部分不就是在list_display中嗎?直接在頁面中循環不就行了嗎。這樣固然沒錯,但是這樣渲染出來的表頭是英文的,我們想要中文的怎么做?
def listview(self,request): # print(self)# 當前訪問摩星表的配置類對象 # print(self.model)# 當前訪問的模型表 data_list = self.model.objects.all() # 構建表頭部分 header_list=[] for field in self.list_display: # 循環每一個字段,if field == '__str__': # 判斷field是__str__,說明使用的是默認配置類,將表頭就定為表的名字 val = self.model._meta.model_name else: # 否則說明使用的自定義配置類, obj = self.model._meta.get_field(field) # 得到自定義配置類的字段對象, val = obj.verbose_name # 獲取字段的verbose_name,verbose_name是models中每一個字段的可設置的參數 header_list.append(val)
# 構建數據表單部分 new_data_list = [] for obj in data_list: temp = [] for field in self.list_display: from django.db.models.fields.related import ManyToManyField field_obj = self.model._meta.get_field(field) # 獲取表中某個字段 if isinstance(field_obj,ManyToManyField): # 判斷field_obj字段是否屬於多對多字段 many_data_list = getattr(obj, field).all() # 如果是多對多字段,book.author.all()取到所有作者對象 item = [str(item) for item in many_data_list] val = ','.join(item) else:# 如果不是多對多字段,獲取值 val = getattr(obj,field) temp.append(val) new_data_list.append(temp)
return render(request,'list.html',locals())
在頁面中,
<table class="table table-hover"> <thead> <tr> {% for header in header_list %} <th>{{ header }}</th> {% endfor %} </tr> </thead> <tody> {% for data in new_data_list %} <tr> {% for item in data %} <td>{{ item }}</td> {% endfor %} </tr> {% endfor %} </tody> </table>
這樣表頭就完了。
接下來我們寫自定義列
我們在查看書籍的時候肯定夠編輯和刪除對不對,所以我們要在表頭加一列:操作。這該怎么做,
添加操作當然要在自定義配置類中的list_display中添加操作,list_display = ["title", "price", "publish",'authors',edit,delete]:
# 定義自己的配置類 class Bookconfig(sites.ModelAdmin): def edit(self,obj=None,is_header=False): if is_header: return '操作' else: return mark_safe("<a href='/stark/app01/book/%s/change/'>編輯</a>"%obj.pk) def delete(self,obj=None,is_header=False): if is_header: return '操作' else: return mark_safe("<a href='/stark/app01/book/%s/delete/'>刪除</a>" % obj.pk) # list_display' must not be a ManyToManyField. list_display = ["title", "price", "publish",'authors',edit,delete] sites.site.register(models.Book,Bookconfig)
那么在視圖函數中怎么用呢?
上面涉及到的知識點:
知識點一:._meta.get_field(field)
知識點二:mark_safe
如果要往頁面中返回標簽的話,django會有這樣一個機制,它會將尖角號進行轉譯,所以渲染在頁面后就會出錯,引入from django.utils.safestring import mark_safe,使用mark_safe是告訴django不要對我們的標簽轉譯,它的作用和頁面中使用的safe的作用一樣的。