您好,登錄后才能下訂單哦!
本篇文章為大家展示了Django中自定義admin Xadmin的實現,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
1,啟動
我們可以通過from django.contrib import admin
來看admin是如何啟動的
Django啟動后,會在manage.py文件中加載配置文件settings.py ,在settings.py中有一個INSTALLED_APPS這個配置項,Django會按照配置項的內容一次加載每一個app.
# Application definition INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'Xadmin.apps.XadminConfig', 'blogs.apps.BlogsConfig', 'bigs.apps.BigsConfig', ]
加載到django.contrib.admin
時,會加載admin相關的,我們點擊admin,進入admin的__init__.py文件,
from django.contrib.admin.sites import AdminSite, site from django.utils.module_loading import autodiscover_modules def autodiscover(): autodiscover_modules('admin', register_to=site)
執行auto_discover這個接口,會自動的加載所有APP中的admin.py
這個文件,這就是admin的啟動文件
2,注冊
自動加載所有APP下的admin.py文件時,會一次記錄所有執行了admin.site.register(模型類)這個方法的模型類,從而完成模型類的注冊。
所有的模型類都執行admin.site.register()
這個方法后完成的注冊,那么這個方法內部都做了些什么?
我們可以點擊site進入admin的源碼中,得到這個:site = AdminSite() site是一個對象,是AdminSite這個類的一個對象,并且是一個單例對象,那么我們就可以肯定,register是這個單例對象的一個方法,那這個方法中到底做了什么?
class AdminSite(object): """ An AdminSite object encapsulates an instance of the Django admin application, ready to be hooked in to your URLconf. Models are registered with the AdminSite using the register() method, and the get_urls() method can then be used to access Django view functions that present a full admin interface for the collection of registered models. """ def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance self.name = name # 關于register的方法 def register(self, model_or_iterable, admin_class=None, **options): if not admin_class: admin_class = ModelAdmin # Instantiate the admin class to save in the registry self._registry[model] = admin_class(model, self) #備注:截取的源碼中的一部分
示例site對象時,會生成一個self._registry={}
這個對象屬性,如果我們沒有指定admin_class,那么admin_class就是ModelAdmin,由此可以看出,admin_class
是admin提供給我們定制頁面的一個自定義類,這個類必須繼承ModelAdmin這個類,以下是:
class ModelAdmin(BaseModelAdmin): "Encapsulates all admin options and functionality for a given model." list_display = ('__str__',) list_display_links = () list_filter = () list_select_related = False list_per_page = 100 list_max_show_all = 200 list_editable = () search_fields = () date_hierarchy = None save_as = False save_as_continue = True save_on_top = False paginator = Paginator preserve_filters = True inlines = [] # Custom templates (designed to be over-ridden in subclasses) add_form_template = None change_form_template = None change_list_template = None delete_confirmation_template = None delete_selected_confirmation_template = None object_history_template = None popup_response_template = None # Actions actions = [] action_form = helpers.ActionForm actions_on_top = True actions_on_bottom = False actions_selection_counter = True checks_class = ModelAdminChecks def __init__(self, model, admin_site): self.model = model self.opts = model._meta self.admin_site = admin_site super(ModelAdmin, self).__init__() def __str__(self): return "%s.%s" % (self.model._meta.app_label, self.__class__.__name__)
所以不管有沒有自定制樣式類,都會執行self._registry[model] = admin_class(model, self),
也就是說,注冊一個模型類,就會在對象的_registry這個字典中添加一個鍵值對,這個鍵是我們注冊的這個模型類 model,值是繼承ModelAdmin的樣式類或者ModelAdmin這個類的一個對象。
3,設計url
因為site是一個單例對象,所以admin在執行完所有admin.py文件后,就會得到整個全局的一個包含所有注冊模型的字典_registry,得到這個self._registry(也就是admin.site對象)字典,我們可以for循環這個admin.site._registry字典,得到這些鍵值對,那么得到這些鍵值對有什么用呢?這就是admin設計url時會用到的。
我們訪問admin這個后臺管理頁面會發現,這個頁面關于我們注冊的所有模型都會實現增刪改查功能,每個功能界面對應不同的模型類時,除了數據不同外,是一樣的,也就是說,admin對于不同的模型類用到是一套url,一套模板,那么這個url是怎么設計的呢?
我們分別訪問不同的模型類的這四個功能頁面,會發現一個規律:
查詢頁面url: http://IP:PORT/admin/app名/模型類的名字(全部小寫)/
添加頁面url: http://IP:PORT/admin/app名/模型類的名字(全部小寫)/add
編輯頁面url:http://IP:PORT/admin/app名/模型類的名字(全部小寫)/id值/change
刪除頁面url:http://IP:PORT/admin/app名/模型類的名字(全部小寫)/id值/delete
通過這個規律可以看出url分發的實現
但是在這個實現的過程中,我們有一個需要注意的時,用戶訪問的請求攜帶的路徑是一個字符串的類型,我們可以通過request.path得到用戶訪問的路徑,也就能得到用戶訪問的是哪個APP下的哪個模型類,但是這兩個參數都是字符串的類型,如何通過字符串得到用戶訪問的哪張表,這是個麻煩,這時,可能我們會想到使用importlib模塊來得到這個類,但是,這樣這個過程很麻煩,Django為我們封裝好了相應的方法:我們可以通過這個模型類的類名,通過._meta.model_name這個方法得到對應的字符串形式的類名,同樣的我們也可以通過這個類名._meta.app_label得到字符串格式的相應的APP名
# 使用model代指模型類的類名 model._meta.model_name #得到字符串格式的類名(全小寫的) model._meta.app_label #可以得到當前類所在APP的字符串的名字 # 補充 model._meta.get_field("字符串格式的字段屬性") # 得到一個字段屬性的對象field_obj,這樣我們就可以利用這個字段對象取得屬性 # 比如: field_obj.verbose_name
通過這兩個封裝的方法,就完美的解決了我們頭疼的問題
from django.conf.urls import url from django.contrib import admin def get_urls_operate(): emp = [] emp.append(url(r'^$',查詢頁面的視圖函數)) emp.append(url(r'^add/$',添加頁面的視圖函數)) emp.append(url(r'^(\d+)/change/$',編輯頁面的視圖函數)) emp.append(url(r'^(\d+)/delete/$',刪除頁面的視圖函數)) return emp def get_urls(): temp = [] for model,main_class_obj in admin.site._registry.items(): app_name = model._meta.app_label model_name = model._meta.model_name temp.append(url(r'^{}/{}/'.format(app_name,model_name),(get_urls_operate(),None,None))) #實現第二層路由的分發 return temp urlpatterns = [ url(r'^Xadmin/',(get_urls(),None,None)) #自定義一個前綴 實現第一層路由的分發 ]
這樣我們就實現一個通過一個路由實現不同場景的分發
通過這三部分,我們可以按照admin的實現方式,來自定制Xadmin
我們了解了admin內部的實現流程,我們可以將這個實現過程封裝到一個類中。
我們自定制Xadmin時,也要按照admin的流程實現,首先是啟動項,admin中,Django啟動時,會自動的執行每個app下的admin.py文件,我們可以自定制為啟動時,自動執行app下的每個自定制的.py文件,比如Xadmin.py 文件,那么如何達到Django啟動的時候幫我們自動掃描加載我們自定制的Xadmin.py文件呢?這是個問題
我們觀察可以發現,Django在啟動時,會加載配置文件settings.py ,在settings.py文件中,有一個INSTALLED_APPS這個列表,這個列表中,放置著我們在Django項目中的所有app的配置信息,我們觀察這個列表:我們自己開啟的APP,在設置配置信息時,會在APP名字后加一個.apps.(app名首字母大寫)Config這個東西,而對應的在我們的app下,Django會給我們自動的配置一個apps.py文件,那么這個apps.py文件有什么作用呢,我們打開這個apps.py文件,看看里面的配置信息:
以blogs這個APP為例:
from django.apps import AppConfig class BlogsConfig(AppConfig): name = 'blogs'
我們可以發現,里面定義了一個類,這個類的類名就是settings配置信息中apps后面跟的那個東東,這個類中有一個靜態屬性name是當前的APP名,這個類繼承了AppConfig這個類。這就是我們從這個.py文件中所能得的所有東西,乍一看,沒有什么有用的信息,那么我們只能從它繼承的類中找了
MODELS_MODULE_NAME = 'models' class AppConfig(object): """ Class representing a Django application and its configuration. """ def __init__(self, app_name, app_module): # Full Python path to the application eg. 'django.contrib.admin'. self.name = app_name def ready(self): """ Override this method in subclasses to run code when Django starts. #這句話的語義為:在子類中重寫此方法,以便在Django啟動時運行代碼 """
查看整個AppConfig,我們可以把我們的要啟動的代碼放置在重寫的ready方法中即可
from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class XadminConfig(AppConfig): name = 'Xadmin' def ready(self): autodiscover_modules('Xadmin') #Django啟動時會自動掃描每個app下的Xadmin.py文件
這樣,我們就完成了自定制Xadmin的啟動階段,啟動后我們就要進行下一步注冊
在每個app下的Xadmin.py 文件中注冊模型
以blogs這個APP下的UserInfo、Book為例:
from blogs import models from Xadmin.service.Xadmin import site site.register(models.UserInfo) site.register(models.Book)
接下了就是設計url了,我們可以仿照admin的方式,在單例對象admin.site的這個類中封裝好這些方法
from django.conf.urls import url from django.shortcuts import HttpResponse,render class ModelXadmin(object): def __init__(self,model,site): self.model = model self.site = site def show(self,request): data_list = self.model.objects.all() return render(request,'show.html',locals()) #locals() 請函數內部所有的鍵值對存儲 == {"data_list":data_list} def add(self,request): return HttpResponse('添加頁面') def edit(self,request, pk): return HttpResponse('編輯頁面') def delete(self,request, pk): return HttpResponse('刪除頁面') @property def get_urls_operate(self): emp = [] emp.append(url(r'^$', self.show)) emp.append(url(r'^add/$', self.add)) emp.append(url(r'^(\d+)/change/$', self.edit)) emp.append(url(r'^(\d+)/delete/$', self.delete)) return emp @property def urls(self): return self.get_urls_operate,None,None class XadminSite(object): def __init__(self,name='xadmin'): self._registry = {} def register(self,model,class_main=None,**option): if not class_main: class_main = ModelXadmin self._registry[model] = class_main(model,self) @property def get_urls(self): # print(admin.site._registry) temp = [] for model, model_admin_object in self._registry.items(): model_name = model._meta.model_name model_app = model._meta.app_label temp.append(url(r'^{}/{}/'.format(model_app, model_name), model_admin_object.urls)) return temp @property def urls(self): return self.get_urls,None,None site = XadminSite()
備注:一個關鍵點,為什么把第二層分發設置在了ModelXadmin這個類中,那肯定是放在這個類中能有什么好處,如果我們把這個二級分發放在XadminSite中,那么我們要取得每一個模型的數據是很麻煩的,但是,如果我們把這個放在ModelXadmin中,由于,在register(注冊)時,我們給class_admin(XadminSite)傳了每一個模型類,所以放在這個類中,我們可以通過self.model這個屬性獲得每個模型類的數據(self.model.objects.all()
),這樣就很容易得到這個模型表。
上述內容就是Django中自定義admin Xadmin的實現,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。