知识预览
admin组件使用
admin源码解析
回到顶部
admin组件使用
Django提供了基于web的管理工具。
Django自动管理工具是django.contrib的一部分。你可以在项目的settings.py中的INSTALLED_APPS看到它:
复制代码
#Applicationdefinition
INSTALLED_APPS=[
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
"app01"
]
复制代码
django.contrib是一套庞大的功能集,它是Django基本代码的组成部分。
激活管理工具
通常我们在生成项目时会在urls.py中自动设置好,
复制代码
fromdjango.conf.urlsimporturl
fromdjango.contribimportadmin
urlpatterns=[
url(r'^admin/',admin.site.urls),
]
复制代码
当这一切都配置好后,Django管理工具就可以运行了。
使用管理工具
启动开发服务器,然后在浏览器中访问http://127.0.0.1:8000/admin/,得到登陆界面,你可以通过命令pythonmanage.pycreatesuperuser来创建超级用户。
为了让admin界面管理某个数据模型,我们需要先注册该数据模型到admin
ViewCode
admin的定制
在admin.py中只需要讲Mode中的某个类注册,即可在Admin中实现增删改查的功能,如:
admin.site.register(models.UserInfo)
但是,这种方式比较简单,如果想要进行更多的定制操作,需要利用ModelAdmin进行操作,如:
复制代码
方式一:
classUserAdmin(admin.ModelAdmin):
list_display=('user','pwd',)
admin.site.register(models.UserInfo,UserAdmin)#第一个参数可以是列表
方式二:
@admin.register(models.UserInfo)#第一个参数可以是列表
classUserAdmin(admin.ModelAdmin):
list_display=('user','pwd',)
复制代码
ModelAdmin中提供了大量的可定制功能,如
1.list_display,列表时,定制显示的列。
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
list_display=('user','pwd','xxxxx')
defxxxxx(self,obj):
return"xxxxx"
2.list_display_links,列表时,定制列可以点击跳转。
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
list_display=('user','pwd','xxxxx')
list_display_links=('pwd',)
3.list_filter,列表时,定制右侧分类筛选。字段至少有两个以上
list_filter=["title"]#注意外键关联
list_filter=["title","user","tags"]
4.list_select_related,列表时,连表查询是否自动select_related
5.list_editable,列表时,列表内设定的列以输入框形式展示,注意要和list_display_links=('pwd',)搭配使用,且links内不能够有edict内的字段
classArticleConfig(admin.ModelAdmin):
defdeletes_article(self):#用函数表示新增字段
returnmark_safe("<ahref="">删除</a>")
list_display=["title","create_time","comment_count","up_count",deletes_article]#展示那些字段
list_display_links=["create_time"]
list_filter=["title","user","tags"]
list_editable=["title"]
6.search_fields,对列表内的字段进行搜索,字段之间是或关系
classArticleConfig(admin.ModelAdmin):
defdeletes_article(self):#用函数表示新增字段
returnmark_safe("<ahref="">删除</a>")
list_display=["title","create_time","comment_count","up_count",deletes_article]#展示那些字段
list_display_links=["title"]
search_fields=["title"]
7.date_hierarchy,列表时,对Date和DateTime类型进行搜索
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
date_hierarchy='ctime'
8inlines,详细页面,如果有其他表和当前表做FK,那么详细页面可以进行动态增加和删除
复制代码
classUserInfoInline(admin.StackedInline):#TabularInline
extra=0
model=models.UserInfo
classGroupAdminMode(admin.ModelAdmin):
list_display=('id','title',)
inlines=[UserInfoInline,]
复制代码
9action,对列表内数据进行批量增删改查,自定义删除等功能
复制代码
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
#定制Action行为具体方法
deffunc(self,request,queryset):
queryset.update(create_time="2017-10-18")
func.short_description="更新时间"
actions=[func,]
#Action选项都是在页面上方显示
actions_on_top=True
#Action选项都是在页面下方显示
actions_on_bottom=False
#是否显示选择个数
actions_selection_counter=True
复制代码
10定制HTML模板
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
11raw_id_fields,详细页面,针对FK和M2M字段变成以Input框形式
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
raw_id_fields=('FK字段','M2M字段',)
12fields,编辑表时,可选择性显示页面,把可以为空的字段隐藏起来
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
fields=('user',)
13exclude,详细页面时,排除的字段
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
exclude=('user',)
14readonly_fields,详细页面时,只读字段
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
readonly_fields=('user',)
15fieldsets,详细页面时,使用fieldsets标签对数据进行分割显示
复制代码
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
fieldsets=(
('基本数据',{
'fields':('user','pwd','ctime',)
}),
('其他',{
'classes':('collapse','wide','extrapretty'),#'collapse','wide','extrapretty'
'fields':('user','pwd'),
}),
)
复制代码
16详细页面时,M2M显示时,数据移动选择(方向:上下和左右)
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
filter_vertical=("m2m字段",)#或filter_horizontal=("m2m字段",)
17ordering,列表时,数据排序规则
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
ordering=('-id',)
或
defget_ordering(self,request):
return['-id',]
18.radio_fields,详细页面时,使用radio显示选项(FK默认使用select)
radio_fields={"ug":admin.VERTICAL}#或admin.HORIZONTAL
19form=ModelForm,用于定制用户请求时候表单验证
复制代码
fromapp01importmodels
fromdjango.formsimportModelForm
fromdjango.formsimportfields
classMyForm(ModelForm):
others=fields.CharField()
classMeta:
model=models=models.UserInfo
fields="__all__"
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
form=MyForm
复制代码
20empty_value_display="列数据为空时,显示默认值"
复制代码
@admin.register(models.UserInfo)
classUserAdmin(admin.ModelAdmin):
empty_value_display="列数据为空时,默认显示"
list_display=('user','pwd','up')
defup(self,obj):
returnobj.user
up.empty_value_display="指定列数据为空时,默认显示"
复制代码
fromdjango.contribimportadmin
#Registeryourmodelshere.
from.modelsimport*
classBookInline(admin.StackedInline):#TabularInline
extra=0
model=Book
classBookAdmin(admin.ModelAdmin):
list_display=("title",'publishDate','price',"foo","publisher")
list_display_links=('publishDate',"price")
list_filter=('price',)
list_editable=("title","publisher")
search_fields=('title',)
date_hierarchy='publishDate'
preserve_filters=False
deffoo(self,obj):
returnobj.title+str(obj.price)
#定制Action行为具体方法
deffunc(self,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
change_list_template="my_change_list_template.html"
classPublishAdmin(admin.ModelAdmin):
list_display=('name','email',)
inlines=[BookInline,]
admin.site.register(Book,BookAdmin)#第一个参数可以是列表
admin.site.register(Publish,PublishAdmin)
admin.site.register(Author)
ViewCode
回到顶部
admin源码解析
单例模式
单例模式(SingletonPattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。
就像系统的某个类模块,每一个项目实例化的对象都指向一个地方,因为它们需要的功能和数据是一样的,因此修改一个,会影响到其他项目的执行,但是这样可以节省空间.就像AppConfig,在很多app内都需要用到,如果内一个app都实例化一个对象,浪费空间的同时,也降低了效率
在配置信息中是很常见的
在Python中,我们可以用多种方法来实现单例模式:
使用模块
使用__new__
使用装饰器(decorator)
使用元类(metaclass)
(1)使用__new__
为了使类只能出现一个实例,我们可以使用__new__来控制实例的创建过程,代码如下:
复制代码
classSingleton(object):
_instance=None
def__new__(cls,*args,**kw):#cls表示当前类
ifnotcls._instance:
cls._instance=super(Singleton,cls).__new__(cls,*args,**kw)#用__new__实例化一个对象,第一次进来的时候_instance,已经变成一个实例化对象了
returncls._instance
classMyClass(Singleton):
a=1
复制代码
复制代码
>>>one=MyClass()
>>>two=MyClass()
>>>one==two
True
>>>oneistwo
True
>>>id(one),id(two)
(4303862608,4303862608)
复制代码
(2)使用模块
其实,Python的模块就是天然的单例模式,因为模块在第一次导入时,会生成.pyc文件,当第二次导入时,就会直接加载.pyc文件,即在python整个项目中模块只导入一次,在别的py文件导入时,就直接使用第一次导入生成的.pyc文件,而不会再次导入模块。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:
#mysingleton.py需要导入的模块
classMy_Singleton(object):
deffoo(self):
pass
my_singleton=My_Singleton()
当我们导入一个其他模块中的实例化对象,或者类,在各个py文件中都指向一个id地址,但是由类生成的对象就是不同的在admin中导入site使用的就是该方法,这里包括导入模块后使用模块.已经实例化的对象都是指向同一个id:
frommysingletonimportmy_singleton#导入一个实例化对象,当在项目其他py文件导入时,就直接指向该空间,共享该方法
my_singleton.foo()
admin执行流程
<1>按着App注册顺序加载执App内所有admin.py文件,即在脚本中导入或者使用admin内的方法都会先执行
defautodiscover():
autodiscover_modules('admin',register_to=site)
<2>执行代码
复制代码
#admin.py
classBookAdmin(admin.ModelAdmin):
list_display=("title",'publishDate','price')
admin.site.register(Book,BookAdmin)
admin.site.register(Publish)
复制代码
<3>admin.site
这里应用的是一个单例模式,对于AdminSite类的一个单例模式,在所有app中执行的admin.site都是同一个对象,指向同一个内存地址
<4>执行register方法
admin.site.register(Book,BookAdmin)
admin.site.register(Publish)
复制代码
classModelAdmin(BaseModelAdmin):pass
defregister(self,model_or_iterable,admin_class=None,**options):
_registry={}
ifnotadmin_class:
admin_class=ModelAdmin
#Instantiatetheadminclasstosaveintheregistry
self._registry[model]=admin_class(model,self)
复制代码
思考:在每一个app的admin.py中加上
print(admin.site._registry)#可以拿到所有已经注册的类名和实例化的对象
<5>admin的URL配置源码
urlpatterns=[
url(r'^admin/',admin.site.urls),
]
复制代码
classAdminSite(object):
defget_urls(self):
fromdjango.conf.urlsimporturl,include
urlpatterns=[]
#Addineachmodel'sviews,andcreatealistofvalidURLSforthe
#app_index
valid_app_labels=[]
formodel,model_admininself._registry.items():
urlpatterns+=[
url(r'^%s/%s/'%(model._meta.app_label,model._meta.model_name),include(model_admin.urls)),
]
ifmodel._meta.app_labelnotinvalid_app_labels:
valid_app_labels.append(model._meta.app_label)
returnurlpatterns
@property
defurls(self):
returnself.get_urls(),'admin',self.name
复制代码
<6>url()方法的扩展应用,即把url中视图函数改成列表[],第一个参数是url路径匹配,第2和第3个参数是None,可以是多层次分发,列表内路径可有函数执行后返回数据
简单版路由分发
复制代码
fromdjango.shortcutsimportHttpResponse
deftest01(request):
returnHttpResponse("test01")
deftest02(request):
returnHttpResponse("test02")
urlpatterns=[
url(r'^admin/',admin.site.urls),
url(r'^yuan/',([
url(r'^test01/',test01),
url(r'^test02/',test02),
],None,None)),
]
复制代码
老师版扩展优化
复制代码
fromdjango.conf.urlsimporturl,include
fromdjango.contribimportadmin
fromdjango.shortcutsimportHttpResponse
defchange_list_view(request):
returnHttpResponse("change_list_view")
defadd_view(request):
returnHttpResponse("add_view")
defdelete_view(request):
returnHttpResponse("delete_view")
defchange_view(request):
returnHttpResponse("change_view")
defget_urls():
temp=[
url(r"^$".format(app_name,model_name),change_list_view),
url(r"^add/$".format(app_name,model_name),add_view),
url(r"^\d+/del/$".format(app_name,model_name),delete_view),
url(r"^\d+/change/$".format(app_name,model_name),change_view),
]
returntemp
url_list=[]
formodel_class,objinadmin.site._registry.items():#切记一定要调用.items方法才能够实行for循环
model_name=model_class._meta.model_name
app_name=model_class._meta.app_label
#temp=url(r"{0}/{1}/".format(app_name,model_name),(get_urls(),None,None))
temp=url(r"{0}/{1}/".format(app_name,model_name),include(get_urls()))
url_list.append(temp)
urlpatterns=[
url(r'^admin/',admin.site.urls),
url(r'^yuan/',(url_list,None,None)),
]
复制代码
注意:在这里调用了models模型内的meta方法,如果在表中没有设置,meta会自定义一些参数
meta有以下的方法
unique_together#查看联合唯一字段属性
permissions#查看权限
db_tablespace#数据库中表名
db_table#查看数据库表名,一般自定义为App名+表名
db_table#表名所在的app
url分发详情
defget_url():#一级分发表
#admin.site._registry拿到当前注册的表和实例化的对象,通过单例模型
url=[]
forkey,valueinadmin.site._registry.items():
#注意这里的key和value都是一个类变量,对其打印或显示,只会显示内存地址,
#因此关键在于拿到对象的名字和相应的上一层路径
app_name=key._meta.app_label
table_name=key._meta.model_name
url_base=re_path('^{}/{}/'.format(app_name,table_name),[get_url2(),None,None])
url.append(url_base)
returnurl
defget_url2():
url=[]
url.append(re_path('^add/$',test))
url.append(re_path('^delete/(\d+)',test))
url.append(re_path('^update/(\d+)',test))
url.append(re_path('^check/(\d+)',test))
returnurl
urlpatterns=[
path('admin/',admin.site.urls),
re_path('^ad/',(get_url(),None,None)),
]
注册问题
register()函数源码,函数注册时,当没有自定义模块时,用自定的类,实例化传进来的参数,如果有自定义的类,就用传进来的类实例化传进来的参数,注意这里把表名做键,实例化的对象做值放在字典中,注意的键是表名,不需要用""
classAdminSite(object):
def__init__(self,name='admin'):
self._registry={}
defregister(self,models,admin_class=None,**option):
ifnotadmin_class:
admin_class=ModelAdmin#默认一个类方法
#对传进来的模型进行实例化,因此传进来一个对象,都会封装在_registry字典中
self._registry[ArticleDetail]=admin_class(models,self)
site=AdminSite()
效果如下图
admin.site.register(models.ArticleDetail)
self._registry[ArticleDetail]=ModelAdmin(ArticleDetail,self)
#self._registry={ArticleDetail:ModelAdmin(ArticleDetail),}
admin.site.register(models.Article,ArticleConfig)
self._registry[Article]=ArticleConfig(Article,self)
#self._registry={ArticleDetail:ModelAdmin(ArticleDetail),Article:ArticleConfig(Article,slef)}
类的补充
类中表示调用他的对象或者,如实例化对象调用类中的方法,此时self就是,字典的键是不可变类型,因此他可以是实例化的对象
如需转载,请注明文章出处和来源网址:http://www.divcss5.com/html/h54742.shtml