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


Posted in Python onMay 04, 2018

admin组件使用

Django 提供了基于 web 的管理工具。

Django 自动管理工具是 django.contrib 的一部分。你可以在项目的 settings.py 中的 INSTALLED_APPS 看到它:

# Application definition

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 中自动设置好,

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

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

]

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

使用管理工具

启动开发服务器,然后在浏览器中访问 http://127.0.0.1:8000/admin/,得到登陆界面,你可以通过命令 python manage.py createsuperuser 来创建超级用户。

为了让 admin 界面管理某个数据模型,我们需要先注册该数据模型到 admin

from django.db import models

class Author(models.Model):

  name=models.CharField( max_length=32)
  age=models.IntegerField()

  def __str__(self):
    return self.name

class Publish(models.Model):

  name=models.CharField( max_length=32)
  email=models.EmailField()

  def __str__(self):
    return self.name


class Book(models.Model):

  title = models.CharField( max_length=32)
  publishDate=models.DateField()
  price=models.DecimalField(max_digits=5,decimal_places=2)

  publisher=models.ForeignKey(to="Publish")
  authors=models.ManyToManyField(to='Author')

  def __str__(self):
    return self.title

admin的定制

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

admin.site.register(models.UserInfo)

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

方式一:

class UserAdmin(admin.ModelAdmin):
   list_display = ('user', 'pwd',)
 
admin.site.register(models.UserInfo, UserAdmin) # 第一个参数可以是列表

方式二:

@admin.register(models.UserInfo)        # 第一个参数可以是列表
class UserAdmin(admin.ModelAdmin):
  list_display = ('user', 'pwd',)

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

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

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  list_display = ('user', 'pwd', 'xxxxx')
 
  def xxxxx(self, obj):
    return "xxxxx"

2. list_display_links,列表时,定制列可以点击跳转。

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  list_display = ('user', 'pwd', 'xxxxx')
  list_display_links = ('pwd',)

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

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

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

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  list_display = ('user', 'pwd','ug',)
  list_editable = ('ug',)

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

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

7. date_hierarchy,列表时,对Date和DateTime类型进行搜索

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

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

class UserInfoInline(admin.StackedInline): # TabularInline
  extra = 0
  model = models.UserInfo
 
class GroupAdminMode(admin.ModelAdmin):
  list_display = ('id', 'title',)
  inlines = [UserInfoInline, ]

9 action,列表时,定制action中的操作

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
 
  # 定制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

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

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

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

12  fields,详细页面时,显示字段的字段

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

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

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

14  readonly_fields,详细页面时,只读字段

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

15 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'),
    }),
  )

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

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  filter_vertical = ("m2m字段",) # 或filter_horizontal = ("m2m字段",)

17 ordering,列表时,数据排序规则

@admin.register(models.UserInfo)
class UserAdmin(admin.ModelAdmin):
  ordering = ('-id',)
  或
  def get_ordering(self, request):
    return ['-id', ]

18. radio_fields,详细页面时,使用radio显示选项(FK默认使用select)

radio_fields = {"ug": admin.VERTICAL} # 或admin.HORIZONTAL

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

admin源码解析

单例模式

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

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

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

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

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

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

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

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

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

<4> 执行register方法

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)

到这里,注册结束!

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

仿admin的url路径分发

#############models.py###########
from django.db import models
class Book(models.Model):
  title = models.CharField(max_length=32)
  author = models.ForeignKey(to='Author')
class Author(models.Model):
  name = models.CharField(max_length=32)
#################admin.py###########
from app01.models import *
admin.site.register(Book)
admin.site.register(Author)
##############views.py################
from django.shortcuts import HttpResponse
def add(request):
  return HttpResponse('add')
def change(request,id):
  return HttpResponse('change')
def delete(request,id):
  return HttpResponse('delete')
def show(request):
  return HttpResponse('show')
################url.py##############
def get_urls2():
  tmp = []
  tmp.append(url(r'^add/',add))
  tmp.append(url(r'^(\d+)/change/',change))
  tmp.append(url(r'^(\d+)/delete/',delete))
  tmp.append(url(r'^',show))
  return tmp
