Django中自定义admin Xadmin的实现代码

在Django框架中,自带一个后台管理页面admin,这个管理页面很全,但是,有些并不是我们需要的,所以我们可以根据admin的实现流程来自定义自己的需求,即根据admin的实现方式来实现自定制--Xadmin

首先,我们先解析admin的流程,在Django中,我们在创建项目的时候,Django自带一个admin的url,实现了不同模型表的增删改查,那么admin是如何实现url的分发的?

我们可以从三部分来看admin的路由分发实现

1,启动

我们可以通过from django.contrib import admin来看admin是如何启动的

Django启动后,会在manage.py文件中加载配置文件settings.py  ,在settings.py中有一个INSTALLED_APPS这个配置项,Django会按照配置项的内容一次加载每一个app.

# Application definition

INSTALLED_APPS = [
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'Xadmin.apps.XadminConfig',
 'blogs.apps.BlogsConfig',
 'bigs.apps.BigsConfig',
]

加载到django.contrib.admin时,会加载admin相关的,我们点击admin,进入admin的__init__.py文件,

from django.contrib.admin.sites import AdminSite, site
from django.utils.module_loading import autodiscover_modules

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

执行auto_discover这个接口,会自动的加载所有APP中的admin.py这个文件,这就是admin的启动文件

2,注册

自动加载所有APP下的admin.py文件时,会一次记录所有执行了admin.site.register(模型类)这个方法的模型类,从而完成模型类的注册。

所有的模型类都执行admin.site.register()这个方法后完成的注册,那么这个方法内部都做了些什么?

我们可以点击site进入admin的源码中,得到这个:site = AdminSite()  site是一个对象,是AdminSite这个类的一个对象,并且是一个单例对象,那么我们就可以肯定,register是这个单例对象的一个方法,那这个方法中到底做了什么?

class AdminSite(object):
 """
 An AdminSite object encapsulates an instance of the Django admin application, ready
 to be hooked in to your URLconf. Models are registered with the AdminSite using the
 register() method, and the get_urls() method can then be used to access Django view
 functions that present a full admin interface for the collection of registered
 models.
 """
 def __init__(self, name='admin'):
 self._registry = {} # model_class class -> admin_class instance
 self.name = name
 # 关于register的方法
 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)
 #备注:截取的源码中的一部分 

示例site对象时,会生成一个self._registry={}这个对象属性,如果我们没有指定admin_class,那么admin_class就是ModelAdmin,由此可以看出,admin_class是admin提供给我们定制页面的一个自定义类,这个类必须继承ModelAdmin这个类,以下是:

class ModelAdmin(BaseModelAdmin):
 "Encapsulates all admin options and functionality for a given model."

 list_display = ('__str__',)
 list_display_links = ()
 list_filter = ()
 list_select_related = False
 list_per_page = 100
 list_max_show_all = 200
 list_editable = ()
 search_fields = ()
 date_hierarchy = None
 save_as = False
 save_as_continue = True
 save_on_top = False
 paginator = Paginator
 preserve_filters = True
 inlines = []

 # Custom templates (designed to be over-ridden in subclasses)
 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
 popup_response_template = None

 # Actions
 actions = []
 action_form = helpers.ActionForm
 actions_on_top = True
 actions_on_bottom = False
 actions_selection_counter = True
 checks_class = ModelAdminChecks

 def __init__(self, model, admin_site):
 self.model = model
 self.opts = model._meta
 self.admin_site = admin_site
 super(ModelAdmin, self).__init__()

 def __str__(self):
 return "%s.%s" % (self.model._meta.app_label, self.__class__.__name__)

所以不管有没有自定制样式类,都会执行self._registry[model] = admin_class(model, self),也就是说,注册一个模型类,就会在对象的_registry这个字典中添加一个键值对,这个键是我们注册的这个模型类 model,值是继承ModelAdmin的样式类或者ModelAdmin这个类的一个对象。

3,设计url

