Django 的 Admin

Django 非常好用的一個(gè)功能就是后臺(tái)界面的自動(dòng)管理。

from django.contrib import admin

from django.utils.safestring import mark_safe
class xxxConfig(admin.ModelAdmin):
    
    def deletes(self):
        return mark_safe('<a href=''>刪除</a>')
    
    list_display = [, deletes] # 里面的字段不能是 ManyToMany 字段
    list_filter = ()
    list_display_links = ()
    search_fields = ()
    
    def patch_init(self, request, queryset):
        queryset.update(xxx=xxx)
    patch_init.short_description = "批量處理"
    actions = [patch_init, ]
所有字段都在 admin.ModelAdmin 中可見
admin.site.register(模型, '你自定義的類')

Admin 的實(shí)現(xiàn)流程:?jiǎn)?dòng),注冊(cè),設(shè)計(jì)url

  • 啟動(dòng)
    INSTALLED_APPS 中的注冊(cè) app 中,掃描 admin 文件,并執(zhí)行
def autodiscover():
    autodiscover_modules('admin', register_to=site)
  • 注冊(cè),在每個(gè)安裝的 app 下面的 admin 文件中注冊(cè) site,即admin.site.register(模型, '你自定義的類')
  • 設(shè)計(jì) url
    在項(xiàng)目的根目錄下 url 文件中會(huì)有 path('admin/', admin.site.urls), 這么一行注冊(cè) url 的函數(shù)
    綜上,其實(shí)這是很明顯的一個(gè)單例模式,因?yàn)楹髢刹街卸加玫搅艘粋€(gè)特殊的對(duì)象 admin.site,admin 是從 django.contrib 中導(dǎo)入的,而 admin 中又導(dǎo)入了 sitefrom django.contrib.admin.sites import AdminSite, site,之后進(jìn)入到 site 中,發(fā)現(xiàn)了也就這么一個(gè)東西:
class AdminSite:
    pass

site = AdminSite()

這其實(shí)用到了 Python 中對(duì)于單例模式的一個(gè)經(jīng)典的用法,模塊就是一個(gè)特殊的單例,因?yàn)槟K無論聲明多少次,最終導(dǎo)入到 Python 解釋器中只會(huì)有一次,就是剛開始那次。

接下來我們看一看源碼做了什么?

# admin 的 __init__.py
from django.contrib.admin.sites import AdminSite, site
def autodiscover():
    autodiscover_modules('admin', register_to=site)

這里隨即進(jìn)入 AdminSite:

# sites.py
pass
class AdminSite:
    def __init__(self, name='admin'):
        self._registry = {}  # model_class class -> admin_class instance
        self.name = name
        pass

    def register(self, model_or_iterable, admin_class=None, **options):
        if not admin_class:
            admin_class = ModelAdmin
        pass

site = AdminSite()

注意這里的 site = AdminSite(),在 Django 的其它地方導(dǎo)入它以后,它就是一個(gè)單例了,它的 id 就不變了。在 AdminSite 中定義了一個(gè)字典 _registry,里面存放的是注冊(cè)的 model 和 其配置類,配置類默認(rèn)是 ModelAdmin,也就是 Django 自己的那個(gè)后臺(tái)。這里完成了 url 的注冊(cè)。
接下來看一看它里面是如何構(gòu)造 url 的。還記得在項(xiàng)目根目錄下的 url(r'admin', admin.site.urls),嗎,進(jìn)入它:

# 跟上面的一樣是 sites.py
def get_urls(self):
    pass
    for model, model_admin in self._registry.items():
     urlpatterns += [
        path('%s/%s/' % (model._meta.app_label, model._meta.model_name), include(model_admin.urls)),
            ]
    if model._meta.app_label not in valid_app_labels:
        valid_app_labels.append(model._meta.app_label)
    return urlpatterns

@property
def urls(self):
    return self.get_urls(), 'admin', self.name

這里面 include(model_admin.urls) 及其重要,Django 默認(rèn)將自己的配置類注冊(cè)到 _register 了,它是 ModelAdminurls

# 注:這是 Django 2 的有些部分可能不一樣,不過不影響
def get_urls(self):
    pass
    info = self.model._meta.app_label, self.model._meta.model_name

    urlpatterns = [
        path('', wrap(self.changelist_view), name='%s_%s_changelist' % info),
        path('add/', wrap(self.add_view), name='%s_%s_add' % info),
        path('autocomplete/', wrap(self.autocomplete_view), name='%s_%s_autocomplete' % info),
        path('<path:object_id>/history/', wrap(self.history_view), name='%s_%s_history' % info),
        path('<path:object_id>/delete/', wrap(self.delete_view), name='%s_%s_delete' % info),
        path('<path:object_id>/change/', wrap(self.change_view), name='%s_%s_change' % info),
        # For backwards compatibility (was the change url before 1.9)
        path('<path:object_id>/', wrap(RedirectView.as_view(
            pattern_name='%s:%s_%s_change' % ((self.admin_site.name,) + info)
        ))),
    ]
    return urlpatterns

