Django基于Admin原理实现的CURD组件
Django管理后台admin
常用共29个功能: 参考
- 在项目的app中的admin.py文件中注册models类,示例如下:
# cat app_name/admin.py
from django.contrib import admin
from django.contrib.admin import ModelAdmin
from . import models
from django.shortcuts import HttpResponse
from django.forms import ModelForm
from django.forms import fields
from django.forms import widgets
# 用户表,自定义admin后台错误信息提示
class UserModelForm(ModelForm):
others = fields.CharField()
class Meta:
model = models.UserInfo
fields = "__all__"
error_messages = {
'name':{'required':'用户名不能问空'}
}
class UserInfoModelAdmin(ModelAdmin):
# 使用自定义的form表单验证功能
form = UserModelForm
# 1.定义列表页面,显示列数据
list_display = ['name','pwd','email']
def email(self, obj):
return obj.name + obj.pwd
email.empty_value_display = "默认为空时显示的值"
# 2.定义列表页面,列可以进行点击进入编辑页面
list_display_links = ['pwd']
# 3.定义列表页面,快速搜索
list_filter = ['ut']
# 4.定义列表页面,分页功能
list_per_page = 10
# 5. 列是否可编辑
list_editable = ['name']
# 6. 查询列
search_fields = ['name','pwd']
# 7. 是否在页面顶端显示保存按钮
# save_on_top = True
# 8. 下拉选项的批量操作,类似于批量删除功能
def func(self, request, queryset):
print(self, request, queryset)
id_list = request.POST.getlist('_selected_action')
# models.UserInfo.objects.filter(id__in=id_list).delete()
func.short_description = "批量初始化"
actions = [func, ]
# 9. 列表页面使用模板文件
change_list_template = ['xxx.html']
# raw_id_fields = ['ut',]
# fields = ['name']
# exclude = ['name',]
# 10. 分类展示
# fieldsets = (
# ('基本数据', {
# 'fields': ('name',)
# }),
# ('其他', {
# 'classes': ('collapse', 'wide', 'extrapretty'), # 'collapse','wide', 'extrapretty'
# 'fields': ('pwd', 'ut'),
# }),
# )
# 11.快速过滤
# filter_vertical = ("roles",)
filter_horizontal = ("roles",)
# 12. 排序
ordering = ['-id']
# 注册使用自定义的UserInfoModelAdmin类的页面展示规则
admin.site.register(models.UserInfo,UserInfoModelAdmin)
# 2. 用户类型表(基于ModelAdmin类)
class UserTypeModelAdmin(ModelAdmin):
list_display = ['title']
admin.site.register(models.UserType,UserTypeModelAdmin)
注: 默认使用ModelAdmin类进行后台操作,可以定义自己的calss,通过继承ModelAdmin类实现定制页面展示功能
- Django自带Admin原理
2.1 每注册一个model类,Django内部会生成4个对应的增删改查URL,如下所示:
URL:
/admin/app_name/model_name/
/admin/app_name/model_name/add/
/admin/app_name/model_name/1/change/
/admin/app_name/model_name/1/delete/
例:/admin/app01/userinfo/
2.2 内部实现机制
- 在app下面的admin.py文件中注册models类;
- Django程序在启动时会循环所有app下面的admin文件中注册的models类,为每个models类生成对应的增删改查4个URL;
- 每个注册的model类会封装一个用于处理当前类所对应的URL的view对象,用于处理CURD操作,默认为ModelAdmin类对象;
1. self.model=models.UserInfo
/admin/app01/userinfo/ obj1.changelist_view
/admin/app01/userinfo/add/ obj1.add_view
/admin/app01/userinfo/(\d+)/delete/ obj1.delete_view
/admin/app01/userinfo/(\d+)/change/ obj1.change_view
2. self.model=models.UserType
/admin/app01/usertype/ obj2.changelist_view
/admin/app01/usertype/add/ obj2.add_view
/admin/app01/usertype/(\d+)/delete/ obj2.delete_view
/admin/app01/usertype/(\d+)/change/ obj2.change_view
自定义实现CURD类似Admin功能
步骤
- 了解django启动时执行的启动文件顺序
- 制作启动文件
- settings.py配置文件中注册启动文件使全局生效
- 实现组件CURD业务逻辑
- 主要参考Django Admin的实现,利用单利模式和include原理实现路由分发
实现
假设组件app名称为: arya
- Django程序启动顺序
在程序启动时,django会根据配置项INSTALLED_APPS中注册的启动文件,遍历每个App下面对应的注册启动文件,在arya组件下面的app.py文件中实现ready方法激活启动文件,如下:
# arya/app.py
from django.apps import AppConfig
class AryaConfig(AppConfig):
name = 'arya'
# Django启动时自动扫描所有app下面的arya模块
def ready(self):
from django.utils.module_loading import autodiscover_modules
autodiscover_modules('arya')
- 在项目的setting.py文件中配置,激活组件,使全局生效,此时Django启动时,在完全启动前,便会扫描所有app下面的arya.py文件并加载生效
INSTALLED_APPS = [
...
'arya.apps.AryaConfig',
...
]
- 核心代码逻辑实现
# cat arya/seevice/v1.py
from django.conf.urls import url
from django.shortcuts import render, HttpResponse, redirect
class AryaConfig(object):
"""
每个models类的URL对应处理的View实现
"""
def __init__(self, model_class, site):
self.model_class = model_class
# View对象
self.site = site
@property
def urls(self):
partterns = [
url(r'^$', self.changelist_view),
url(r'^add/', self.add_view),
url(r'^(\d+)/change/$', self.change_view),
url(r'^(\d+)/delete/$', self.delete_view)
]
return partterns
def changelist_view(self, request):
"""
列表试图
:param request:
:return:
"""
# return HttpResponse("列表页面")
return render(request, 'arya/changelist.html')
def add_view(self, request):
"""
添加试图
:param request:
:return:
"""
return HttpResponse("添加试图")
def change_view(self, request):
"""
修改试图
:param request:
:return:
"""
return HttpResponse("修改试图")
def delete_view(self, request):
"""
删除试图
:param request:
:return:
"""
return HttpResponse("删除试图")
class AryaSite(object):
"""
实现类似于admin.site.register()功能
"""
# 存放所有的models类及对应处理UTRL的的view对象
def __init__(self):
self._registry = {}
def register(self, class_name, config_class):
"""
注册方法,封装对象
self._registry = {
module.UserInfo: obj1, # obj1 = AryaConfig(models.UserInfo,site),
module.UserType: obj2, # obj2 = AryaConfig(models.UserType,site),
}
:param class_name: models类
:param config_class: 对应的View类(AryaConfig)
:return:
"""
self._registry[class_name] = config_class(class_name, self)
@property
def urls(self):
"""
处理子路由
:return:
"""
partterns = [
url(r'^login/$', self.login),
url(r'^logout/$', self.logout),
]
# 循环self._registry属性里面的每一个元素,key为models类,value为URLS对应处理的类obj对象
for model_class, arya_config_obj in self._registry.items():
# 分别为app名称和models的类名称
print("*" * 50)
print(model_class._meta.app_label, model_class._meta.model_name)
app_model_name_urls = r'^{0}/{1}/'.format(model_class._meta.app_label, model_class._meta.model_name)
# arya_config_obj.urls self._registry字典中存放的values对象obj下面的urls方法
pt = url(app_model_name_urls, (arya_config_obj.urls, None, None))
partterns.append(pt)
# 3元组
return partterns, None, None
def login(self):
"""
登陆
:return:
"""
return redirect('login')
def logout(self):
"""
退出
:return:
"""
return redirect('login')
# 实例化,利用单例模式
site = AryaSite()
引入arya组件并使用
- 创建app,引入arya组件
创建多个app,并在每个app下面创建arya.py文件,用于实现CURD操作
django startapp app01
...
- 在app01下面创建models模型
# cat app01/models.py
from django.db import models
class UserType(models.Model):
"""
用户类型表
"""
title = models.CharField(max_length=32, verbose_name="用户类型")
class Meta:
verbose_name_plural = "用户类型表"
def __str__(self):
return self.title
class Role(models.Model):
"""
角色表
"""
caption = models.CharField(max_length=32, verbose_name="角色名")
class Meta:
verbose_name_plural = "角色表"
def __str__(self):
return self.caption
class UserInfo(models.Model):
"""
用户表
"""
username = models.CharField(max_length=32, verbose_name="用户名")
password = models.CharField(max_length=64, verbose_name="密码")
email = models.CharField(max_length=32, verbose_name="邮箱")
ut = models.ForeignKey(to="UserType", blank=True, verbose_name="用户类型")
roles = models.ManyToManyField(to="Role", blank=True, verbose_name="所属角色")
class Meta:
verbose_name_plural = "用户表"
def __str__(self):
return self.username
生成表结构并制作部分展示数据,可以直接在表中添加,也可以通过admin后台进行添加
在app01中的arya.py文件中注册models类并自定义实现展示UI
# cat app01/arya.py
from arya.service import v1
from . import models
# 自定义属性控制UI展示
class UserInfoConfig(v1.AryaConfig):
"""
自定义用户信息UI
"""
list_display = ['username', 'ut', 'roles', 'email']
class UserTypeConfig(v1.AryaConfig):
"""
自定义用户类型UI
"""
list_display = ['title']
class RoleConfig(v1.AryaConfig):
"""
自定义角色UI
"""
list_display = ['caption']
# 注册models
v1.site.register(models.UserInfo, UserInfoConfig)
v1.site.register(models.UserType, UserTypeConfig)
v1.site.register(models.Role, RoleConfig)
- 在项目中应用arya组件,使URL生效
#cat project_name/urls.py
from django.contrib import admin
from django.conf.urls import url
from arya.service import v1
from . import views
# url的第二个参数返回类型为([],None,None)的元组,源码见include方法
# 此处的login和logut也可以使用arya/service/v1.py文件中定义的路由,示例为自己实现
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 此处会生成对应的多个URL子路由
url(r'^arya/', v1.site.urls),
url(r'^index/$', views.index, name="index"),
url(r'^login/$', views.login, name="login"),
url(r'^logout/$', views.logout, name="logout"),
]
- 路由试图处理
# cat project_name/views.py
from django.shortcuts import render, redirect
from app01 import models
def login(request):
"""
登陆
:param request:
:return:
"""
if request.method == "GET":
return render(request, 'login.html')
else:
username = request.POST.get('username')
password = request.POST.get('password')
obj = models.UserInfo.objects.filter(username=username, password=password).first()
if obj:
request.session['userinfo'] = {'username': obj.username, 'is_login': True}
return redirect('index')
return render(request, 'login.html', {'msg': '用户名或密码错误'})
def logout(request):
"""
退出
:param request:
:return:
"""
if request.method == "GET":
return redirect('login')
def index(request):
"""
首页
:param request:
:return:
"""
if request.method == "GET":
return render(request, 'index.html')
- 项目URL
此时在项目的路由中已经存在对应增删改查的4个URL,如下所示:
# app_nmae 应用名
# models_name models类名小写
arya/app_name/models_name/
arya/app_name/models_name/add/
arya/app_name/models_name/(\d+)/change/
arya/app_name/models_name/(\d+)/delete/
# 在该示例中为:
http://127.0.0.1:8000/arya/app01/userinfo/
http://127.0.0.1:8000/arya/app01/userinfo/add/
http://127.0.0.1:8000/arya/app01/userinfo/()
....
- 扩展
在每个app下面的arya.py文件中继承arya组件中的service.v1.AryaConfig类,自己内部实现处理URL的view以及定制化操作
总结
至此,自定义实现的类似Django admin组件基本开发完成,能够满足models模型数据的CURD操作。在Django中作为app引入CustAdmin组件,然后在settings文件中注册后就
可以生效使用了,engoy it!
github