開始今日份整理html
保證django自動的加載每個app下的stark.py文件前端
from django.utils.module_loading import autodiscover_modules class StarkConfig(AppConfig): name = 'stark' def ready(self): autodiscover_modules('stark')
所謂註冊就是仿照admin模塊,對於註冊的數據表進行記錄,方便後面的url的增刪改查java
仿照admin在stark下建立一個包services,並建立一個sites.py文件,代碼以下python
from django.contrib import admin from django.urls import path from django.shortcuts import render,HttpResponse class ModelStark(object): list_display =("__str__") def __init__(self,model): self.model = model def list_view(self, request): return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request, id): return HttpResponse("change_view") def delete_view(self, request, id): return HttpResponse("delete_view") @property def get_url(self,): temp = [ path("", self.list_view), path("add/",self. add_view), path("(\d+)/change/", self.change_view), path("(\d+)/delete/", self.delete_view), ] return (temp, None, None) class StarkSite: def __init__(self): self._registry ={} def register(self,model,admin_class=None,**options): admin_class = admin_class or ModelStark self._registry[model]=admin_class(model) def get_urls(self): temp =[] # 拿到已經註冊的全部表 for model,config_obj in self._registry.items(): # 表名 model_name = model._meta.model_name # 項目名 model_label = model._meta.app_label temp.append( path("%s/%s/"%(model_label,model_name),config_obj.get_url) ) return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
在app01中建立stark.py文件,並註冊數據庫
from stark.services.sites import site,ModelStark from .models import Book,Publish,Author,Author_detail # 分別註冊書籍,出版社以及做者 site.register(Book) site.register(Publish) site.register(Author) print(site._registry)
打印註冊的列表,結果以下django
{<class 'app01.models.Publish'>: <stark.services.sites.ModelStark object at 0x04B66B50>, <class 'app01.models.Book'>: <stark.services.sites.ModelStark object at 0x04B669B0>, <class 'app01.models.Author'>: <stark.services.sites.ModelStark object at 0x04B66970>}
這樣就註冊成功了vim
爲了自定義的URL。因此咱們纔會有自定義頁面,纔會有配置類。app
(1)在site中StarkSite類中建立一個URLS(self)方法,用@property方式,靜態方法ide
(2)將二級分發功能放在配置類模塊中函數
(3)配置類中self以及self.model的區別(超級重要)
self:是配置類對象
self.model:數據表對象,其實就是數據表的數據
經過上面:便可理解爲何在註冊的時候有一個空字典,在每個表對象進行註冊時,對每個表生成對應的配置類對象,若是一個表對象有本身的自定義樣式,則會走本身自定義樣式,無則會走默認樣式。
這樣就基本實現了url的分發功能,有一級也有二級分發。這塊內容就是理解就會以爲東西少,不理解則東西好多!,只須要記住
self是配置類,self.model就是數據表對象就能夠了。
對於默認類,self爲默認配置類,其中self.model爲傳入的表對象,展現則使用默認類中的樣式。
對於自定義類,self爲自定義類,其中self.model爲傳入的表對象,自定義類繼承默認類,優先使用自定義定義的類方法。
以下圖展現
from django.contrib import admin from django.urls import path from django.shortcuts import render,HttpResponse class ModelStark(object): list_display =("__str__") def __init__(self,model): self.model = model def list_view(self, request): return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request, id): return HttpResponse("change_view") def delete_view(self, request, id): return HttpResponse("delete_view") @property def get_url(self,): temp = [ path("", self.list_view), path("add/",self. add_view), path("(\d+)/change/", self.change_view), path("(\d+)/delete/", self.delete_view), ] return (temp, None, None) class StarkSite: def __init__(self): self._registry ={} def register(self,model,admin_class=None,**options): admin_class = admin_class or ModelStark self._registry[model]=admin_class(model) def get_urls(self): temp =[] # 拿到已經註冊的全部表 for model,config_obj in self._registry.items(): # 表名 model_name = model._meta.model_name # 項目名 model_label = model._meta.app_label temp.append( path("%s/%s/"%(model_label,model_name),config_obj.get_url) ) return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
訪問順序
path("stark/app01/book",BookConfig(Book).list_view) path("stark/app01/book/add",BookConfig(Book).add_view) path("stark/app01/publish",ModelAdmin(Publish).list_view) path("stark/app01/publish/add",ModelAdmin(Publish).add_view)
普通數據就是相似於數據庫中book表中的title,price,出版日期,做者等基礎數據,django自然對一對多支持
#目標數據類型 new_data=[ ["python",123], ["java",234] ]
視圖層以下
def list_view(self, request): """ self:當前配置類 self.model:當前訪問的表數據 :param request: :return: """ # 當前要展現的數據表的數據 querset = self.model.objects.all() print(querset) print(self.list_display) # 用於構建視圖中的展現數據 new_data = [] for obj in querset: temp = [] # 構建列表嵌套中的小列表,使用的是自定義配置列表中要展現的內容 for field_or_info in self.list_display: vim = getattr(obj,field_or_info) temp.append(vim) new_data.append(temp) print('new_data', new_data) return render(request,'stark/list_view.html',locals())
模板層以下
對於Book表,是自定義展現配置類,展現以下圖
視圖層以及模板層如上,不過須要注意的是
沒有加逗號,django會默認認爲是一個字符串,並不會以一個元祖來讀取元素,最後致使報錯
對於出版社展現以下,只會展現對象名,顯示名稱是因爲模型類中有__str__方法
在app01中添加展現列表中添加做者這個多對多字段
添加多對多字段
模板展現
最後展現中,做者多對多數據顯示爲none,
(1)知識補充:
使用名字訪問一個model的實例:模型名._meta.get_field("publish")
展現模型類的的名字:模型名._meta.model_name
展現模型類對應的項目名稱:模型名._meta.app_label
展現一個模型類對象的默認名稱:模型對象.verbose_name
對於模型類中的參數,若是設置了verbose.name則會顯示設置的名字,無則顯示參數名稱
(2)多對多的判斷
對於多對多的判斷,首先是導包,對於 list_display來講,普通屬性從self.list_display拿到的是字符串,一對多和多對多則是拿到的對象,拿到對象的類型判斷是不是多對多,若是是多對多則報錯並報錯
對於多對多來講,須要提示爲多對多,須要使用自定義列,彈出錯誤,用於提示錯誤
數據的反射,例如book的出版狀態只有已出版以及未出版,但在數據庫中記錄只有1和2,須要對1和2的內容取出並反射出具體的內容
注:這裏主要使用的是」get_屬性名_display方法」,這樣最後在頁面中展現就會變成以及出版或者是未出版,不在是數據庫中1和2
field_obj = self.model._meta.get_field(field_or_func) #獲取模型對象
這句話,獲取的是模型類中的方法,因爲模型類中沒有__str__方法,因此須要對其進行處理
自定義函數,例如show_author,而後把函數名丟到list_display列表中
stites中獲取返回值,而後加入到列表中傳到前端
注:因爲list_display中有字符串也有函數,因此須要用到callable來判斷是都爲函數名
這裏的self 是類函數調用的方式.,由於原來類中須要穿參,如今增長一個參數而已,什麼都行.可是最好是self
在callable 內容中傳入obj對象,方便操做數據
在自定製配置類中,經過obj 獲取對應的做者信息
非定製列 ,即只有 __str__,只須要返回到數據表名的大寫便可
若是是普通屬性,則只須要丟到對應的head_list列表中便可,對於自定義列,傳入爲函數名的時候則須要對傳入作判斷
app中註冊類書寫
導入mark_safe包
from django.utils.safestring import mark_safe
能夠是後臺傳入的標籤內容不會被轉化,直接成爲前端代碼
導入包
from django.urls import reverse
定義類名以及表名
def __init__(self,model): self.model = model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label
視圖層反向解析,設置name
@property def get_url(self,): # temp = [ # path("", self.list_view), # path("add/",self. add_view), # re_path("(\d+)/change/", self.change_view), # re_path("(\d+)/delete/", self.delete_view), # ] temp = [ path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)), path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)), re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)), re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)), ] return (temp, None, None)
反向解析代碼
# 反向解析當前訪問表的增刪改查URL def get_list_url(self): # 反向解析當前表的查詢的URL list_url = reverse("%s_%s_list" % (self.app_label, self.model_name)) return list_url def get_add_url(self, obj): # 反向解析當前表的添加的URL add_url = reverse("%s_%s_delete" % (self.app_label, self.model_name)) return add_url def get_delete_url(self, obj): # 反向解析當前表的刪除的URL delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return delete_url def get_change_url(self, obj): # 反向解析當前表的修改的URL change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,)) return change_url
分析:反向解析名字爲app名加表名,利用的是無名分組,注意無名分組爲元祖傳參,最後是三個默認列代碼
# 三個默認列 # 選擇框 def show_checkbox(self, obj=None, heade=False): if heade: return mark_safe("<input type='checkbox'>") return mark_safe("<input type='checkbox'>") # 刪除框 def show_delbtn(self, obj=None, heade=False): if heade: return '刪除' # return mark_safe("<a href='stark/app01/book/%s/delete'>刪除</a>" % obj.pk) return mark_safe("<a href='%s'>刪除</a>" % self.get_delete_url(obj)) # 編輯框 def show_editbtn(self, obj=None, heade=False): if heade: return '編輯' # return mark_safe("<a href='stark/app01/book/%s/change'>編輯</a>" % obj.pk) return mark_safe("<a href='%s'>編輯</a>" % self.get_change_url(obj)) ####同時構建新的list_display,若是須要在默認列表中都展現,須要設定新的list_display # 構建新的list_display def get_new_list_display(self): temp = [] temp.extend(self.list_display) temp.append(ModelStark.show_editbtn) temp.append(ModelStark.show_delbtn) temp.insert(0, ModelStark.show_checkbox) return temp
屬性說明:
獲取表頭中,是header =true 這樣能夠獲取表頭數據內容
完整site代碼以下
from django.contrib import admin from django.urls import path,re_path from django.shortcuts import render,HttpResponse from django.utils.safestring import mark_safe from django.urls import reverse class ModelStark(object): list_display =("__str__",) def __init__(self,model): self.model = model self.model_name = self.model._meta.model_name self.app_label = self.model._meta.app_label # 反向解析當前訪問表的增刪改查URL def get_list_url(self): # 反向解析當前表的查詢的URL list_url = reverse("%s_%s_list" % (self.app_label, self.model_name)) return list_url def get_add_url(self, obj): # 反向解析當前表的添加的URL add_url = reverse("%s_%s_delete" % (self.app_label, self.model_name)) return add_url def get_delete_url(self, obj): # 反向解析當前表的刪除的URL delete_url = reverse("%s_%s_delete" % (self.app_label, self.model_name), args=(obj.pk,)) return delete_url def get_change_url(self, obj): # 反向解析當前表的修改的URL change_url = reverse("%s_%s_change" % (self.app_label, self.model_name), args=(obj.pk,)) return change_url # 三個默認列 # 選擇框 def show_checkbox(self, obj=None, heade=False): if heade: return mark_safe("<input type='checkbox'>") return mark_safe("<input type='checkbox'>") # 刪除框 def show_delbtn(self, obj=None, heade=False): if heade: return '刪除' # return mark_safe("<a href='stark/app01/book/%s/delete'>刪除</a>" % obj.pk) return mark_safe("<a href='%s'>刪除</a>" % self.get_delete_url(obj)) # 編輯框 def show_editbtn(self, obj=None, heade=False): if heade: return '編輯' # return mark_safe("<a href='stark/app01/book/%s/change'>編輯</a>" % obj.pk) return mark_safe("<a href='%s'>編輯</a>" % self.get_change_url(obj)) # 構建新的list_display def get_new_list_display(self): temp = [] temp.extend(self.list_display) temp.append(ModelStark.show_editbtn) temp.append(ModelStark.show_delbtn) temp.insert(0, ModelStark.show_checkbox) return temp # 視圖函數 def list_view(self, request): """ self:當前配置類 selfmodel:當前訪問的表數據 :param request: :return: """ # 當前訪問表的數據 querset = self.model.objects.all() print(querset) print(self.list_display) #用於展現頭部文件 header_list=[] for field_or_info in self.get_new_list_display(): #判斷是函數名或者是字符段 if callable(field_or_info): vim=field_or_info(self,heade=True) header_list.append(vim) else: # 獲取指定字段的對象屬性,並拿出verbose_name屬性 if field_or_info=='__str__': #若是隻有默認裝飾類,只有__str__,則拿出他的表名做爲頭 vim = self.model._meta.model_name.upper() else: file_obj =self.model._meta.get_field(field_or_info) vim = file_obj.verbose_name header_list.append(vim) #用於構建視圖中的展現數據 new_data=[] for obj in querset: temp=[] for field_or_info in self.get_new_list_display(): # 判斷是函數仍是字符段 if callable(field_or_info): vim = field_or_info(self,obj) else: try: from django.db.models.fields.related import ManyToManyField info_obj=self.model._meta.get_field(field_or_info) # 判斷多對多字段 if type(info_obj)==ManyToManyField: raise Exception("list_distplay 不能是多很少字段") #判斷是不是__str__ # if field_or_info=='__str': # vim=getattr(obj,field_or_info)() # 判斷是否有choices字段 if info_obj.choices: vim = getattr(obj,'get_%s_display'%field_or_info)() else: vim =getattr(obj,field_or_info) except Exception as e: vim = getattr(obj, field_or_info)() temp.append(vim) new_data.append(temp) print('new_data',new_data) # 目標數據 # new_data=[ # ["python",123], # ["java",234] # ] return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request, id): return HttpResponse("change_view") def delete_view(self, request, id): return HttpResponse("delete_view") @property def get_url(self,): # temp = [ # path("", self.list_view), # path("add/",self. add_view), # re_path("(\d+)/change/", self.change_view), # re_path("(\d+)/delete/", self.delete_view), # ] temp = [ path("", self.list_view, name="%s_%s_list" % (self.app_label, self.model_name)), path("add/", self.add_view, name="%s_%s_add" % (self.app_label, self.model_name)), re_path("(\d+)/change/", self.change_view, name="%s_%s_change" % (self.app_label, self.model_name)), re_path("(\d+)/delete/", self.delete_view, name="%s_%s_delete" % (self.app_label, self.model_name)), ] return (temp, None, None) class StarkSite: def __init__(self): self._registry ={} def register(self,model,admin_class=None,**options): admin_class = admin_class or ModelStark self._registry[model]=admin_class(model) def get_urls(self): temp =[] # 拿到已經註冊的全部表 for model,config_obj in self._registry.items(): # 表名 model_name = model._meta.model_name # 項目名 model_label = model._meta.app_label temp.append( path("%s/%s/"%(model_label,model_name),config_obj.get_url) ) return temp @property def urls(self): return self.get_urls(),None,None site = StarkSite()
完整註冊stark代碼以下
from stark.services.sites import site,ModelStark from .models import * from django.utils.safestring import mark_safe class BookConfig(ModelStark): def show_authors(self,obj=None,heade=False): if heade: return "做者信息" return " ".join([author.name for author in obj.author.all()]) # # 選擇框 # def show_checkbox(self,obj=None,heade=False): # if heade: # return mark_safe("<input type='checkbox'>") # return mark_safe("<input type='checkbox'>") # # # 刪除框 # def show_delbtn(self, obj=None, heade=False): # if heade: # return '刪除' # return mark_safe("<a href='stark/app01/book/%s/delete'>刪除</a>"%obj.pk) # # # 編輯框 # def show_editbtn(self, obj=None, heade=False): # if heade: # return '編輯' # return mark_safe("<a href='stark/app01/book/%s/change'>編輯</a>" % obj.pk) list_display=["title","price","staes","publish",show_authors] # list_display=["title","price","staes","publish"] site.register(Book,BookConfig) site.register(Publish) print(site._registry)
a