@property
def urls(self):
    return self.get_urls()

這里重要的是 Django 對(duì) url 做了兩級(jí)分發(fā),而且這兩級(jí) url 不在同一個(gè)類中,這樣做的目的就是為了方便構(gòu)造模板。最后那一級(jí) url 放在了 ModelAdmin 中,就是增刪改查那四個(gè)功能。

說明:這里二級(jí)分發(fā) url 主要是為了方便后面模板構(gòu)造數(shù)據(jù),因?yàn)闃?gòu)造數(shù)據(jù)要訪問 model,如果兩級(jí) url 全部放在一個(gè)類中,那么需要找到 model 便需要根據(jù) url 來匹配,但是將二級(jí) url 放在默認(rèn)的類中,那么它便可以找到對(duì)應(yīng)的 model 了,因?yàn)?_register 中存放的是 model 和 配置類形成的字典。而默認(rèn)配置類里面會(huì)注冊(cè)進(jìn)來 對(duì)應(yīng)的 model,所以在配置類中可以找到 model。

先暫時(shí)到這,可能有諸多不清楚的,后面再補(bǔ)充。
順便說一句,AdminSite 的源碼連注釋,加空行總共 500 行代碼,有空了解一下。??

Django 是如何找到每個(gè) app 下的 admin.py 文件呢,在每個(gè) app 下都有一個(gè)配置類,如 admin 的 AdminConfig,它里面會(huì)定義一個(gè) ready 方法,django 在加載 INSTALLED_APPS 時(shí),會(huì)調(diào)用里面的方法。

class AdminConfig(SimpleAdminConfig):
    def ready(self):
        super().ready()
        self.module.autodiscover()

在我們自己構(gòu)建組件時(shí),可以這樣寫:

from django.apps improt AppConfig
from django.uitls.moudle_loading improt autodiscover_moudles

class xxxConfig(AppConfig):
    name = xxx
    def ready(self):
        autodiscover_moudles('里面放需要加載文件的名稱')

設(shè)計(jì) url

首先來了解一下 url 注冊(cè)的另一種方式:

def test01(request):
    return HttpResponse('test01')
def test02(request):
    pass
def test03(request):
    pass

urlpatterns = [
    url(r'^test/', ([
        url(r't1/', test01),
        url(r't2/', test02),
        url(r't3/', test03),
    ], None, None))
]

這種相當(dāng)于是將 include 中的 url 放到當(dāng)前 url 中了。
構(gòu)造 url:

get_urls2():
    temp = []
    temp.append(url(r'^$'), view_name)
    temp.append(url(r'^add$'), view_name)
    temp.append(url(r'^(\d+)/change/$'), view_name)
     temp.append(url(r'^(\d+)/delete/$'), view_name)
    return temp

def get_urls():
    res = []
    for model, admin_class_obj in admin.site_register.items():
        app_name = model._meta.app_label
        model_name = model._meta.model_name
        temp.append(url(r'{0}/{1}'.format(app_name, model_name), (get_urls2(), None, None)), )
    return res

urlpatterns = [
    url(r'^xadmin/', (get_urls(), None, None)),
]

以上有幾個(gè)函數(shù)很有趣:
model._meta.app_label --> 獲取模型所屬 app 的名稱字符串
model._meta.model_name --> 獲取模型名稱字符串
obj = model._meta.get_field("field") --> 獲取模型內(nèi)某個(gè)屬性,別忘記,其實(shí)模型內(nèi)的屬性也是一個(gè)類
所以:obj.verbose_name 即可取到其對(duì)應(yīng)的屬性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 由于django后臺(tái)管理沒有富文本編輯器,展示出來的頁(yè)面不美觀,所以我們想要引入第三方富文本編輯器。網(wǎng)上搜尋了一番...
    longshelan_113閱讀 683評(píng)論 0 1
  • 切換到創(chuàng)建項(xiàng)目的目錄 cd C:\Users\admin\Desktop\DjangoProject創(chuàng)建名為pr...
    在努力中閱讀 3,539評(píng)論 2 3
  • Web框架之Django: (1)簡(jiǎn)介: Django是一個(gè)由Python寫成開源的重量級(jí)Web應(yīng)用框架,采用MT...
    老肖閱讀 3,167評(píng)論 0 18
  • The Django admin site Django中一個(gè)最強(qiáng)大的部分是自動(dòng)管理接口,在模型中讀取元數(shù)據(jù)來提供...
    常大鵬閱讀 29,618評(píng)論 2 18
  • 成長(zhǎng)慢原因:過分關(guān)注能得到的,對(duì)于輸出自己的價(jià)值投入太少。 改變:表達(dá)自己所思所想,以及收集別人的反饋。試著勇敢去...
    阿瀘姑娘閱讀 121評(píng)論 0 0

友情鏈接更多精彩內(nèi)容