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 源码分析 )(代码片段

django-admin和manage.py用法

django-admin.py和manage.py的用法

Android 事件分发事件分发源码分析 ( Activity 中各层级的事件传递 | Activity -> PhoneWindow -> DecorView -> ViewGroup )(代码片段

Django源码分析1:创建项目和应用分析

《Docker 源码分析》全球首发啦!