详解Django之admin组件的使用和源码剖析

来源:http://www.prospettivedarte.com 作者:计算机教程 人气:194 发布时间:2019-05-10
摘要:启动 在stark应用下的apps.py文件添加一下代码,加载每一个app下的所有stark文件 from django.apps import AppConfigfrom django.utils.module_loading import autodiscover_modulesclass StarkConfig(AppConfig): name = 'stark'

启动

在stark应用下的apps.py文件添加一下代码,加载每一个app下的所有stark文件

from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules


class StarkConfig(AppConfig):
    name = 'stark'

    # 在项目启动的时候加载所有的stark模块
    def ready(self):
        autodiscover_modules('stark')
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  fields = ('user',)

首先,创建一个Python Package包,创建一个stark文件

皇牌天下投注网 1

正如本篇开头所述,我们在使用admin组件的时候,是在我们注册时候调用一个单例对象site进行注册

class StarkSite(object):
        def __init__(self):
            self._registry = {}

site = StarkSite()

然后在app01的stark文件中导入

from stark.service.stark import site

生成一个单例对象

通过单例对象site调用注册方法,所以需要在StarkSite类创建一个register方法

# servicestark.py
def register(self, model, admin_class=None, **options):
    # 如果注册的时候没有自定义配置类,执行
    if not admin_class:
        admin_class = ModelStark   # 配置类
    # 将配置类对象加到_registry字典中,键为模型类
    self._registry[model] = admin_class(model) # _registry={'model':admin_class(model)}

在对应app中的注册方法:

# app01stark.py


from app01 import models
from stark.service.stark import site,ModelStark

# 自定义配置类
class BookConfig(ModelStark):
    pass

site.register(models.Book,BookConfig)
site.register(models.Author)
site.register(models.AuthorDetail)
site.register(models.Publish)

注册之后,启动项目就会将我们注册的模型类添加到字典_registry中

  1. 使用模块
  2. 使用  __new__
  3. 使用装饰器(decorator)
  4. 使用元类(metaclass)

设计URL

Django项目建起来之后就会自动创建一个url文件,如:其中admin的url就已经配置好了

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

进入源码看一眼,会发现url方法有property装饰器,会将函数装饰成一个属性

它会在项目的启动的时候就执行,将内部的url进行分发,生成url的方法就是get_urls()

自定义url

def get_urls(self):
        temp = []
        for model,config_obj in self._registry.items():
            model_name = model._meta.model_name # 拿到模型类的名字
            app_label = model._meta.app_label # 拿到当前类所在app的名字
            # 第一路由
            temp.append(url(r'^%s/%s/'%(app_label, model_name),config_obj.urls))

        return temp

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

这样就可以对每一个app下面的每一个模型类进行url分发,但是还要对每一个模型进行数据的增删改查,所以就需要进行第二级的分发

皇牌天下投注网 2

二级url分发实现:

def get_urls(self):
    temp = []
    model_name = self.model._meta.model_name
    app_label = self.model._meta.app_label

    temp.append(url("^$", self.list_view,name="%s_%s_list"%(app_label,model_name)))
    temp.append(url("^add/$",self.add_view,name="%s_%s_add"%(app_label,model_name)))
    temp.append(url("^(d )/change/",self.change_view,name="%s_%s_change"%(app_label,model_name)))
    temp.append(url("^(d )/delete/",self.delete_view,name="%s_%s_delete"%(app_label,model_name)))
    return temp

@property
def urls(self):

    return self.get_urls(),None,None

 

ModelAdmin中提供了大量的可定制功能,如

stark组件开发

仿照Django内置的admin组件自定义一个后台管理组件,实现数据的CRUD

11 raw_id_fields,详细页面,针对FK和M2M字段变成以Input框形式

(1)使用 __new__

为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  
        return cls._instance  

class MyClass(Singleton):  
    a = 1

在上面的代码中,我们将类的实例和一个类变量 _instance皇牌天下投注网, 关联起来,如果 cls._instance 为 None 则创建实例,否则直接返回 cls._instance

执行情况如下:

>>> one = MyClass()
>>> two = MyClass()
>>> one == two
True
>>> one is two
True
>>> id(one), id(two)
(4303862608, 4303862608)
from mysingleton import my_singleton
my_singleton.foo()

单例模式

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

在 Python 中,我们可以用多种方法来实现单例模式:

  • 使用模块
  • 使用 __new__
  • 使用装饰器(decorator)
  • 使用元类(metaclass)
radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTAL

2)使用模块

其实,Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。如果我们真的想要一个单例类,可以考虑这样做:

# mysingleton.py
class My_Singleton(object):
    def foo(self):
        pass

my_singleton = My_Singleton()

将上面的代码保存在文件 mysingleton.py 中,然后这样使用:

from mysingleton import my_singleton

my_singleton.foo() # 获得一个单例对象

13 exclude,详细页面时,排除的字段

注册

我们在使用Django内置的admin组件的时候,首先就是要对我们创建的Model(模型表)进行注册,至于注册过后我们才可以对表的数据进行CRUD操作。

<2> 执行代码

准备工作

首先,我们需要新建一个Django项目,一个方便组织代码的APP应用,一个stark APP用于存放自定义组件的核心代码。

皇牌天下投注网 3

创建成功之后到settings.py文件对app进行注册

皇牌天下投注网 4

执行情况如下:

admin源码解析

当这一切都配置好后,Django 管理工具就可以运行了。

admin执行流程

<1> 循环加载执行所有已经注册的app中的admin.py文件

def autodiscover():
    autodiscover_modules('admin', register_to=site)

 <2> 执行代码

#admin.py

class BookAdmin(admin.ModelAdmin):
    list_display = ("title",'publishDate', 'price')

admin.site.register(Book, BookAdmin) 
admin.site.register(Publish)

<3> admin.site

皇牌天下投注网 5

这里应用的是一个单例模式,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象

 <4> 执行register方法

admin.site.register(Book, BookAdmin) 
admin.site.register(Publish)

默认admin配置类:ModelAdmin

皇牌天下投注网 6

 注意:admin.site.registry(xx),注册时,_registry{}字典保存的键是model 中的类名,值是model的管理类的AdminClass类

class ModelAdmin(BaseModelAdmin):pass

def register(self, model_or_iterable, admin_class=None, **options):
    if not admin_class:
            admin_class = ModelAdmin
    # Instantiate the admin class to save in the registry
    self._registry[model] = admin_class(model, self)

那么,在app的stark.py中加上(同理可在每一个app的admin.py中测试)

print(site._registry)   # stark.py,执行结果?
print(admin.site._registry)   # admin.py,执行结果?

结果:

皇牌天下投注网 7皇牌天下投注网 8

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2018/07/23 9:53
# @Author  : MJay_Lee
# @File    : stark.py
# @Contact : limengjiejj@hotmail.com

from app01 import models
from stark.service.stark import site,ModelStark
from django.utils.safestring import mark_safe

class BookConfig(ModelStark):

    list_display = ["title","price","publish"]

site.register(models.Book,BookConfig)

site.register(models.Author)
site.register(models.AuthorDetail)
site.register(models.Publish)

print("my_stark.app01===>n",site._registry)
# 打印结果
'''
my_stark.app01===>
 {<class 'app01.models.Book'>: <app01.stark.BookConfig object at 0x0000018D0A372748>, <class 'app01.models.Author'>: <stark.service.stark.ModelStark object at 0x0000018D0A372A58>, <class 'app01.models.AuthorDetail'>: <stark.service.stark.ModelStark object at 0x0000018D0A372AC8>, <class 'app01.models.Publish'>: <stark.service.stark.ModelStark object at 0x0000018D0A37D1D0>}
'''

打印结果

到这里,注册结束!

 <5> admin的URL配置

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

如何实现路由分发:

class AdminSite(object):

     def get_urls(self):
        from django.conf.urls import url, include

        urlpatterns = []

        # 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)


        return urlpatterns

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

<6>  url()方法的扩展应用

from django.shortcuts import HttpResponse
def test01(request):
    return HttpResponse("test01")

def test02(request):
    return HttpResponse("test02")

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^yuan/', ([
                    url(r'^test01/', test01),
                    url(r'^test02/', test02),

                    ],None,None)),

]

扩展优化

from django.conf.urls import url,include
from django.contrib import admin

from django.shortcuts import HttpResponse

def change_list_view(request):
    return HttpResponse("change_list_view")
def add_view(request):
    return HttpResponse("add_view")
def delete_view(request):
    return HttpResponse("delete_view")
def change_view(request):
    return HttpResponse("change_view")

def get_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),
    ]

    return temp


url_list=[]

for model_class,obj in admin.site._registry.items():

    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)),
]

您可能感兴趣的文章:

