Django 內置的admin是對於model中對應的數據表進行增刪改查提供的組建
一.Django admin的內部依賴:
依賴的app
django.contrib.auth
django.contrib.contenttypes
django.contrib.messages
django.contrib.sessions

模版:
django.contrib.auth.context_processors.auth
django.contrib.messages.context_processors.messages

中間件:
django.contrib.auth.middleware.AuthenticationMiddleware
django.contrib.messages.middleware.MessageMiddleware

二:配置路由
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), ]
當前配置的路由可以創建一些路由映射關系:
/admin/
/admin/login/
/admin/logout/
/admin/password_change/
/admin/password_change/done/
/admin/app名稱/model名稱/
/admin/app名稱/model名稱/add/
/admin/app名稱/model名稱/ID值/history/
/admin/app名稱/model名稱/ID值/change/
/admin/app名稱/model名稱/ID值/delete/
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. """ # Text to put at the end of each page's <title>. site_title = ugettext_lazy('Django site admin') # Text to put in each page's <h1>. site_header = ugettext_lazy('Django administration') # Text to put at the top of the admin index page. index_title = ugettext_lazy('Site administration') # URL for the "View site" link at the top of each admin page. site_url = '/' _empty_value_display = '-' login_form = None index_template = None app_index_template = None login_template = None logout_template = None password_change_template = None password_change_done_template = None def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance self.name = name self._actions = {'delete_selected': actions.delete_selected} self._global_actions = self._actions.copy() all_sites.add(self) def register(self, model_or_iterable, admin_class=None, **options): """ Registers the given model(s) with the given admin class. The model(s) should be Model classes, not instances. If an admin class isn't given, it will use ModelAdmin (the default admin options). If keyword arguments are given -- e.g., list_display -- they'll be applied as options to the admin class. If a model is already registered, this will raise AlreadyRegistered. If a model is abstract, this will raise ImproperlyConfigured. """ if not admin_class: admin_class = ModelAdmin if isinstance(model_or_iterable, ModelBase): model_or_iterable = [model_or_iterable] for model in model_or_iterable: if model._meta.abstract: raise ImproperlyConfigured( 'The model %s is abstract, so it cannot be registered with admin.' % model.__name__ ) if model in self._registry: raise AlreadyRegistered('The model %s is already registered' % model.__name__) # Ignore the registration if the model has been # swapped out. if not model._meta.swapped: # If we got **options then dynamically construct a subclass of # admin_class with those **options. if options: # For reasons I don't quite understand, without a __module__ # the created class appears to "live" in the wrong place, # which causes issues later on. options['__module__'] = __name__ admin_class = type("%sAdmin" % model.__name__, (admin_class,), options) # Instantiate the admin class to save in the registry self._registry[model] = admin_class(model, self) def get_urls(self): from django.conf.urls import url, include # Since this module gets imported in the application's root package, # it cannot import models from other applications at the module level, # and django.contrib.contenttypes.views imports ContentType. from django.contrib.contenttypes import views as contenttype_views def wrap(view, cacheable=False): def wrapper(*args, **kwargs): return self.admin_view(view, cacheable)(*args, **kwargs) wrapper.admin_site = self return update_wrapper(wrapper, view) # Admin-site-wide views. urlpatterns = [ url(r'^$', wrap(self.index), name='index'), url(r'^login/$', self.login, name='login'), url(r'^logout/$', wrap(self.logout), name='logout'), url(r'^password_change/$', wrap(self.password_change, cacheable=True), name='password_change'), url(r'^password_change/done/$', wrap(self.password_change_done, cacheable=True), name='password_change_done'), url(r'^jsi18n/$', wrap(self.i18n_javascript, cacheable=True), name='jsi18n'), url(r'^r/(?P<content_type_id>\d+)/(?P<object_id>.+)/$', wrap(contenttype_views.shortcut), name='view_on_site'), ] # Add in each model's views, and create a list of valid URLS for the # app_index valid_app_labels = [] for model, model_admin in self._registry.items(): urlpatterns += [ url(r'^%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) # If there were ModelAdmins registered, we should have a list of app # labels for which we need to allow access to the app_index view, if valid_app_labels: regex = r'^(?P<app_label>' + '|'.join(valid_app_labels) + ')/$' urlpatterns += [ url(regex, wrap(self.app_index), name='app_list'), ] return urlpatterns @property def urls(self): return self.get_urls(), 'admin', self.name
option.py BaseModelAdmin類 def get_urls(self): from django.conf.urls import url def wrap(view): def wrapper(*args, **kwargs): return self.admin_site.admin_view(view)(*args, **kwargs) wrapper.model_admin = self return update_wrapper(wrapper, view) info = self.model._meta.app_label, self.model._meta.model_name urlpatterns = [ url(r'^$', wrap(self.changelist_view), name='%s_%s_changelist' % info), url(r'^add/$', wrap(self.add_view), name='%s_%s_add' % info), url(r'^(.+)/history/$', wrap(self.history_view), name='%s_%s_history' % info), url(r'^(.+)/delete/$', wrap(self.delete_view), name='%s_%s_delete' % info), url(r'^(.+)/change/$', wrap(self.change_view), name='%s_%s_change' % info), # For backwards compatibility (was the change url before 1.9) url(r'^(.+)/$', 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()
三:定制admin
在admin.py中只需注冊某個類,即可在admin中實現增刪改查的功能。
admin.site.register(UserInfo)
為類定制更多的信息,需為其定制modelAdmin
1.應用方式:
#方式一:裝飾器 @admin.register(UserInfo) class UserAdmin(admin.ModelAdmin): list_display = ['name','nickname','email'] #方式二:參數傳入 # admin.site.register(UserInfo,UserAdmin)
2.定制功能:
list_display,列表時,定制顯示的列。
list_display 有四種賦值方式:
#模型的字段 class PersonAdmin(admin.ModelAdmin): list_display = ('first_name', 'last_name') #一個接受對象實例作為參數的可調用對象 def upper_case_name(obj): return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = 'Name' class PersonAdmin(admin.ModelAdmin): list_display = (upper_case_name,) #一個表示ModelAdmin 中某個屬性的字符串。行為與可調用對象相同 class PersonAdmin(admin.ModelAdmin): list_display = ('upper_case_name',) def upper_case_name(self, obj): return ("%s %s" % (obj.first_name, obj.last_name)).upper() upper_case_name.short_description = 'Name' #表示模型中某個屬性的字符串。它的行為與可調用對象幾乎相同,但這時的self 是模型實例。 from django.db import models from django.contrib import admin class Person(models.Model): name = models.CharField(max_length=50) birthday = models.DateField() def decade_born_in(self): return self.birthday.strftime('%Y')[:3] + "0's" decade_born_in.short_description = 'Birth decade' class PersonAdmin(admin.ModelAdmin): list_display = ('name', 'decade_born_in')
實例:
@admin.register(UserInfo) class UserAdmin(admin.ModelAdmin): list_display = ['name','nickname','email','xxx'] list_display_links = ('nickname',) def xxx(self,obj): a = '<a href="www.baidu.com>點擊跳轉</a>' return mark_safe(a)

list_display_links,指定列表顯示的哪列可以點擊跳轉,定制列可以點擊跳轉。

list_filter 設置激活激活Admin 修改列表頁面右側欄中的過濾器

#字段名稱,其指定的字段應該是BooleanField、CharField、DateField、DateTimeField、#IntegerField、ForeignKey 或ManyToManyField, class UserAdmin(admin.ModelAdmin): list_filter = ('group','roles') #list_filter 中的字段名稱也可以使用__ 查找跨關聯關系 list_filter = ('group__title','roles') #一個繼承自django.contrib.admin.SimpleListFilter 的類,你需要給它提供title 和 parameter_name 屬性來重寫lookups 和queryset 方法 from django.contrib import admin from app01.models import * from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ class Ugg(admin.SimpleListFilter): title = _('decade born') parameter_name = 'xxxxxx' def lookups(self, request, model_admin): """ 顯示篩選選項 :param request: :param model_admin: :return: """ return UserGroup.objects.values_list('id', 'title') def queryset(self, request, queryset): """ 點擊查詢時,進行篩選 :param request: :param queryset: :return: """ v = self.value() return queryset list_filter = ('group',Ugg) #一個元組,第一個元素是字段名稱,第二個元素是從繼承自django.contrib.admin.FieldListFilter 的一個類 class PersonAdmin(admin.ModelAdmin): list_filter = ( ('is_staff', admin.BooleanFieldListFilter), )
list_select_related,設置list_select_related以告訴Django在檢索管理更改列表頁面上的對象列表時使用 select_ralated。這可以節省大量的數據庫查詢。該值應該是布爾值,列表或元組。默認值為False。
list_select_related = ['group']
list_max_show_all 控制在“顯示所有”管理更改列表頁面上可以顯示的項目數,默認情況下,設置為200。
list_per_page. 設置控制Admin 修改列表頁面每頁中顯示多少項。默認設置為100。
ordering以指定如何在Django管理視圖中對對象列表進行排序
ordering = ['-id', ]. 從大到小 ordering = ['id', ]. 從小到大
paginator 默認情況下,使用django.core.paginator.Paginator
prepopulated_fields設置為將字段名稱映射到其應預先填充的字段的字典:
prepopulated_fields = {'name':('nickname','email')} #nickname 和email和name的值相同
prepopulated_fields不接受DateTimeField,ForeignKey或ManyToManyField字段。
list_editable指定列表中可以編輯的列
list_editable = ('name',)

-
search_fields,模糊搜索時列表中的搜索列范圍,
search_fields = ('namer', 'email')

date_hierarchy,列表時,對Date和DateTime類型進行搜索
preserve_filters,詳細頁面,刪除、修改,更新后跳轉回列表后,是否保留原搜索條件
save_as = False,詳細頁面,按鈕為“Sava as new” 或 “Sava and add another”
save_as_continue = True,點擊保存並繼續編輯
save_on_top = False,詳細頁面,在頁面上方是否也顯示保存刪除等按鈕
fields,詳細頁面時,顯示字段的字段
exclude,詳細頁面時,排除的字段
readonly_fields,詳細頁面時,只讀字段
fieldsets,詳細頁面時,使用fieldsets標簽對數據進行分組顯示
fieldsets = ( ('基本數據', { 'fields': ('name', ) }), ('其他', { 'classes': ('collapse', 'wide', 'extrapretty'), # 'collapse','wide', 'extrapretty' 'fields': ('email','group',), }), )

多對多或一對多顯示時添加數據移動選擇(方向:上下和左右)
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)

inlines,詳細頁面,如果有其他表和當前表做FK,那么詳細頁面可以進行動態增加和刪除
inlines 關聯的類必須繼承:StackedInline,且放在外鍵的類里
class UserInfoInline(admin.StackedInline): # TabularInline extra = 0 model = UserInfo class UserGropuAdmin(admin.ModelAdmin): inlines = [UserInfoInline,]

action 定制action中的操作
def func(self, request, queryset): (必須有request,queryset參數) print(self, request, queryset) print(request.POST.getlist('_selected_action')) func.short_description = "中文顯示自定義Actions" actions = [func, ] # Action選項都是在頁面上方顯示 actions_on_top = True # Action選項都是在頁面下方顯示 actions_on_bottom = False # 是否顯示選擇個數 actions_selection_counter = True

在整個站點應用該操作:
from django.contrib import admin admin.site.add_action(fund)
為全局ModelAdmin禁用某個操作
admin.site.disable_action('delete_selected')
為特定的ModelAdmin禁用所有操作ModelAdmin
class MyModelAdmin(admin.ModelAdmin): actions = None
按需啟用或禁用操作
class MyModelAdmin(admin.ModelAdmin): ... def get_actions(self, request): actions = super(MyModelAdmin, self).get_actions(request) if request.user.username[0].upper() != 'J': if 'delete_selected' in actions: del actions['delete_selected'] return actions
定制HTML模板
Admin模板文件位於contrib/admin/templates/admin 目錄中。
為一個特定的app重寫admin模板, 需要拷貝django/contrib/admin/templates/admin 目錄到你剛才創 建的目錄下, 並且修改它們.
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

view_on_site,編輯時,是否在頁面上顯示view on setview_on_site = False 或 def view_on_site(self, obj): return 'https://www.baidu.com'
radio_fields,詳細頁面時,使用radio顯示選項(FK默認使用select)
radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTALshow_full_result_count = True,列表時,模糊搜索后面顯示的數據個數樣式
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): # show_full_result_count = True # 1 result (12 total) # show_full_result_count = False # 1 result (Show all) search_fields = ('user',)
form = ModelForm,用於定制用戶請求時候表單驗證
empty_value_display = "列數據為空時,顯示默認值"
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): empty_value_display = "列數據為空時,默認顯示" list_display = ('user','pwd','up') def up(self,obj): return obj.user up.empty_value_display = "指定列數據為空時,默認顯示"