因为site是一个单例对象,所以admin在执行完所有admin.py文件后,就会得到整个全局的一个包含所有注册模型的字典_registry,得到这个self._registry(也就是admin.site对象)字典,我们可以for循环这个admin.site._registry字典,得到这些键值对,那么得到这些键值对有什么用呢?这就是admin设计url时会用到的。

我们访问admin这个后台管理页面会发现,这个页面关于我们注册的所有模型都会实现增删改查功能,每个功能界面对应不同的模型类时,除了数据不同外,是一样的,也就是说,admin对于不同的模型类用到是一套url,一套模板,那么这个url是怎么设计的呢?

我们分别访问不同的模型类的这四个功能页面,会发现一个规律:

查询页面url: http://IP:PORT/admin/app名/模型类的名字(全部小写)/

添加页面url:   http://IP:PORT/admin/app名/模型类的名字(全部小写)/add

编辑页面url:http://IP:PORT/admin/app名/模型类的名字(全部小写)/id值/change

删除页面url:http://IP:PORT/admin/app名/模型类的名字(全部小写)/id值/delete

通过这个规律可以看出url分发的实现

但是在这个实现的过程中,我们有一个需要注意的时,用户访问的请求携带的路径是一个字符串的类型,我们可以通过request.path得到用户访问的路径,也就能得到用户访问的是哪个APP下的哪个模型类,但是这两个参数都是字符串的类型,如何通过字符串得到用户访问的哪张表,这是个麻烦,这时,可能我们会想到使用importlib模块来得到这个类,但是,这样这个过程很麻烦,Django为我们封装好了相应的方法:我们可以通过这个模型类的类名,通过._meta.model_name这个方法得到对应的字符串形式的类名,同样的我们也可以通过这个类名._meta.app_label得到字符串格式的相应的APP名

# 使用model代指模型类的类名
model._meta.model_name #得到字符串格式的类名(全小写的)
model._meta.app_label #可以得到当前类所在APP的字符串的名字
# 补充
model._meta.get_field("字符串格式的字段属性") # 得到一个字段属性的对象field_obj,这样我们就可以利用这个字段对象取得属性                           # 比如: field_obj.verbose_name

通过这两个封装的方法,就完美的解决了我们头疼的问题

from django.conf.urls import url

from django.contrib import admin

def get_urls_operate():
 emp = []
 emp.append(url(r'^$',查询页面的视图函数))
 emp.append(url(r'^add/$',添加页面的视图函数))
 emp.append(url(r'^(\d+)/change/$',编辑页面的视图函数))
 emp.append(url(r'^(\d+)/delete/$',删除页面的视图函数))
 return emp

def get_urls():
 temp = []
 for model,main_class_obj in admin.site._registry.items():
 app_name = model._meta.app_label
 model_name = model._meta.model_name
 temp.append(url(r'^{}/{}/'.format(app_name,model_name),(get_urls_operate(),None,None))) #实现第二层路由的分发
 return temp

urlpatterns = [
 url(r'^Xadmin/',(get_urls(),None,None)) #自定义一个前缀 实现第一层路由的分发
]

这样我们就实现一个通过一个路由实现不同场景的分发

通过这三部分,我们可以按照admin的实现方式,来自定制Xadmin

我们了解了admin内部的实现流程,我们可以将这个实现过程封装到一个类中。

  我们自定制Xadmin时,也要按照admin的流程实现,首先是启动项,admin中,Django启动时,会自动的执行每个app下的admin.py文件,我们可以自定制为启动时,自动执行app下的每个自定制的.py文件,比如Xadmin.py 文件,那么如何达到Django启动的时候帮我们自动扫描加载我们自定制的Xadmin.py文件呢?这是个问题

  我们观察可以发现,Django在启动时,会加载配置文件settings.py ,在settings.py文件中,有一个INSTALLED_APPS这个列表,这个列表中,放置着我们在Django项目中的所有app的配置信息,我们观察这个列表:我们自己开启的APP,在设置配置信息时,会在APP名字后加一个.apps.(app名首字母大写)Config这个东西,而对应的在我们的app下,Django会给我们自动的配置一个apps.py文件,那么这个apps.py文件有什么作用呢,我们打开这个apps.py文件,看看里面的配置信息:

