1.display顯示要設置的字段
1. 自定義樣式類,顯示出要顯示的字段,在這個類中,也可以設置對應函數。 list_display=[check,"title",delete]
2.在 Modelxadmin中設置:list_display=["__str__"]
設置Modelxadmin的靜態屬性,即當注冊的對象沒使用樣式類時,使用Modelxadmin的樣式屬性
3.處理表頭
display中的函數名或者變量名作為表頭
1.需要判斷傳的列表中的內容是函數名還是字符串
2.如果是字符串,判斷是"__str__"還是其他的
3.讓相應的字符串表頭顯示對應的中文,取到字段對象,引用字段中的verbose_name
4.處理表單數據
需要判斷傳的列表中的內容是函數名還是字符串
1.若是函數名,去執行對應的函數,取到對應的值
2.若是變量,利用反射到相應的數據中取到值
2.設定樣式類list_display

from Xadmin.service.Xadmin import site,Modelxadmin from app01 import models from django.utils.safestring import mark_safe class BookConfig(Modelxadmin): href=change/'%s/'自動在當前路徑后拼接路徑 def edit(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "操作" return mark_safe("<a href='change/%s/'>編輯</a>"%obj.pk) def delete(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "刪除" return mark_safe("<a href='del/%s/'>刪除</a>" % obj.pk) def check(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "選擇" return mark_safe("<input type='checkbox'>") list_display=[check,"title","price","publish","authors",edit,delete] site.register(models.Book,BookConfig)
3.顯示設置
1.處理表頭
處理表頭 [check,'title', 'prcie',edit]
# 1.需要判斷傳的列表中的內容是函數名還是字符串
# 2.如果是字符串,判斷是"__str__"還是其他的

head=[] for field in self.list_display: if isinstance(field,str): if field=="__str__": val=self.model._meta.model_name.upper() #如果沒定義樣式類,表頭就顯示操作表的名字的大寫 else: # class Book(models.Model): # title = models.CharField(max_length=32, verbose_name="書名") # price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="價格") #如果是字段字符串,讓表頭顯示其定義的中文表頭。title是字段對象,找到title后title.verbose_name 獲取這個屬性值 obj=self.model._meta.get_field(field) val=obj.verbose_name else: val = field(self,is_header=True) head.append(val)
2.處理表單數據

使用反射 data_list=self.model.objects.all() #取出每一條數據的對象,data_list[0].字段名(title) 就能得到相應的數據 content = [] for obj in data_list: temp=[] for field in self.list_display:#自定義的樣式類中有可能放的是自定義的函數名[check,'title', 'prcie',edit] #需要判斷傳的列表中的內容是函數名還是字符串 if isinstance(field,str): #判斷數據類型 val=getattr(obj,field) #相當於obj.title,obj.price 其中obj.__str__會自動觸發這個方法 print("結果是:",val) else: val=field(self,obj,) #定義的方法,obj為這個方法執行的哪條數據對象 temp.append(val) content.append(temp) return render(request,"list.html",{"content":content,"head":head,"type":type})
4.利用反向路由解析得到路徑

''' #Modelxadmin中設置 class Modelxadmin(object): list_display=["__str__"] #設置Modelxadmin的靜態屬性,即當注冊的對象沒使用樣式類時,使用Modelxadmin的樣式屬性 def __init__(self,model,site): #如果傳的是book,model就是Book 傳的是publish,model就是Publiah self.model=model self.site=site self.model_name = self.model._meta.model_name #得到app名 self.app_name = model._meta.app_label #得到表名 #為路由設置別名: def get_url_2(self): temp = [] # print("=====",model_name ) # temp.append(url(r"^$", self.list_view)) temp.append(url(r"^$", self.list_view,name="{}/{}_list".format( self.app_name, self.model_name))) temp.append(url(r"^add/$", self.add_view,name="{}/{}_add".format( self.app_name, self.model_name))) # temp.append(url(r"^(\d+)/change/$", self.change_view,)) temp.append(url(r"^change/(\d+)/$", self.change_view,name="{}/{}_change".format( self.app_name, self.model_name) )) temp.append(url(r"^del/(\d+)/$", self.del_view,name="{}/{}_del".format( self.app_name, self.model_name))) return temp #自定以樣式類中設置: from django.utils.safestring import mark_safe from django.urls import reverse class BookConfig(Modelxadmin): def edit(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "操作" #BookConfig中沒有self.app_name,就去Modelxadmin找 url_name="{}/{}_change".format( self.app_name, self.model_name) v = reverse(url_name, args=(obj.pk,)) return mark_safe("<a href='%s'>編輯</a>" % v) '''
顯示頁面的html
''' <p> <span>序號</span> {% for foo in head %} <span>{{ foo }}</span> {% endfor %} </p> {% for foo in content %} <P> <span>{{ forloop.counter }}</span> {% for foo1 in foo %} <span>{{ foo1 }}</span> {% endfor %} </P> {% endfor %} '''
5.顯示多對多的關系字段
多對多的字段,傳過去之后在頁面上顯示字符串:app01.Author.None

例:作者是多對多的關系 list_display=[check,"title","price","publish","authors",edit,delete] 傳過去之后在頁面上顯示字符串:app01.Author.None 解決方法一:將ManytoMany這個字段當作函數名傳過去,不再寫成字符串 在樣式類中定義ManytoMany字段方法: def display_authors(self,obj=None, is_header=False): if is_header: return "作者名稱" s=[] for author in obj.authors.all(): #必須使用all(),得到所有的作者對象 s.append(author.name) #取出每個作者對象的name屬性 val=" | ".join(s) return mark_safe(val) list_display = [check, "title", "price", "publish", display_authors, edit, delete] 方法二:判斷是不是ManytoMany類型 data_list=self.model.objects.all() #取出每一條數據的對象,data_list[0].字段名(title) 就能得到相應的數據 content = [] for obj in data_list: temp=[] for field in self.list_display:#自定義的樣式類中有可能放的是自定義的函數名[check,'title', 'prcie',edit] #需要判斷傳的列表中的內容是函數名還是字符串 if isinstance(field,str): #判斷數據類型 #處理多對多的字段方法二:判斷是不是ManytoMany類型 from django.db.models.fields.related import ManyToManyField many_obj = self.model._meta.get_field(field) #取到字段對象 if isinstance(many_obj,ManyToManyField): t=[] for i in getattr(obj,field).all(): t.append(i.name) val=" | ".join(t) else:val=getattr(obj,field) #相當於obj.title,obj.price 其中obj.__str__會自動觸發這個方法 list_display=[check,"title","price","publish","authors",edit,delete]
6.將刪除,編輯,選擇按鈕封裝起來

''' app01.Xadmin 1.使用繼承:但是需要在每個樣式類中設定 class Operation(): def edit(self, obj,is_header): if is_header: # 此時作表頭處理 return "操作" else: url_name = "{}/{}_change".format(self.app_name, self.model_name) # BookConfig中沒有self.app_name,就去Modelxadmin找 v = reverse(url_name, args=(obj.pk,)) return mark_safe("<a href='%s'>編輯</a>" % v) def delete(self, obj, is_header): if is_header: # 此時作表頭處理 return "操作" return mark_safe("<a href='del/%s/'>刪除</a>" % obj.pk) def check(self, obj, is_header): if is_header: # 此時作表頭處理 return "選擇" else:print(777) return mark_safe("<input type='checkbox'>") class BookConfig(Modelxadmin, Operation): def check(self,obj=None, is_header=False):return super().check(obj, is_header) def edit(self,obj=None, is_header=False):return super().edit(obj, is_header) def delete(self,obj=None, is_header=False):return super().delete(obj, is_header) list_display=[check,"title","price","publish","authors",edit,delete] #如果不在BookConfig中定義check,edit,delete函數,在list_dispaly中加函數名后,會顯示未定義。在用super調用時不能傳位置參數 2.在Xadmin中設置,將check,edit,delete加到每個模型表的樣式類中,模型表的樣式類就不用再加這些函數 class Modelxadmin(object): # 選擇按鈕 編輯 刪除 def edit(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "操作" else: v=self.get_change_url(obj) return mark_safe("<a href='%s'>編輯</a>" %v) def delete(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "操作" v = self.get_del_url(obj) return mark_safe("<a href='%s'>刪除</a>" %v) def check(self, obj=None, is_header=False): if is_header: # 此時作表頭處理 return "選擇" v = self.get_del_url(obj) return mark_safe("<input type='checkbox'>") #構建新的list_dispaly def new_list_display(self): temp=[] temp.append(Modelxadmin.check) temp.extend(self.list_display) temp.append(Modelxadmin.edit) temp.append(Modelxadmin.delete) return temp #處理表頭 [check,'title', 'prcie',edit] for field in self.new_list_display():pass #處理表單數據,使用反射 data_list=self.model.objects.all() #取出每一條數據的對象,data_list[0].字段名(title) 就能得到相應的數據 content = [] for obj in data_list: temp=[] for field in self.new_list_display():pass 樣式類中直接傳要顯示的字段 list_display = ["title", "price", "publish", "authors"] '''
7.設定樣式類list_display_link
1.在循環表單數據時,如果list_display中的字段名在list_display_link,就將改字段的內容設置成編輯標簽
2.如果表中數據設置成了編輯標簽,那么編輯這個操作就沒什么用了,應該判斷如果樣式中無list_display_link,就顯示編輯操作,
有list_display_link則不顯示編輯操作

在new_list_display中判斷是否加編輯操作 def new_list_display(self): temp=[] temp.append(Modelxadmin.check) temp.extend(self.list_display) #判斷是否加編輯操作 if not self.list_display_link: temp.append(Modelxadmin.edit) temp.append(Modelxadmin.delete) return temp ##將相應值設置成編輯標簽 from django.db.models.fields.related import ManyToManyField try: many_obj = self.model._meta.get_field(field) #取到字段對象 if isinstance(many_obj,ManyToManyField): t=[] for i in getattr(obj,field).all(): t.append(i.name) val=" | ".join(t) else: #判斷改字段是否在list_display_link,如果在,就設置成標簽形式,不再就正常顯示 if field in self.list_display_link: edit_url=self.get_change_url(obj) val=mark_safe("<a href='%s'>%s</a>"%(edit_url,getattr(obj,field))) else:val=getattr(obj,field) except Exception as e: val = getattr(obj, field)
顯示頁面的函數形式

''' def list_view(self, request): #self是Modelxadmin的實例對象,要么是自定義樣式類的實例對象 # print("這里是:", model_name ) type=request.GET.get("name") if not type:type="" print(type) print(self.model) #用戶調用的哪張表,self.model就是哪張表 <class 'app02.models.Order'> print("新的是:",self.new_list_display()) #處理表頭 [check,'title', 'prcie',edit] # 1.需要判斷傳的列表中的內容是函數名還是字符串 # 2.如果是字符串,判斷是"__str__"還是其他的 head=[] # for field in self.list_display: for field in self.new_list_display(): if isinstance(field,str): if field=="__str__": print("食物") val=self.model._meta.model_name.upper() #如果沒定義樣式類,表頭就顯示操作表的名字的大寫 else: # class Book(models.Model): # title = models.CharField(max_length=32, verbose_name="書名") # price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="價格") #如果是字段字符串,讓表頭顯示其定義的中文表頭。title是字段對象,找到title后title.verbose_name 獲取這個屬性值 obj=self.model._meta.get_field(field) val=obj.verbose_name else: val = field(self,is_header=True) head.append(val) print(head) #處理表單數據,使用反射 data_list=self.model.objects.all() #取出每一條數據的對象,data_list[0].字段名(title) 就能得到相應的數據 content = [] for obj in data_list: temp=[] # for field in self.list_display:#自定義的樣式類中有可能放的是自定義的函數名[check,'title', 'prcie',edit] for field in self.new_list_display(): #需要判斷傳的列表中的內容是函數名還是字符串 if isinstance(field,str): #判斷數據類型 #處理多對多的字段方法二:判斷是不是ManytoMany類型 from django.db.models.fields.related import ManyToManyField try: #如果是__str__ 走到這會報錯,因此使用拋出異常處理 many_obj = self.model._meta.get_field(field) #取到字段對象 if isinstance(many_obj,ManyToManyField): t=[] for i in getattr(obj,field).all(): t.append(i.name) val=" | ".join(t) else: # val=getattr(obj,field) #相當於obj.title,obj.price 其中obj.__str__會自動觸發這個方法 #判斷改字段是否在list_display_link,如果在,就設置成標簽形式,不再就正常顯示 if field in self.list_display_link: edit_url=self.get_change_url(obj) val=mark_safe("<a href='%s'>%s</a>"%(edit_url,getattr(obj,field))) else:val=getattr(obj,field) except Exception as e: val = getattr(obj, field) print("結果是:",val) else: val=field(self,obj,) #定義的方法,obj為這個方法執行的哪條數據對象 temp.append(val) print("temp是:", temp) content.append(temp) print("content是:", content) # ##獲取增加頁面的url 點擊增加的時候,跳到增加頁面。自動拼接 # add_url="add" return render(request,"list.html",{"content":content,"head":head,"type":type,"add_url":self.get_add_url()}) '''
8.設置分頁
將分頁方法設置為顯示類得屬性,用時直接用對象調用

class ShowList(object): def __init__(self,config,data_list,request): self.config=config #config是Modelxadmin的對象 self.data_list=data_list self.request=request ##配置分頁設置: current_page = self.request.GET.get("page") pagination = Pagination(current_page, self.data_list.count(), "%s" % self.config.get_list_url(), self.request.GET, per_page_num=3) self.pagination=pagination self.model_list = self.data_list[pagination.start:pagination.end] def get_body(self): content = [] for obj in self.model_list:pass #循環分完頁之后數據對象
分頁條:
<ul class="pull-right">
{{show_list.pagination.page_html|safe }}
</ul>
9.搜索功能
搜索時用GET請求,后端很根據收到的搜索條件進行處理,在顯示全部數據的基礎上,將符合搜索的內容顯示出來
未使用搜索時,獲得當前對象的所有內容
data_list = self.model.objects.all()
加了搜索,就在這基礎上進行條件搜索,使用filter
data_list = self.model.objects.filter(條件)
獲取到設定的搜索字段,使用Q()進行操作,將字符串類型的字段和接受到的搜索值加到Q()中,搜索時會檢測所有對象的這個字段中是否含有搜索值,如果有,就把這個
對象取出來

class Modelxadmin(object): search_fields = [] def get_search(self, request): search_condition = Q() search_condition.connector = 'or' search_value = request.GET.get("search_value") if search_value: for search_field in self.search_fields: search_condition.children.append((search_field + "__icontains", search_value)) return search_condition def list_view(self, request): #self是Modelxadmin的實例對象,要么是自定義樣式類的實例對象 #print(self.model) #用戶調用的哪張表,self.model就是哪張表 <class 'app02.models.Order'> search_condition=self.get_search(request) data_list = self.model.objects.filter(search_condition) #search_condition有值,就按值搜索,無值就搜索全部
在顯示頁面,設置搜索框是否顯示。通過判斷search_fields來判斷是都設置了搜索值,如果為空,在頁面上就不顯示搜索
HTML

''' {% if show_list.config.search_fields %} <div class="input-group"> <form action=" " method="GET"> <span class="input-group-btn"> <input type="text" name="search_value" class="form-control" placeholder="Search for..."> <button class="btn btn-default" >搜索</button> </span> </form> </div> {% endif %} '''
10.批處理功能
實現選擇對應得操作后,執行對應得函數
批處理操作使用select選擇的方式:value應對應函數名,顯示的操作名稱不應該直接再HTML中設定,
可以在后端為相應的執行函數起相應的名字
對函數做描述:foo.short_description="批量初始化" #對這個函數作描述

class A(): def foo(self,queryset): queryset.delete() foo.short_description="批量刪除" def update(self,queryset): queryset.update(price=100) update.short_description="批量初始化" #對這個函數作描述 action=[foo,update] b=A() for i in b.action: #i是函數名 print(i.__name__,i.short_description) HTML中 <option value="{{ i.__name__ }}">{{ i.short_description) }}</option>
1.設置批處理函數
在app01 Xadmin中設置自定義處理函數: class BookConfig(Modelxadmin): def all_update(self,request,queryset): #queryset為數據對象 queryset.update(price=998) list_url = self.get_list_url() return redirect("%s" % list_url) all_update.short_description="批量初始化" actions=[all_update,] 在全局中設置批量刪除函數: class Modelxadmin(object): actions=[] def all_delete(self,request,queryset): queryset.delete() list_url=self.get_list_url() return redirect("%s"%list_url) all_delete.short_description="批量刪除"
2.在Modelxadmin將批量刪除和樣式類中的actions合到一起

def get_action(self): #將批量刪除和樣式類中的actions合到一起 temp=[] temp.append(self.all_delete) temp.extend(self.actions) #迭代添加 return temp #將得到的temp作為ShowList的一個屬性,並函數名和描述值處理后在頁面顯示出來 class ShowList(object): self.actions=self.config.get_action() def new_actions(self): temp=[] for action in self.actions: temp.append({ "name":action.__name__, "desc":action.short_description }) return temp
3.HTML
<span class="input-group-btn" > <select name="action" id="" class="form-control"> <option value="">------------------</option> {% for foo in show_list.new_actions %} <option value="{{ foo.name }}">{{foo.desc }}</option> {% endfor %} </select> <button class="btn btn-default" >GO</button> </span>
4.后台接收處理:
class Modelxadmin(object): def list_view(self, request): if request.method=='POST': #批量操作 action=request.POST.get("action") #哪種操作,name="action",值為要執行操作的函數名 print("操作是",action) selected_pk=request.POST.getlist("selected") #操作的數據 action_obj=self.model.objects.filter(pk__in=selected_pk) action=getattr(self,action) ret=action(request,action_obj) return ret
完整的views.py

##批處理:得到注冊對象樣式類中指定的操作,並為所有的注冊對象添加上刪除操作 def all_delete(self,request,queryset): queryset.delete() list_url=self.get_list_url() return redirect("%s"%list_url) all_delete.short_description="批量刪除" def get_action(self): #將批量刪除和樣式類中的actions合到一起 temp=[] temp.append(self.all_delete) temp.extend(self.actions) #迭代添加 return temp #將得到的temp作為ShowList的一個屬性 def list_view(self, request): #self是Modelxadmin的實例對象,要么是自定義樣式類的實例對象 if request.method=='POST': #批量操作 action=request.POST.get("action") #哪種操作 print("操作是",action) selected_pk=request.POST.getlist("selected") #操作的數據 action_obj=self.model.objects.filter(pk__in=selected_pk) action=getattr(self,action) ret=action(request,action_obj) return ret
11.過濾功能
1.首先在頁面上展示出過濾的內容
頁面收到后端傳來的數據進行循壞操作,收到的應該是個字典:
{"publish":["a","a"],"author":["a","a"]},key值為表名,value為表中的所有對象的名字,同時將value
設置成標簽,herf設為?key=obj.pk的形式,點完標簽后,后台接受到操作的表名和要操作的對象進行搜索操作,從而展示出來
2.在指定的app01中注冊模型表中設置過濾的字段:以Book表為例:
class BookConfig(Modelxadmin): list_filter=["publish","authors"] 在Xadimn中作后台處理操作: class Modelxadmin(object): list_filter = []
首先要做的是創建出{"publish":["a","a"],"author":["a","a"]}這種類型給頁面展示出來,展示出來之后,在做跳轉操作,展示的處理都放在
ShowList中,在ShowList中定義處理函數。得到自定義的search_fields中,得到對應的字符串類型的字段,根據字符串,找到這個字段對象,根據字段
對象,得到關聯表中的所有對象,將這個對象名做成鏈接返給頁面
1.def get_filter_link_tags(self): # link_tags={"publish":["a","a"],"author":["a","a"]} link_tags={} for filter_field in self.list_filter: #["title", "price"] filter_field_obj=self.config.model._meta.get_field(filter_field) #得到Book表中的publish和authors字段 #得到字段對象關聯表的所有對象。publish和authors中所有對象 related_data_list=filter_field_obj.rel.to.objects.all() temp=[] for obj in related_data_list: #對每個對象做處理 _url="%s=%s"%(filter_field,obj.pk) s="<a href='?%s'>%s</a>"%(_url,str(obj)) #在頁面顯示出?publish=2 temp.append(mark_safe(s)) link_tags[filter_field]=temp return link_tags
3.點擊相應鏈接
在點擊相應鏈接之后,點擊publish中的對象顯示?publish=2這種形式,點擊author中的內容顯示?author=2
但是要保存搜索條件,即在上次選的條件下繼續搜索,達到?publish=2&?author=2的效果。使用request.GET
在第一次點擊鏈接之后,頁面刷新,會重新走到這一步,獲取數據返還給頁面,此時self.request.GET獲取到?publish=2,在執行到循環authors的對象時
就會將參數拼接起來?publish=2&?author=2

def get_filter_link_tags(self): # link_tags={"publish":["a","a"],"author":["a","a"]} link_tags={} from copy import deepcopy for filter_field in self.list_filter: # /Xadmin/app01/book/?page=2 params = deepcopy(self.request.GET) #將后面的參數以字典的形式接收 {'page':2} filter_field_obj=self.config.model._meta.get_field(filter_field) #得到字段對象關聯表的所有對象 related_data_list=filter_field_obj.rel.to.objects.all() temp=[] for obj in related_data_list: params[filter_field]=obj.pk # {"authors":2} _url=params.urlencode() # _url="%s=%s"%(filter_field,obj.pk) s="<a href='?%s'>%s</a>"%(_url,str(obj)) temp.append(mark_safe(s)) link_tags[filter_field]=temp return link_tags
4.點擊完當前標簽之后,當前標簽添加背景色。通過判斷當前的接受到的id和循環中的當前id是否相等
current_id=self.request.GET.get(filter_field) if current_id==str(obj.pk): s = "<a class='item' href='?%s'>%s</a>" % (_url, str(obj)) else: s="<a href='?%s'>%s</a>"%(_url,str(obj))
5.鏈接跳轉
點擊相應的標簽后,后台接收到?publish=2這個數據,進行過濾查詢,使用Q().children

class Modelxadmin(object): filter_condition=Q() for filter_field,val in request.GET.items(): ##當選擇分頁時,頁面上會把page=2傳過來,仍走這一步,但是表中並沒有這個字段,所以會報錯 if filter_field not in ['page',"search_value"]: filter_condition.children.append((filter_field,val)) data_list = self.model.objects.filter(filter_condition).filter(search_condition) #search_condition有值
過濾功能views.py

class BookConfig(Modelxadmin): list_filter=["publish","authors"] class Modelxadmin(object): list_filter = [] def list_view(self, request): filter_condition=Q() for filter_field,val in request.GET.items(): ##當選擇分頁時,頁面上會把page=2傳過來,仍走這一步,但是表中並沒有這個字段,所以會報錯 if filter_field not in ['page',"search_value"]: filter_condition.children.append((filter_field,val)) data_list = self.model.objects.filter(filter_condition).filter(search_condition) #search_condition有值,就按值搜索,無值就搜索全部 class ShowList(object): def get_filter_link_tags(self): # link_tags={"publish":["a","a"],"author":["a","a"]} link_tags={} from copy import deepcopy for filter_field in self.list_filter: # /Xadmin/app01/book/?page=2 params = deepcopy(self.request.GET)#將后面的參數以字典的形式接收 {'page':2} current_id=self.request.GET.get(filter_field) filter_field_obj=self.config.model._meta.get_field(filter_field) #得到字段對象關聯表的所有對象 related_data_list=filter_field_obj.rel.to.objects.all() temp=[] for obj in related_data_list: params[filter_field]=obj.pk # {"authors":2} _url=params.urlencode() # _url="%s=%s"%(filter_field,obj.pk) if current_id==str(obj.pk): s = "<a class='item' href='?%s'>%s</a>" % (_url, str(obj)) else: s="<a href='?%s'>%s</a>"%(_url,str(obj)) temp.append(mark_safe(s)) link_tags[filter_field]=temp return link_tags HTML: <div class="col-sm-2"> {% for filter_filed,link_tag_list in show_list.get_filter_link_tags.items %} <p>By {{ filter_filed.upper }}</p> {% for link_tag in link_tag_list %} <p>{{ link_tag }}</p> {% endfor %} {% endfor %} </div>