def get_urls():
  temp = []
  for model, admin_class_obj in admin.site._registry.items():
    model_name = model._meta.model_name
    app_label = model._meta.app_label
    temp.append(url(r'^{}/{}/'.format(app_label,model_name),(get_urls2(),None,None))) #[url(r'^app01/book/',),]
  return temp

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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python多重继承实例
Oct 11 Python
python检查字符串是否是正确ISBN的方法
Jul 11 Python
python 多线程实现检测服务器在线情况
Nov 25 Python
python中根据字符串调用函数的实现方法
Jun 12 Python
Android基于TCP和URL协议的网络编程示例【附demo源码下载】
Jan 23 Python
Python实现Kmeans聚类算法
Jun 10 Python
TensorFlow利用saver保存和提取参数的实例
Jul 26 Python
python实现对指定字符串补足固定长度倍数截断输出的方法
Nov 15 Python
python中append实例用法总结
Jul 30 Python
Python3安装pip工具的详细步骤
Oct 14 Python
python实现PCA降维的示例详解
Feb 24 Python
selenium自动化测试入门实战
Dec 21 Python
Python实现正弦信号的时域波形和频谱图示例【基于matplotlib】
May 04 #Python
使用python3+xlrd解析Excel的实例
May 04 #Python
对python中的xlsxwriter库简单分析
May 04 #Python
使用实现XlsxWriter创建Excel文件并编辑
May 04 #Python
Python实现获取前100组勾股数的方法示例
May 04 #Python
python XlsxWriter模块创建aexcel表格的实例讲解
May 03 #Python
Python 中的Selenium异常处理实例代码
May 03 #Python
You might like
PHP图片裁剪函数(保持图像不变形)
2014/05/04 PHP
PHP+Memcache实现wordpress访问总数统计(非插件)
2014/07/04 PHP
PHP中常用的数组操作方法笔记整理
2016/05/16 PHP
php关联数组与索引数组及其显示方法
2018/03/12 PHP
php中html_entity_decode实现HTML实体转义
2018/06/13 PHP
[Web]防止用户复制页面内容和另存页面的方法
2009/02/06 Javascript
js监听表单value的修改同步问题,跨浏览器支持
2009/12/31 Javascript
in.js 一个轻量级的JavaScript颗粒化模块加载和依赖关系管理解决方案
2011/07/26 Javascript
用jQuery实现一些导航条切换,显示隐藏的实例代码
2013/06/08 Javascript
js substring从右边获取指定长度字符串(示例代码)
2013/12/23 Javascript
javascript数组操作总结和属性、方法介绍
2014/04/05 Javascript
Bootstrap每天必学之标签页(Tab)插件
2020/08/09 Javascript
jQuery animate easing使用方法图文详解
2016/06/17 Javascript
解决wx.onMenuShareTimeline出现的问题
2016/08/16 Javascript
使用JQuery中的trim()方法去掉前后空格
2016/09/16 Javascript
AngularJS动态绑定HTML的方法分析
2016/11/07 Javascript
微信小程序 两种为对象属性赋值的方式详解
2017/02/23 Javascript
nodeJS实现简单网页爬虫功能的实例(分享)
2017/06/08 NodeJs
JS中使用gulp实现压缩文件及浏览器热加载功能
2017/07/12 Javascript
荐书|您有一份JavaScript书单待签收
2017/07/21 Javascript
开发Vue树形组件的示例代码
2017/12/21 Javascript
浅析Vue项目中使用keep-Alive步骤
2018/07/27 Javascript
webpack 如何解析代码模块路径的实现
2019/09/04 Javascript
使用原生JS实现火锅点餐小程序(面向对象思想)
2019/12/10 Javascript
如何通过javaScript去除字符串两端的空白字符
2020/02/06 Javascript
Python 面向对象 成员的访问约束
2008/12/23 Python
python标准日志模块logging的使用方法
2013/11/01 Python
深入浅析Python传值与传址
2018/07/10 Python
使用pytorch实现可视化中间层的结果
2019/12/30 Python
Elasticsearch py客户端库安装及使用方法解析
2020/09/14 Python
超市中秋节活动方案
2014/02/12 职场文书
排查整治工作方案
2014/06/09 职场文书
条幅标语大全
2014/06/20 职场文书
汽车机电维修工求职信
2014/09/30 职场文书
企业内部管理控制:银行存款控制制度范本
2020/01/10 职场文书
golang 接口嵌套实现复用的操作
2021/04/29 Golang