以blogs这个APP为例:

from django.apps import AppConfig
class BlogsConfig(AppConfig):
 name = 'blogs'

我们可以发现,里面定义了一个类,这个类的类名就是settings配置信息中apps后面跟的那个东东,这个类中有一个静态属性name是当前的APP名,这个类继承了AppConfig这个类。这就是我们从这个.py文件中所能得的所有东西,乍一看,没有什么有用的信息,那么我们只能从它继承的类中找了

MODELS_MODULE_NAME = 'models'
class AppConfig(object):
 """
 Class representing a Django application and its configuration.
 """
 def __init__(self, app_name, app_module):
 # Full Python path to the application eg. 'django.contrib.admin'.
 self.name = app_name

 def ready(self):
 """
 Override this method in subclasses to run code when Django starts.
    #这句话的语义为:在子类中重写此方法,以便在Django启动时运行代码
 """

查看整个AppConfig,我们可以把我们的要启动的代码放置在重写的ready方法中即可

from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules
class XadminConfig(AppConfig):
 name = 'Xadmin'
 def ready(self):
  autodiscover_modules('Xadmin') #Django启动时会自动扫描每个app下的Xadmin.py文件

这样,我们就完成了自定制Xadmin的启动阶段,启动后我们就要进行下一步注册

在每个app下的Xadmin.py 文件中注册模型

以blogs这个APP下的UserInfo、Book为例:

from blogs import models
from Xadmin.service.Xadmin import site
site.register(models.UserInfo)
site.register(models.Book)

接下了就是设计url了,我们可以仿照admin的方式,在单例对象admin.site的这个类中封装好这些方法

from django.conf.urls import url
from django.shortcuts import HttpResponse,render
class ModelXadmin(object):
 def __init__(self,model,site):
  self.model = model
  self.site = site
 def show(self,request):
  data_list = self.model.objects.all()
  return render(request,'show.html',locals()) #locals() 请函数内部所有的键值对存储 == {"data_list":data_list}
 def add(self,request):
  return HttpResponse('添加页面')
 def edit(self,request, pk):
  return HttpResponse('编辑页面')
 def delete(self,request, pk):
  return HttpResponse('删除页面')
 @property
 def get_urls_operate(self):
  emp = []
  emp.append(url(r'^$', self.show))
  emp.append(url(r'^add/$', self.add))
  emp.append(url(r'^(\d+)/change/$', self.edit))
  emp.append(url(r'^(\d+)/delete/$', self.delete))
  return emp
 @property
 def urls(self):
  return self.get_urls_operate,None,None
class XadminSite(object):
 def __init__(self,name='xadmin'):
  self._registry = {}
 def register(self,model,class_main=None,**option):
  if not class_main:
   class_main = ModelXadmin
  self._registry[model] = class_main(model,self)
 @property
 def get_urls(self):
  # print(admin.site._registry)
  temp = []
  for model, model_admin_object in self._registry.items():
   model_name = model._meta.model_name
   model_app = model._meta.app_label
   temp.append(url(r'^{}/{}/'.format(model_app, model_name), model_admin_object.urls))
  return temp
 @property
 def urls(self):
  return self.get_urls,None,None
site = XadminSite()

备注:一个关键点,为什么把第二层分发设置在了ModelXadmin这个类中,那肯定是放在这个类中能有什么好处,如果我们把这个二级分发放在XadminSite中,那么我们要取得每一个模型的数据是很麻烦的,但是,如果我们把这个放在ModelXadmin中,由于,在register(注册)时,我们给class_admin(XadminSite)传了每一个模型类,所以放在这个类中,我们可以通过self.model这个属性获得每个模型类的数据(self.model.objects.all()),这样就很容易得到这个模型表。

