CRM项目之stark组件自动生成url 1

stark组件简单来说是帮助开发者快速实现数据库表的增删查改。

前期知识储备

django项目启动时,自定义执行某个py文件

定制一个功能,在django启动项目时,自动触发某个py文件的执行。django启动时,且在读取项目中路由之前执行某个py文件。

在django的每个应用下都有一个apps.py这个文件,在这个文件中的Config类中定义ready方法,并在ready方法中调用autodiscover_modules(‘文件名’)。

from django.utils.module_loading import autodiscover_modules

class RbacConfig(AppConfig):
    name = 'rbac'
    
    def ready(self):
        autodiscover_modules('xxx')

django在启动时,就会去已注册的所有app的目录下找xxx.py文件,并自动导入(先在自己目录下查找,如果没有再去其他已注册app下查找)。因为django启动项目会执行已注册的apps.py的Config类的ready方法。

xxx.py文件

print('rbac 的xxx文件')

启动项目时输出的log
在这里插入图片描述
细心的已经发现了相同的log打印了两次,是因为django项目启动了两次。这是django的机制,有两个线程一个是启动项目,一个是检测代码是否有改变,当检测到代码改变时会自动重启项目。如果不想要这个功能在启动时执行python manage.py runserver 127.0.0.1:8081 --noreload即可。

python模块导入特性

在python中如果已经导入过的文件再次被重新导入时,python不会重新解释一遍,而是选择从内存中直接将原来导入的值拿来使用。即模块导入多次,只解释执行一次。

可以通过这种方式来实现最简单的单例模式。

django路由分发的本质(include)

通过阅读include源码可以发现,include函数返回的时一个有三个元素的元组(urlconf_module, app_name, namespace),元组的第一个元素是从字符串变成app.urls的对象(即urls.py文件导入的对象),通过此对象可以获取urls.urlpatterns获取分发的路由。

由此get到了路由分发的第二种编写方式:

from app01 import urls
urlpatterns = [
	url(r'^web/' (urls, app_name, namespace))
]

在源码内部读取路由时,如果第一个参数有urls.urlpatterns,那么子路由就从该属性中获取;如果第一个参数无urls.urlpatterns属性,那么子路由就是第一个参数。

由此get到了路由分发的第三种编写方式:

from app01 import urls
urlpatterns = [
	url(r'^web/' ([
		url(r'^index/', veiws.index),
		url(r'^home/', veiws.home),
	], app_name, namespace))
]

知识点结合的小例子

新建一个django项目,其目录结构如下:
在这里插入图片描述

settings.py中注册两个app

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'app01.apps.App01Config',
    'app02.apps.App02Config',
]

利用模块实现的单例模式,在一个人文件中导入并写入内容,另一个文件中导入读取内容。
my_site.py

from django.conf.urls import url
from app01 import views

class StarkSite():
    def __init__(self):
        self._register = []

    def get_urls(self):
        patterns = []
        for app in self._register:
            patterns.append(url(r'{}/'.format(app), views.index))
        return patterns


    @property
    def urls(self):
        return (self.get_urls(), None, None)


site = StarkSite()

app01/xxx.py

from my_site import site
site._register.append('app1')

app02/xxx.py

from my_site import site
site._register.append('app2')

app01/apps.py

from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules

class App01Config(AppConfig):
    name = 'app01'

    def ready(self):
        autodiscover_modules('xxx')

app02/apps.py

from django.apps import AppConfig
from django.utils.module_loading import autodiscover_modules


class App02Config(AppConfig):
    name = 'app02'

    def ready(self):
        autodiscover_modules('xxx')

项目下的urls.py

from django.conf.urls import url
from django.contrib import admin
from my_site import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^web/', site.urls)
]

