Django基于Admin原理实现的CURD组件

Django基于Admin原理实现的CURD组件


Django管理后台admin

常用共29个功能: 参考

  1. 在项目的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类实现定制页面展示功能

  1. 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

  1. 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')
  1. 在项目的setting.py文件中配置,激活组件,使全局生效,此时Django启动时,在完全启动前,便会扫描所有app下面的arya.py文件并加载生效
INSTALLED_APPS = [
    ...
    'arya.apps.AryaConfig',
    ...
]
  1. 核心代码逻辑实现
# 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组件并使用

  1. 创建app,引入arya组件
创建多个app,并在每个app下面创建arya.py文件,用于实现CURD操作
django startapp app01
...
  1. 在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
  1. 生成表结构并制作部分展示数据,可以直接在表中添加,也可以通过admin后台进行添加

  2. 在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)
  1. 在项目中应用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"),
]
  1. 路由试图处理
# 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')
  1. 项目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/()
....
  1. 扩展
    在每个app下面的arya.py文件中继承arya组件中的service.v1.AryaConfig类,自己内部实现处理URL的view以及定制化操作

总结

至此,自定义实现的类似Django admin组件基本开发完成,能够满足models模型数据的CURD操作。在Django中作为app引入CustAdmin组件,然后在settings文件中注册后就
可以生效使用了,engoy it!

github

你可能感兴趣的:(Django基于Admin原理实现的CURD组件)