总结

以上所述是小编给大家介绍的Django中自定义admin Xadmin的实现代码 ,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

(0)

相关推荐

  • 对django xadmin自定义菜单的实例详解

    1. 自定义菜单 adminx.py class GlobalSetting(object): site_title = u'xxx后台' def kuF_site_menu(self): return [{ 'title': u'用户&账户', 'perm': self.get_model_perm(User, 'view'), 'icon':'fa fa-users', 'menus':( {'title': u'用户', 'url': self.get_model_url(User, 'c

  • 在django admin中添加自定义视图的例子

    django admin提供了完善的用户管理和数据模型管理,方便实用.研究了一下在admin里面添加自己的页面. 在admin.py里继承django.contrib.admin.ModelAdmin基类 class FaceAdmin(admin.ModelAdmin): 然后在里面写自己的视图处理函数.基类里面的save_model和delete_model函数可以做数据对象的新建和删除的预处理和后处理.自建的函数如果要redirect到自己建的view,反向映射要包含admin:,写成 r

  • Django 中自定义 Admin 样式与功能

    Django 中自定义 Admin 样式与功能 自定义 Admin 样式与功能 1 页面修改中文 1.1 语言设置为中文 settings.py LANGUAGE_CODE = 'zh-hans' 修改结果 1.2 应用管理设置为中文 应用/apps.py from django.apps import AppConfig class BbssConfig(AppConfig):     name = 'bbs'     # 添加下面这句     verbose_name = 'BBS系统' 修

  • Django2.1集成xadmin管理后台所遇到的错误集锦(填坑)

    django默认是有一个admin的后台管理模块,但是丑,功能也不齐全,但是大神给我们已经集成好了xadmin后台,我们拿来用即可,但是呢,django已经升级到2.1版本了,xadmin貌似跟不上节奏,那么在集成过程中咱就一步一步填坑吧,这也是一种学习的过程,遇到错误,找到错误的地方,看看django最新升级都修改了那些,去掉了那些,把相应出错的地方替换即可. xadmin源码地址:https://github.com/sshwsfc/xadmin 下载并解压: 我们用到的是xadmin文件夹

  • django+xadmin+djcelery实现后台管理定时任务

    继上一篇中间表的数据是动态的,图表展示的数据才比较准确.这里用到一个新的模块Djcelery,安装配置步骤如下: 1.安装 redis==2.10.6 celery==3.1.23 django-celery==3.1.17 flower==0.9.2 supervisor==3.3.4 flower用于监控定时任务,supervisor管理进程,可选 2.配置 settings.py中添加以下几行: #最顶头加上 from __future__ import absolute_import #

  • python3.4下django集成使用xadmin后台的方法

    环境:window7 x64.python3.4.django1.10 一.pip install xadmin安装报错 1.使用pip install xadmin命令安装可能报如下错误: 2.解决方案 亲测使用 pip install git+git://github.com/sshwsfc/xadmin.git 命令可以正常使用. 二.django项目中配置xadmin settings.py配置 INSTALLED_APPS = [ 'django.contrib.admin', 'dj

  • Django中自定义admin Xadmin的实现代码

    在Django框架中,自带一个后台管理页面admin,这个管理页面很全,但是,有些并不是我们需要的,所以我们可以根据admin的实现流程来自定义自己的需求,即根据admin的实现方式来实现自定制--Xadmin 首先,我们先解析admin的流程,在Django中,我们在创建项目的时候,Django自带一个admin的url,实现了不同模型表的增删改查,那么admin是如何实现url的分发的? 我们可以从三部分来看admin的路由分发实现 1,启动 我们可以通过from django.contri

  • Django 中自定义 Admin 样式与功能的实现方法

    自定义 Admin 样式与功能 1 页面修改中文 1.1 语言设置为中文 settings.py LANGUAGE_CODE = 'zh-hans' 修改结果 1.2 应用管理设置为中文 应用/apps.py from django.apps import AppConfig class BbssConfig(AppConfig): name = 'bbs' # 添加下面这句 verbose_name = 'BBS系统' 修改结果 1.3 数据库表设置为中文 应用/models.py class

  • Django中自定义模型管理器(Manager)及方法

    1.自定义管理器(Manager) 在语句Book.objects.all()中, objects 是一个特殊的属性,通过它来查询数据库,它就是模型的一个Manager. 每个Django模型至少有一个manager,你可以创建自定义manager以定制数据库的访问. 这里有两个方法创建自定义manager:添加额外的manager;修改manager返回的初始Queryset. 添加额外的manager 增加额外的manager是为模块添加 表级功能 的首选办法.(至于 行级功能 ,也就是只作

  • 在Django中自定义filter并在template中的使用详解

    Django内置的filter有很多,然而我们由于业务逻辑的特殊要求,有时候仍然会不够用,这个时候就需要我们自定义filter来实现相应的内容.接下来让我们从自定义一个get_range(value)来产生列表的filter开始吧. 首先在你的django app的models.py的同级目录建立一个templatetags的文件夹,并在里面新建一个init.py的空文件,这个文件确保了这个文件夹被当做一个python的包.在添加了templatetags模块之后,我们需要重新启动服务器才能使其

  • 在django中自定义字段Field详解

    Django的Field类中方法有: to_python() # 把数据库数据转成python数据 from_db_value() # 把数据库数据转成python数据 get_pre_value() # 把python数据压缩准备存入数据库 get_db_pre_value() # 把压缩好的数据转成数据库查询集 get_prep_lookup() # 指定过滤的条件 value_to_string() # 数据序列化 如果创建的Field比字符串,日期,整数等更复杂的数据结构,可能需要重写t

  • Android中自定义对话框(Dialog)的实例代码

    1.修改系统默认的Dialog样式(风格.主题) 2.自定义Dialog布局文件 3.可以自己封装一个类,继承自Dialog或者直接使用Dialog类来实现,为了方便以后重复使用,建议自己封装一个Dialog类 第一步: 我们知道Android定义个控件或View的样式都是通过定义其style来实现的,查看Android框架中的主题文件,在源码中的路径:/frameworks/base/core/res/res/values/themes.xml,我们可以看到,Android为Dialog定义了

  • Django中F函数的使用示例代码详解

    F()函数 F()函数的导入 from django.db.models import F 为什么要使用F()函数? 一个 F()对象代表了一个model的字段值或注释列.使用它就可以直接参考model的field和执行数据库操作而不用再把它们(model field)查询出来放到python内存中. 开发个人博客时,统计每篇文章浏览量的逻辑通常是这样写的: post = Post.objects.get(...) post.views += 1 post.save() 上面的语句已经相当简短了

  • 详解django中自定义标签和过滤器

    想要实现自定义标签和过滤器需要进行准备工作: 准备(必需)工作: 1  在某个app下创建一个名为templatetags(必需,且包名不可变)的包.假设我们在名为polls的app下创建了一个templatetags的包,并在该包下创建了一个名为mytags的文件.那么目录结构看起来应该就像这样: polls/ __init__.py models.py templatetags/ __init__.py mytags.py views.py 2  settings文件中的INSTALLD_A

  • Django中使用第三方登录的示例代码

    OAuth2.0是什么 OAuth的英文全称是Open Authorization,它是一种开放授权协议.OAuth目前共有2个版本,2007年12月的1.0版(之后有一个修正版1.0a)和2010年4月的2.0版,1.0版本存在严重安全漏洞,而2.0版解决了该问题. OAuth简单说就是一种授权的协议,只要授权方和被授权方遵守这个协议去写代码提供服务,那双方就是实现了OAuth模式. OAuth2.0实现第三方登录的流程 例如你想登录豆瓣去看看电影评论,但你丫的从来没注册过豆瓣账号,又不想新注

随机推荐