实现的功能时给web下的路由分发添加了app1,app2。
在这里插入图片描述
代码执行流程:

  1. 项目启动,顺序执行已注册app的AppxxConfig类的ready方法
  2. ready方法中的autodiscover_modules(‘xxx’)执行,从当前app目录下查找xxx.py文件,如果没有去其他已注册的app下查找,查找到这个文件进行导入
  3. 在app01导入xxx.py模块时,会解释执行xxx.py中的代码,在xxx.py中导入了from my_site import site,找到my_site.py这个文件,解释执行my_site.py文件,会产生一个StarkSite类的实例化对象并放在内存中,site指向这个内存地址。
  4. 向site对象中的__register添加分发的路由字符串值
  5. 在app02导入xxx.py模块时,解释执行xxx.py文件,在xxx.py中导入了`from my_site import site,在内存中发下这个文件已经导入过了,直接拿到对于内存地址,向site对象中的__register添加分发的路由字符串值
  6. 在app01下的xxx.py和app02下的xxx.py文件拿到的是同一个实例化对象,基于模块实现的单例模式,导入多次解释执行一次,在app01和app02均可以想这个对象中增加内容。
  7. 在项目下的url.py中调用site.urls就可以获取到一个url对象列表来进行路由分发
  8. 执行路由分发

自动生成url

对于app下的每个表都自动生成四个url,对应增删改查,有连个app,三个表其内容如下
app01/models.py

class Depart(models.Model):
    title = models.CharField(verbose_name="部门名称", max_length=32)

    def __str__(self):
        return self.title


class UserInfo(models.Model):
    name = models.CharField(verbose_name="用户名", max_length=32)
    age = models.CharField(verbose_name="年龄", max_length=32)
    mail = models.CharField(verbose_name="邮箱", max_length=32)
    depart = models.ForeignKey(verbose_name="部门", to='Depart')

    def __str__(self):
        return self.name

app02/models.py

class Host(models.Model):
    host = models.CharField(verbose_name="主机名", max_length=32)
    ip = models.GenericIPAddressField(verbose_name='IP', protocol='both')

期望生成的url格式为:app名/类名小写/list/

/app01/depart/list/
/app01/depart/add/
/app01/depart/change/(?P<pk>\d+)/
/app01/depart/delete/(?P<pk>\d+)/
...
/app02/host/delete/(?P<pk>\d+)/

单例模式的py文件内容:stark/service/v1.py

from django.conf.urls import url
from django.shortcuts import HttpResponse

# 视图函数的基类,传递要操作的模型类
class StarkHandle(object):
    def __init__(self, model_class):
        self.model_class = model_class
        print(self.model_class)

    def change_list_view(self, request):
        return HttpResponse('列表页面')

    def add_view(self, request):
        return HttpResponse('新增页面')

    def change_view(self, request, pk):
        return HttpResponse('修改页面')

    def delete_view(self, request, pk):
        return HttpResponse('删除页面')


class StarkSite(object):
    def __init__(self):
        self._registry = []
        self.name = 'stark'
        self.namespace = 'stark'

    def get_urls(self):
    	# 自动扫描self._registry中的内容,生成url对象列表
        urls = []
        for item in self._registry:
            model_class = item.get('model_class')
            handle = item.get('handle')
            urls.append(url(r'^{}/{}/list/$'.format(model_class._meta.app_label, model_class._meta.model_name),
                            handle.change_list_view))
            urls.append(url(r'^{}/{}/add/$'.format(model_class._meta.app_label, model_class._meta.model_name),
                            handle.add_view))
            urls.append(url(r'^{}/{}/change/(?P<pk>\d+)/$'.format(model_class._meta.app_label, model_class._meta.model_name),
                            handle.change_view))
            urls.append(url(r'^{}/{}/delete/(?P<pk>\d+)/$'.format(model_class._meta.app_label, model_class._meta.model_name),
                            handle.delete_view))
        return urls

    @property
    def urls(self):
    	# 返回的是元组 ([url对象列表], name, namespace), 路由分发的第三种编写格式
        return self.get_urls(), self.name, self.namespace

    def register(self, model_class, handle_class=StarkHandle):
    	# 注册每个app下的模型类,和其操作模型类的handle类的实例化对象
        self._registry.append({'model_class': model_class, 'handle': handle_class(model_class)})
site = StarkSite()

在app目录下创建stark.py,在app下的appConfig类中ready方法下autodiscover_modules(‘stark’),stark.py文件内容,向site中注册模型类和操作模型类的类

from stark.service.v1 import site, StarkHandle
# 用户可以继承StarkHandle类,重写其中的视图函数实现不同的独有的功能
class HostHandle(StarkHandle):
    pass

site.register(Host, HostHandle)
from app01.models import Depart, UserInfo
from stark.service.v1 import site, StarkHandle


class DepartHandle(StarkHandle):
    pass


site.register(UserInfo)  # 使用默认的StarkHandle类,做处理url对应的视图函数类
site.register(Depart, DepartHandle)

在项目的urls.py中使用,自动生成的url

from django.conf.urls import url
from django.contrib import admin
from stark.service.v1 import site
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'stark/', site.urls)
]

效果:
为每个app下的每个表生成个增删查改四个url和其对于的视图函数
在这里插入图片描述
在这里插入图片描述

自动生成url的改进

增加用户自定义url前缀

1.改进分析:

在某些场景下用户需要对url增加一些前缀,如给list增加private前缀和publick前缀,生成两套url

stark/ ^app01/userinfo/private/list/$
stark/ ^app01/userinfo/publicl/ist/$

针对于不同人群展示不同的url信息的场景,要在注册时将用户自定制的前缀信息传入。

2.代码实现:

class StarkSite(object):
    def get_urls(self):
        urls = []
        for item in self._registry:
            model_class = item.get('model_class')
            handle = item.get('handle')
            prev = item.get('prev')
            app_label, model_name = model_class._meta.app_label, model_class._meta.model_name
			# 根据用户是否传入prev前缀,生成不同的url
            if prev:
                urls.append(url(r'^{}/{}/{}/list/$'.format(app_label, model_name, prev),
                                handle.change_list_view))
                urls.append(url(r'^{}/{}/{}/add/$'.format(app_label, model_name, prev),
                                handle.add_view))
                urls.append(url(r'^{}/{}/{}/change/(?P<pk>\d+)/$'.format(app_label, model_name, prev),
                                handle.change_view))
                urls.append(url(r'^{}/{}/{}/delete/(?P<pk>\d+)/$'.format(app_label, model_name, prev),
                                handle.delete_view))
            else:
                urls.append(url(r'^{}/{}/list/$'.format(app_label, model_name),
                                handle.change_list_view))
                urls.append(url(r'^{}/{}/add/$'.format(app_label, model_name),
                                handle.add_view))
                urls.append(url(r'^{}/{}/change/(?P<pk>\d+)/$'.format(app_label, model_name),
                                handle.change_view))
                urls.append(url(r'^{}/{}/delete/(?P<pk>\d+)/$'.format(app_label, model_name),
                                handle.delete_view))
        return urls

    def register(self, model_class, handle_class=StarkHandle, prev=None):
        """

        :param model_class: models中数据库表对应的类
        :param handle_class: 处理请求的视图函数所在的类
        :param prev: 生成url的前缀
        :return:
        """
        self._registry.append({'model_class': model_class, 'handle': handle_class(model_class), 'prev': prev})

site = StarkSite()

注册代码:

site.register(UserInfo, prev='private')  # 使用默认的StarkHandle类,做url对应的视图函数类
site.register(UserInfo, prev='public')  # 为url添加不同的前缀,一个表可以生成多种url

3.效果展示:
对于userinfo生成了两套url
在这里插入图片描述

用户自定义url内容

改进分析:

在上述代码中,我们添加增删查改功能都是直接写死的

urls.append(url(r'^{}/{}/list/$'.format(app_label, model_name),
                handle.change_list_view))
urls.append(url(r'^{}/{}/add/$'.format(app_label, model_name),
                handle.add_view))
urls.append(url(r'^{}/{}/change/(?P<pk>\d+)/$'.format(app_label, model_name),
                handle.change_view))
urls.append(url(r'^{}/{}/delete/(?P<pk>\d+)/$'.format(app_label, model_name),
                handle.delete_view))

这样自由度不够,要支持用户可以自定制增(add)删(delete)查(list)改(change)的后缀,如将删除的url修改为/app01/depart/del/(?P<pk>\d+)/

代码实现:
在做一层路由分发,urls.append(url(r'^{}/{}/list/$'.format(app_label, model_name),handle.change_list_view))修改为urls.append(url(r'^{}/{}/list/$'.format(app_label, model_name), ([], ))),url对象列表可以由用户来定制。

from django.conf.urls import url
from django.shortcuts import HttpResponse


class StarkHandle(object):
    """
    处理请求的视图函数所在的类,公共类
    """
    def __init__(self, model_class):
        self.model_class = model_class
        print(self.model_class)

    def change_list_view(self, request):
        return HttpResponse('列表页面')

    def add_view(self, request):
        return HttpResponse('新增页面')

    def change_view(self, request, pk):
        return HttpResponse('修改页面')

    def delete_view(self, request, pk):
        return HttpResponse('删除页面')

    def get_urls(self):
    	# 可以使用默认的,用户也可以重写这个方法来自定制生成的url对象列表
        patterns = [
            url(r'^list/$', self.change_view),
            url(r'^add/$', self.change_view),
            url(r'^change/(?P<pk>\d+)/$', self.change_view),
            url(r'^delete/(?P<pk>\d+)/$', self.delete_view),
        ]

        return patterns

class StarkSite(object):
    def get_urls(self):
        urls = []
        for item in self._registry:
            model_class = item.get('model_class')
            handle = item.get('handle')
            prev = item.get('prev')
            app_label, model_name = model_class._meta.app_label, model_class._meta.model_name
            if prev:
                # 在做一层路由分发, 路由分发函数由handle类中实现
                urls.append(url(r'^{}/{}/{}/'.format(app_label, model_name, prev), (handle.get_urls(), None, None)))  
            else:
                urls.append(url(r'^{}/{}/'.format(app_label, model_name), (handle.get_urls(), None, None)))
        return urls

使用,app01/stark.py

from django.shortcuts import HttpResponse
from django.conf.urls import url
from app01.models import Depart, UserInfo
from stark.service.v1 import site, StarkHandle


class DepartHandle(StarkHandle):
    def get_urls(self):
        # 自定义这个参数,动态控制url的生成,在此函数中为Depart表生成了三个url,去掉了修改的功能
        patterns = [
            url(r'^list/$', self.change_view),
            url(r'^add/$', self.change_view),
            url(r'^del/(?P<pk>\d+)/$', self.delete_view),
        ]
        return patterns


site.register(UserInfo, prev='private')  # 使用默认的StarkHandle类,做url对应的视图函数类
site.register(UserInfo, prev='public')  # 为url添加不同的前缀,一个表可以生成多种url
site.register(Depart, DepartHandle)

可以看到depart下的路由分发只有三个url,很方便的由用户来定制url
在这里插入图片描述
当用户要给表增加一个url时,我们需要将在原有的url的基础上再进行添加url,要添加一个用户对url进行添加的功能,增加一个extra_urls的方法,用户可以通过重写这个方法来新增url。

class StarkHandle(object):
    def get_urls(self):
    	# 默认的提供给用户的url,增删查改
        patterns = [
            url(r'^list/$', self.change_view),
            url(r'^add/$', self.change_view),
            url(r'^change/(?P<pk>\d+)/$', self.change_view),
            url(r'^delete/(?P<pk>\d+)/$', self.delete_view),
        ]
        # 将扩展的url添加到url对象列表中
        patterns.extend(self.extra_urls())
        return patterns

    def extra_urls(self):
	    # 扩展url
        return []

使用

class DepartHandle(StarkHandle):
    def extra_urls(self):
        # 用户添加url, 并在类中实现对应视图函数
        return [url(r'detail/(\d+)$', self.detail_view)]

    def detail_view(self, request, pk):
        return HttpResponse('详细页面')

site.register(Depart, DepartHandle)

在这里插入图片描述

为url设置别名

为了我们方便反向解析url,我们要为每个url设置别名,设置规格是每条url的别名都是不能重复的,并且每个url可以设置前缀,结合这两点我们的名字规则可以设置为:

  • 有前缀的列表页url app名字_模型类名小写_前缀名_list
  • 无前缀的列表页url app名字_模型类名小写_list

修改StarkHandle类,在初始化时接收prev前缀参数,定义property修饰的方法来获取url的别名。

class StarkHandle(object):
    """
    处理请求的视图函数所在的类,公共类
    """
    def __init__(self, model_class, prev):
        self.model_class = model_class
        self.prev = prev

    def change_list_view(self, request):
        return HttpResponse('列表页面')

    def add_view(self, request):
        return HttpResponse('新增页面')

    def change_view(self, request, pk):
        return HttpResponse('修改页面')

    def delete_view(self, request, pk):
        return HttpResponse('删除页面')

    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 "{}_{}_{}_{}".format(app_label, model_name, self.prev, param)

        return "{}_{}_{}".format(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_change_url_name(self):
        """
        获取修改页面url的name
        :return:
        """
        return self.get_url_name('change')

    @property
    def get_delete_url_name(self):
        """
        获取删除页面url的name
        :return:
        """
        return self.get_url_name('delete')

    def get_urls(self):
        patterns = [
            url(r'^list/$', self.change_view, name=self.get_list_url_name),
            url(r'^add/$', self.change_view, name=self.get_add_url_name),
            url(r'^change/(?P<pk>\d+)/$', self.change_view, name=self.get_change_url_name),
            url(r'^delete/(?P<pk>\d+)/$', self.delete_view, name=self.get_delete_url_name),
        ]
        patterns.extend(self.extra_urls())
        return patterns

    def extra_urls(self):
        return []

修改注册的功能代码,在实例化StarkHandle类时传递prev前缀

class StarkSite(object):

    def register(self, model_class, handle_class=StarkHandle, prev=None):
        """

        :param model_class: models中数据库表对应的类
        :param handle_class: 处理请求的视图函数所在的类
        :param prev: 生成url的前缀
        :return:
        """
        self._registry.append({'model_class': model_class, 'handle': handle_class(model_class, prev), 'prev': prev})

使用:自动生成了带特定规则的别名

site.register(UserInfo, prev='private')
site.register(UserInfo)

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在React项目中,使用mui的DataGridPro组件中的baseTooltip插槽,可以通过以下代码实现: ```jsx import { DataGridPro } from '@mui/x-data-grid-pro'; function CustomTooltip(props) { const { row, value } = props; return ( <div> <p>{`Row ${row.id}: ${value}`}</p> </div> ); } export default function App() { const columns = [ { field: 'id', headerName: 'ID', width: 70 }, { field: 'firstName', headerName: 'First name', width: 130 }, { field: 'lastName', headerName: 'Last name', width: 130 }, { field: 'age', headerName: 'Age', type: 'number', width: 90 }, ]; const rows = [ { id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 }, { id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 }, { id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 }, { id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 }, { id: 5, lastName: 'Targaryen', firstName: 'Daenerys', age: null }, { id: 6, lastName: 'Melisandre', firstName: null, age: 150 }, { id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 }, { id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 }, { id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 }, ]; return ( <div style={{ height: 400, width: '100%' }}> <DataGridPro rows={rows} columns={columns} components={{ baseTooltip: CustomTooltip, }} /> </div> ); } ``` 在上述代码中,我们定义了一个CustomTooltip组件作为baseTooltip的插槽,然后将其传递给DataGridPro组件的components属性中。CustomTooltip组件接收row和value两个props,分别表示当前行和当前单元格的值,组件可以根据这些信息自定义tooltip的内容和样式。最后,我们将DataGridPro组件渲染到页面上即可。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值