Day 76 CRM业务——stark组件
stark组件
介绍
stark 组件,是一个帮助开发者快速实现数据库表的增删改查+。
目标
10s 完成一张表的增删改查
前戏
1、django 项目启动时,自定义执行某个 py 文件
django 启动时,且在读取项目中 路由加载 之前执行某个 py 文件
在任意 app 的 apps.py 中的 Config 类中定义 ready 方法,并调用 autodiscover_modules
from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class App02Config(AppConfig): name = 'app02' def ready(self): autodiscover_modules('xxx')
django 在启动时们就会去已注册的所有 app 的目录下找 xxx.py 并自动导入。
如果发现执行了两次,是因为 django 内部的自动重启导致的:
使用命令:python manage.py runserver 127.0.0.1:8000 --noreload
pycharm:Edit Configurations ——> Additional options 输入: --noreload
提示:
如果 xxx.py 执行的代码向 "某个神奇的地方" 放入了一些值,之后的路由加载时,可以去"某个神奇的地方"读取到原来设置的值
2、单例模式
多例模式
class Foo: pass obj01 = Foo() obj01.name = 'ysg' print(obj01) # <__main__.Foo object at 0x000001D154C76128> obj02 = Foo() # print(obj02.name) # AttributeError: 'Foo' object has no attribute 'name' print(obj02) # <__main__.Foo object at 0x000001D154C76278>
单例模式
单:一个。
例:实例,对象
如果以后存在一个单例模式的对象,可以现在此对象中放入一个值,然后再在其他的文件中导入该对象,通过对象再次将值获取到。
commons.py
class Foo(): pass site = Foo()
app02.py
import commons print('app02:', commons.site.name)
app01.py
import commons app01 = commons.site app01.name = 'ysg' # <commons.Foo object at 0x0000021DF8C56208> print(app01) import commons app02 = commons.site print(app02.name) # ysg print(app02) # <commons.Foo object at 0x0000021DF8C56208> import app02 # <commons.Foo object at 0x0000029587E76198> # app02: ysg
通过 python 模块导入的特性,在 python 中,如果已经导入过的文件再次被重新的导入的时候,python不会在重新解释一遍,而是选择从内存中直接将原来的值拿来用,公用一块内存地址。
3、django路由分发的本质:include
方法一:
from django.conf.urls import url, include from django.contrib import admin urlpatterns = [ url(r'^rbac/', include(('rbac.urls', 'rbac'))), ]
方法二:
include 函数主要返回有是哪个元素的元组
第一个参数是 urls 文件对象,通过此对象可以获取 urls.patterns 获取分发的路由
from django.urls import path,re_path,include from django.conf.urls import url print('this is url') urlpatterns = [ url(r'web01/', (urls,app_name,namespace)) ]
方法三:
在源码内部,读取路由时:
如果第一个参数有:urls.patterns 属性,那么子路由就从该属性中获取。
如果第一个参数无:urls.patterns 属性,那么子路由就是第一个参数。
from django.contrib import admin from django.urls import path,re_path,include from django.conf.urls import url from app02 import views print('this is url') urlpatterns = [ path('admin/', admin.site.urls), path('index/', views.index), url(r'web01/', ([ url(r'^web/', views.index), url(r'^home/', views.login) ], 'appname', 'namespace')) ]
stark组件的准备工作
1、创建 django project
并创建 app01、app02、stark 三个应用
2、创建解除业务表
app01
部门表
class Depart(models.Model): ''' 部门表 ''' title = models.CharField(verbose_name='部门名称',max_length=32)
用户表
class UserInfo(models.Model): ''' 用户表 ''' name = models.CharField(verbose_name='用户名称',max_length=32) age = models.CharField(verbose_name='年龄',max_length=32) email = models.CharField(verbose_name='Email',max_length=32) depart = models.ForeignKey(verbose_name='部门ID',to=Depart,on_delete=models.CASCADE)
app02
class Host(models.Model): ''' 主机表 ''' host = models.CharField(verbose_name='主机名称',max_length=32) ip = models.GenericIPAddressField(verbose_name='IP')
数据库迁移
__init__.py
import pymysql pymysql.install_as_MySQLdb()
Terminal 命令行
python manage.py makemigrations
python manage.py migrate
stark组件实现
为 app 中的每个 model 类自动创建 URL 以及相关视图函数
url.py
from django.contrib import admin from django.urls import path from django.conf.urls import url from stark.service.v1 import site urlpatterns = [ path('admin/', admin.site.urls), url(r'^stark/', site.urls), ]
app01/models.py
from django.db import models # Create your models here. class Depart(models.Model): ''' 部门表 ''' title = models.CharField(verbose_name='部门名称',max_length=32) class UserInfo(models.Model): ''' 用户表 ''' name = models.CharField(verbose_name='用户名称',max_length=32) age = models.CharField(verbose_name='年龄',max_length=32) email = models.CharField(verbose_name='Email',max_length=32) depart = models.ForeignKey(verbose_name='部门ID',to=Depart,on_delete=models.CASCADE)
app02/models.py
from django.db import models # Create your models here. class Host(models.Model): ''' 主机表 ''' host = models.CharField(verbose_name='主机名称',max_length=32) ip = models.GenericIPAddressField(verbose_name='IP') class Role(models.Model): ''' 角色表 ''' title = models.CharField(verbose_name='角色名称',max_length=32)
app01/stark.py
from django.shortcuts import HttpResponse from stark.service.v1 import site from app01 import models class DepartHandler: def __init__(self, model_class): self.model_class = model_class def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('部门列表界面') def add_view(self, request): ''' 部门列表界面 :param request: :return: ''' pass def edit_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass def del_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass class UserInfoHandler: def __init__(self, model_class): self.model_class = model_class def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('用户列表界面') def add_view(self, request): ''' 部门列表界面 :param request: :return: ''' pass def edit_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass def del_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass site.register(models.Depart, DepartHandler) site.register(models.UserInfo, UserInfoHandler)
app02/stark.py
from django.shortcuts import HttpResponse from stark.service.v1 import site from app02 import models class HostHandler: def __init__(self, model_class): self.model_class = model_class def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('主机列表界面') def add_view(self, request): ''' 部门列表界面 :param request: :return: ''' pass def edit_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass def del_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass site.register(models.Host, HostHandler) class RoleHandler: def __init__(self, model_class): self.model_class = model_class def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('角色列表界面') def add_view(self, request): ''' 部门列表界面 :param request: :return: ''' pass def edit_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass def del_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' pass site.register(models.Role, RoleHandler)
v1.py
from django.conf.urls import url class StarkSite(object): def __init__(self): self._registry = [] self.app_name = 'stark' self.namespace = 'stark' def register(self, model_class, handler_class): ''' :param model_class: model 是数据库表对应的类 :param handler_class: 处理请求的视图函数所在的类 :return: ''' self._registry.append({'model_class': model_class, 'handler': handler_class(model_class)}) def get_urls(self): patterns = [] for item in self._registry: model_class = item['model_class'] handler = item['handler'] # model_class._meta.app_label 获取数据库表所在的应用名 # model_class._meta.model_name 获取数据库表的表名称 # print(model_class._meta.app_label,model_class._meta.model_name) app_label, model_name = model_class._meta.app_label, model_class._meta.model_name patterns.append(url(r'%s/%s/list/$' % (app_label, model_name), handler.list_view)) patterns.append(url(r'%s/%s/add/$' % (app_label, model_name), handler.add_view)) patterns.append(url(r'%s/%s/edit/(?P<pk>\d+)/$' % (app_label, model_name), handler.edit_view)) patterns.append(url(r'%s/%s/del/(?P<pk>\d+)/$' % (app_label, model_name), handler.del_view)) return patterns @property def urls(self): return self.get_urls(), self.app_name, self.namespace site = StarkSite()
stark组件开发之提取公共视图函数
# -*- coding: utf-8 -*- # @File : v1.py # @Date : 2020-06-16 # @Author : Administrator from django.conf.urls import url from django.shortcuts import render, HttpResponse # stark组件开发之提取公共视图函数 class StarkHandler: def __init__(self, model_class): self.model_class = model_class def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' data_list = self.model_class.objects.all() return render(request,'stark/changelist.html',locals()) def add_view(self, request): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('添加界面') def edit_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('编辑界面') def del_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('删除界面') # 为 app 中的每个 model 类自动创建 URL 以及相关视图函数 class StarkSite(object): def __init__(self): self._registry = [] self.app_name = 'stark' self.namespace = 'stark' def register(self, model_class, handler_class=None): ''' :param model_class: model 是数据库表对应的类 :param handler_class: 处理请求的视图函数所在的类 :return: ''' if not handler_class: handler_class = StarkHandler self._registry.append({'model_class': model_class, 'handler': handler_class(model_class)}) def get_urls(self): patterns = [] for item in self._registry: model_class = item['model_class'] handler = item['handler'] # model_class._meta.app_label 获取数据库表所在的应用名 # model_class._meta.model_name 获取数据库表的表名称 # print(model_class._meta.app_label,model_class._meta.model_name) app_label, model_name = model_class._meta.app_label, model_class._meta.model_name patterns.append(url(r'%s/%s/list/$' % (app_label, model_name), handler.list_view)) patterns.append(url(r'%s/%s/add/$' % (app_label, model_name), handler.add_view)) patterns.append(url(r'%s/%s/edit/(?P<pk>\d+)/$' % (app_label, model_name), handler.edit_view)) patterns.append(url(r'%s/%s/del/(?P<pk>\d+)/$' % (app_label, model_name), handler.del_view)) return patterns @property def urls(self): return self.get_urls(), self.app_name, self.namespace site = StarkSite()
stark组件开发之URL分发和默认Handler及别名
app01/stark.py
from django.shortcuts import HttpResponse from django.conf.urls import url from stark.service.v1 import site, StarkHandler from app01 import models class DepartHandler(StarkHandler): def extra_urls(self): return [url(r'^update/(?P<pk>\d+)/$', self.update_view)] def update_view(self, request, pk): return HttpResponse('修改密码') class UserInfoHandler(StarkHandler): pass site.register(models.Depart, DepartHandler, prev='one') site.register(models.Depart, DepartHandler) site.register(models.UserInfo, UserInfoHandler)
v1.py
class StarkHandler: # stark组件开发之提取公共视图函数 def __init__(self, model_class, prev): self.model_class = model_class self.prev = prev def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' data_list = self.model_class.objects.all() return render(request, 'stark/changelist.html', locals()) def add_view(self, request): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('添加界面') def edit_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('编辑界面') def del_view(self, request, pk): ''' 部门列表界面 :param request: :return: ''' return HttpResponse('删除界面') # stark组件开发之URL分发和默认Handler 及别名 def get_url_name(self, param): app_label, model_name = self.model_class._meta.app_label, self.model_class._meta.model_name if self.prev: return '%s_%s_%s_%s' % (app_label, model_name, self.prev, param) return '%s_%s_%s' % (app_label, model_name, param) @property def get_list_url_name(self): ''' 获取列表界面的 url 的 name :return: ''' return self.get_url_name('list') @property def get_add_url_name(self): ''' 获取添加界面的 url 的 name :return: ''' return self.get_url_name('add') @property def get_edit_url_name(self): ''' 获取编辑界面的 url 的 name :return: ''' return self.get_url_name('edit') @property def get_del_url_name(self): ''' 获取删除界面的 url 的 name :return: ''' return self.get_url_name('del') def get_urls(self): ''' 重写 get_urls 可以修改所要生成的 url,和减少 url :return: ''' patterns = [ url(r'^list/$', self.list_view, name=self.get_list_url_name), url(r'^add/$', self.add_view, name=self.get_add_url_name), url(r'^edit/(?P<pk>\d+)/$', self.edit_view, name=self.get_edit_url_name), url(r'^del/(?P<pk>\d+)/$', self.del_view, name=self.get_del_url_name), ] patterns.extend(self.extra_urls()) return patterns def extra_urls(self): ''' 重写 extra_urls 可以增加 url :return: ''' return []
stark组件开发之列表页面自定义函数扩展
app01/start.py
from stark.service.v1 import site, StarkHandler from django.utils.safestring import mark_safe from app01 import models class DepartHandler(StarkHandler): # 自定义页面显示的列(表头和内容) def display_edit(self, obj=None, is_header=None): if is_header: return '编辑' return mark_safe('<a href="#">编辑</a>') def display_del(self, obj=None, is_header=None): if is_header: return '删除' return mark_safe('<a href="#">删除</a>') list_display = ['id', 'title', display_edit, display_del]
v1.py
from django.conf.urls import url from django.shortcuts import render, HttpResponse from types import FunctionType # stark组件开发之提取公共视图函数 class StarkHandler: # 定制页面显示的列 list_display = [] def __init__(self, model_class, prev): self.model_class = model_class self.prev = prev def get_list_display(self): ''' 获取页面上应该显示的列,预留的自定义扩展。如:以后可以根据用户权限的不同显示对应的列 :return: ''' value = [] value.extend(self.list_display) return value def list_view(self, request): ''' 部门列表界面 :param request: :return: ''' # 1、处理表格的表头 # ###### stark 组件开发之列表页面定制列 ###### # 页面要显示的列 # 用户访问的表 models.UserInfo ['name','age','email','depart'] header_list = [] list_display = self.get_list_display() # 支持 StarkHandler 为空 if list_display: for key_or_fun in list_display: if isinstance(key_or_fun, FunctionType): verbose_name = key_or_fun(self, obj=None, is_header=True) else: verbose_name = self.model_class._meta.get_field(key_or_fun).verbose_name header_list.append(verbose_name) else: header_list.append(self.model_class._meta.model_name) # 处理表的内容 data_list = self.model_class.objects.all() body_list = [] for row in data_list: tr_list = [] if list_display: for key_or_fun in list_display: if isinstance(key_or_fun, FunctionType): tr_list.append(key_or_fun(self, row, is_header=False)) else: tr_list.append(getattr(row, key_or_fun)) else: tr_list.append(row) body_list.append(tr_list) return render(request, 'stark/changelist.html', locals())