Django-admin用法和源码分析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django-admin用法和源码分析相关的知识,希望对你有一定的参考价值。
一、单例模式:单个实例公用一个对象
1、基于模块的单例模式
s1.py文件:
class Foo(object): def test(self): print("123") v = Foo()
s2.py文件:
from s1 import v as v1 print(v1,id(v1)) #<s1.Foo object at 0x0000000002221710> 35788560 from s1 import v as v2 print(v1,id(v2)) #<s1.Foo object at 0x0000000002221710> 35788560 # 两个的内存地址是一样的 # 文件加载的时候,第一次导入后,再次导入时不会再重新加载。
2、基于new方法的单例模式
class Singleton: def __new__(cls, *args, **kw): '''__new__是一个构造方法,self就是他构造的''' if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kw) return cls._instance one = Singleton() two = Singleton() print(one,two) #他们两个的地址一样 # print(id(one),id(two)) one.name = 'alex' print(two.name)
二、Django-admin使用流程
1、数据库迁移
models.py文件:
from django.db import models class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() def __str__(self): return self.name class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True,verbose_name="编号") title = models.CharField( max_length=32,verbose_name="名称") publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格") # 与Publish建立一对多的关系,外键字段建立在多的一方 publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors=models.ManyToManyField(to='Author',) def __str__(self): return self.title #执行下面python语句生成相关表(数据迁移) # python3 manage.py makemigrations # python3 manage.py migrate
2、创建超级用户
# python3 manage.py createsuperuser
3、admin.py中注册表
from django.contrib import admin from app01 import models admin.site.register(models.Book) admin.site.register(models.Publish) admin.site.register(models.Author)
4、如果新建应用app02
# python3 manage.py startapp app02
settings.py文件添加内容:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', "app02.apps.App02Config", ] 然后在app02应用的models.py增加表,接着数据库迁移,在app02应用的admin.py中对表进行注册
三、admin源码分析
1、访问url
def get_urls(): temp = [ url(r'^$'.format(app_name, cls_name), change_list), url(r'^add/$'.format(app_name, cls_name), add_view), url(r'^del/$'.format(app_name, cls_name), delete_view), url(r'^change/$'.format(app_name, cls_name), change_view) ] return temp url_list = [] for model_class, v in admin.site._registry.items(): cls_name = model_class._meta.model_name # 当前类名称的小写 app_name = model_class._meta.app_label # 当前app的名称 方式一: # all_urls = url(r'^{0}/{1}/'.format(app_name,cls_name), (get_urls(),None,None,)) 方式二: all_urls = url(r'^{0}/{1}/'.format(app_name, cls_name), include(get_urls())) url_list.append(all_urls) urlpatterns = [ url(r'^admin/', admin.site.urls), # admin.site这个对象里面有一个属性_registry = {} # 点击urls查看源码返回的是一个元组,元组的第一个元素是一个列表 url(r'^index/', ( [ url(r'^app01/userinfo/', ([ url(r'^$', change_list, name="login"), url(r'^add/$', add_view, name="login"), url(r'^(d+)/del/$', delete_view, name="login"), url(r'^(d+)/change/$', change_view, name="login"), ], None, None), name="login"), url(r'^app01/usertype/', ([ url(r'^$', change_list, name="login"), url(r'^add/$', add_view, name="login"), url(r'^(d+)/del/$', delete_view, name="login"), url(r'^(d+)/change/$', change_view, name="login"), ], None, None), name="login"), ], None, None)), url(r'^app02/article/', ([ url(r'^$', change_list, name="login"), url(r'^add/$', add_view, name="login"), url(r'^(d+)/del/$', delete_view, name="login"), url(r'^(d+)/change/$', change_view, name="login"), ], None, None), name="login"), # index和index2的两个是一样的,我们可以用index2的方式替代index url(r'^index2/', (url_list, None, None,)), ]
2、admin源码流程
a. 运行程序,找到每一个app中的 admin.py 文件,并加载 - app01.admin.py - 创建admin.site中的对象 - 执行对象的 register方法,目的:将注册类添加到 _registry中 _registry = { key是传进来的model value:是ModelAdmin的对象,传了两个参数 models.Role: ModelAdmin(models.Role,admin.site), models.UserInfo: ModelAdmin(models.UserInfo,admin.site) models.UserType: ModelAdmin(models.UserType,admin.site) } - app02.admin.py - 用app01.admin中创建那个admin.site对象 - 执行对象的 register方法,目的:讲注册类添加到 _registry中 _registry = { models.Role: ModelAdmin(models.Role,admin.site), models.UserInfo: ModelAdmin(models.UserInfo,admin.site) models.UserType: ModelAdmin(models.UserType,admin.site) models.Article: ModelAdmin(models.Article,admin.site) } admin.site是一个对象(单例模式创建),其中封装了: _registry = { models.Role: ModelAdmin(models.Role,admin.site), models.UserInfo: ModelAdmin(models.UserInfo,admin.site) models.UserType: ModelAdmin(models.UserType,admin.site) models.Article: ModelAdmin(models.Article,admin.site) } b. urls.py 再次调用 admin.site 对象的 urls属性: urlpatterns = [ url(r'^admin/', admin.site.urls), ] class ModelAdmin(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site def changelist_view(self,request): data_list = self.model_class.objects.all() #是动态的 return HttpResponse('列表页面') def add_view(self,request): return HttpResponse('添加页面') def delete_view(self,request,nid): return HttpResponse('删除页面') def change_view(self,request,nid): return HttpResponse('修改页面') def get_urls(self): urlpatterns = [ url(r'^$', self.changelist_view), url(r'^add/$', self.add_view), url(r'^(.+)/delete/$', self.delete_view), url(r'^(.+)/change/$', self.change_view), ] return urlpatterns @property def urls(self): return self.get_urls() class AdminSite(object): def __init__(self): self._registry = {} def register(self,model_class,model_admin): self._registry[model_class] = model_admin(model_class,self) def get_urls(self): """ models.Role: ModelAdmin(models.Role,admin.site), models.UserInfo: ModelAdmin(models.UserInfo,admin.site) models.UserType: ModelAdmin(models.UserType,admin.site) models.Article: ModelAdmin(models.Article,admin.site) """ url_list = [] for model_class,model_admin in self._registry.items(): model_class是一个类 app_name = model_class._meta.app_label model_name = model_class._meta.model_name url_list += [ url('%s/%s' %(app_name,model_name,), include(model_admin.urls)) ] return url_list @property def urls(self): return (self.get_urls(), None,None )
四、Django-admin(web页面显示)
models.py文件:
from django.db import models class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() # 与AuthorDetail建立一对一的关系 authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField( max_length=32) publishDate=models.DateField() price=models.DecimalField(max_digits=5,decimal_places=2) # 与Publish建立一对多的关系,外键字段建立在多的一方 publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors=models.ManyToManyField(to='Author',)
admin.py文件:
from django.contrib import admin # Register your models here. from .models import * #定制功能 class BookConfig(admin.ModelAdmin): list_display = ["nid","title","price","publishDate","publish"] #显示的列 list_display_links=["title","price"] #字段可以点击跳转 list_filter=["title","publish"] #定制右侧快速筛选 search_fields=["title"] #列表时,模糊搜索的功能 def patch_init(self,request,queryset): #批量操作执行的函数 queryset.update(price=100) patch_init.short_description = "批量初始化" #批量操作显示的描述 actions = [patch_init] #对所选择的选项执行批量操作函数 #change_list_template="list.html" #定制HTML模板 ordering=("price","nid",) #数据排序规则 admin.site.register(Book,BookConfig) #第一个参数是对哪个表进行注册,第二个参数是新增的自定义的功能类,这样book页面就会显示新的功能了 admin.site.register(Publish) admin.site.register(Author) admin.site.register(AuthorDetail)
其他的一些定制功能:
1、分页
# 分页,每页显示条数 list_per_page = 100 # 分页,显示全部(真实数据<该值时,才会有显示全部) list_max_show_all = 200 # 分页插件 paginator = Paginator
2、list_editable,列表时,可以编辑的列
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): list_display = ('user', 'pwd','ug',) list_editable = ('ug',)
3、date_hierarchy,列表时,对Date和DateTime类型进行搜索
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): date_hierarchy = 'ctime'
4、preserve_filters,详细页面,删除、修改,更新后跳转回列表后,是否保留原搜索条件
5、save_as = False,详细页面,按钮为“Sava as new” 或 “Sava and add another”
save_as_continue = True # 如果 save_as=True,save_as_continue = True, 点击Sava as new 按钮后继续编辑。 # 如果 save_as=True,save_as_continue = False,点击Sava as new 按钮后返回列表。
6、save_on_top = False,详细页面,在页面上方是否也显示保存删除等按钮
7、inlines,详细页面,如果有其他表和当前表做FK,那么详细页面可以进行动态增加和删除
class UserInfoInline(admin.StackedInline): # TabularInline extra = 0 model = models.UserInfo class GroupAdminMode(admin.ModelAdmin): list_display = ('id', 'title',) inlines = [UserInfoInline, ]
8、raw_id_fields,详细页面,针对FK和M2M字段变成以Input框形式
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): raw_id_fields = ('FK字段', 'M2M字段',)
9、fields,详细页面时,显示字段的字段
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): fields = ('user',)
10、exclude,详细页面时,排除的字段
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): exclude = ('user',)
11、readonly_fields,详细页面时,只读字段
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): readonly_fields = ('user',)
12、fieldsets,详细页面时,使用fieldsets标签对数据进行分割显示
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): fieldsets = ( ('基本数据', { 'fields': ('user', 'pwd', 'ctime',) }), ('其他', { 'classes': ('collapse', 'wide', 'extrapretty'), # 'collapse','wide', 'extrapretty' 'fields': ('user', 'pwd'), }), )
13、详细页面时,M2M显示时,数据移动选择(方向:上下和左右)
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)
14、view_on_site,编辑时,是否在页面上显示view on set
view_on_site = False 或 def view_on_site(self, obj): return 'https://www.baidu.com'
15、radio_fields,详细页面时,使用radio显示选项(FK默认使用select)
radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTAL
16、show_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',)
17、formfield_overrides = {},详细页面时,指定现实插件
from django.forms import widgets from django.utils.html import format_html class MyTextarea(widgets.Widget): def __init__(self, attrs=None): # Use slightly better defaults than HTML's 20x2 box default_attrs = {'cols': '40', 'rows': '10'} if attrs: default_attrs.update(attrs) super(MyTextarea, self).__init__(default_attrs) def render(self, name, value, attrs=None): if value is None: value = '' final_attrs = self.build_attrs(attrs, name=name) return format_html('<textarea {}> {}</textarea>',final_attrs, value) @admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): formfield_overrides = { models.models.CharField: {'widget': MyTextarea}, }
18、prepopulated_fields = {},添加页面,当在某字段填入值后,自动会将值填充到指定字段。
@admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): prepopulated_fields = {"email": ("user","pwd",)} PS: DjangoAdmin中使用js实现功能,页面email字段的值会在输入:user、pwd时自动填充
19、form = ModelForm,用于定制用户请求时候表单验证
from app01 import models from django.forms import ModelForm from django.forms import fields class MyForm(ModelForm): others = fields.CharField() class Meta: model = models = models.UserInfo fields = "__all__" @admin.register(models.UserInfo) class UserAdmin(admin.ModelAdmin): form = MyForm
20、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 = "指定列数据为空时,默认显示"
以上是关于Django-admin用法和源码分析的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向整体加固脱壳 ( DEX 优化流程分析 | DexPrepare.cpp 中 dvmOptimizeDexFile() 方法分析 | /bin/dexopt 源码分析 )(代码片段
Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段