这里应用的是一个单例模式,对于AdminSite类的一个单例模式,执行的每一个app中的每一个admin.site都是一个对象

admin.site.register(Book, BookAdmin) 
admin.site.register(Publish)


class ModelAdmin(BaseModelAdmin):pass
def register(self, model_or_iterable, admin_class=None, **options):
  if not admin_class:
      admin_class = ModelAdmin
  # Instantiate the admin class to save in the registry
  self._registry[model] = admin_class(model, self)

方式二:

但是,这种方式比较简单,如果想要进行更多的定制操作,需要利用ModelAdmin进行操作,如:

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  raw_id_fields = ('FK字段', 'M2M字段',)

15 fieldsets,详细页面时,使用fieldsets标签对数据进行分割显示

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  exclude = ('user',)

<4> 执行register方法

<3> admin.site

20 empty_value_display = "列数据为空时,显示默认值"

到这里,注册结束!

单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保 某一个类只有一个实例存在 。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。

  1. list_display,列表时,定制显示的列。

比如,某个服务器程序的配置信息存放在一个文件中,客户端通过一个 AppConfig 的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建 AppConfig 对象的实例,这就导致系统中存在多个 AppConfig 的实例对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下。事实上,类似 AppConfig 这样的类,我们希望在程序运行期间只存在一个实例对象。

# Application definition

INSTALLED_APPS = [
  'django.contrib.admin',
  'django.contrib.auth',
  'django.contrib.contenttypes',
  'django.contrib.sessions',
  'django.contrib.messages',
  'django.contrib.staticfiles',
  "app01"
]

在admin.py中只需要讲Mode中的某个类注册,即可在Admin中实现增删改查的功能,如:

在 Python 中,我们可以用多种方法来实现单例模式:

urlpatterns = [
  url(r'^admin/', admin.site.urls),
]


class AdminSite(object):  
   def get_urls(self):
    from django.conf.urls import url, include   
    urlpatterns = []
    # 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)
    return urlpatterns
  @property
  def urls(self):
    return self.get_urls(), 'admin', self.name
@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)

<6>  url()方法的扩展应用

10 定制HTML模板

16 详细页面时,M2M显示时,数据移动选择(方向:上下和左右)

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  date_hierarchy = 'ctime'

<1> 循环加载执行所有已经注册的app中的admin.py文件

皇牌天下投注网 9

单例模式

from django.conf.urls import url,include
from django.contrib import admin
from django.shortcuts import HttpResponse
def change_list_view(request):
  return HttpResponse("change_list_view")
def add_view(request):
  return HttpResponse("add_view")
def delete_view(request):
  return HttpResponse("delete_view")
def change_view(request):
  return HttpResponse("change_view")
def get_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),
  ]

  return temp
url_list=[]
for model_class,obj in admin.site._registry.items():
  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)),
]

admin执行流程

仿admin的url路径分发

  1. date_hierarchy,列表时,对Date和DateTime类型进行搜索
from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
  url(r'^admin/', admin.site.urls),

]
  1. search_fields,列表时,模糊搜索的功能

8  inlines,详细页面,如果有其他表和当前表做FK,那么详细页面可以进行动态增加和删除

为了使类只能出现一个实例,我们可以使用 __new__ 来控制实例的创建过程,代码如下:

@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 = "指定列数据为空时,默认显示"


from django.contrib import admin
# Register your models here.
from .models import *
class BookInline(admin.StackedInline): # TabularInline
  extra = 0
  model = Book

class BookAdmin(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

  def foo(self,obj):

    return obj.title str(obj.price)
  # 定制Action行为具体方法
  def func(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"
class PublishAdmin(admin.ModelAdmin):
   list_display = ('name', 'email',)
   inlines = [BookInline, ]
admin.site.register(Book, BookAdmin) # 第一个参数可以是列表
admin.site.register(Publish,PublishAdmin)
admin.site.register(Author)

在上面的代码中,我们将类的实例和一个类变量 _instance 关联起来,如果  cls._instance 为 None 则创建实例,否则直接返回  cls._instance 。

  1. list_filter,列表时,定制右侧快速筛选。

  2. list_select_related,列表时,连表查询是否自动select_related

  3. list_editable,列表时,可以编辑的列

本文由皇牌天下投注网发布于计算机教程,转载请注明出处:详解Django之admin组件的使用和源码剖析

关键词:

上一篇:移动端页面布局的那些事儿

下一篇:没有了

最火资讯