一、内容回顾
类可否作为字典的key
初级
举例:
class Foo(object): pass _registry = { Foo:123 } print(_registry)
执行输出:
{<class '__main__.Foo'>: 123}
说明说法是成立的。
中级
class User(object): pass class Role(object): pass class Bar(object): def __init__(self,b): self.b = b _registry = { User:Bar(User), Role:Bar(Role), } print(_registry)
执行输出:
{<class '__main__.Role'>: <__main__.Bar object at 0x00000158F1BFC668>, <class '__main__.User'>: <__main__.Bar object at 0x00000158F1B39320>}
高级
class User(object): pass class Role(object): pass class Bar(object): def __init__(self,b): self.b = b _registry = { User:Bar(User), Role:Bar(Role), } for k,v in _registry.items(): print(k, v.b)
执行输出:
<class '__main__.Role'> <class '__main__.Role'> <class '__main__.User'> <class '__main__.User'>
从结果上来看,k和v.b 结果是一样的!请记住这个例子,下面的内容会用到!
通过model获取app名和类名
创建一个项目untitled,注意:django版本为1.11
进入命令行,创建第二个应用
python manage.py startapp app02
修改settings.py,注册2个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', ]
修改 app01-->models.py,新建表名为UserInfo
from django.db import models # Create your models here. class UserInfo(models.Model): username = models.CharField(verbose_name="用户名",max_length=32)
修改 app02->models.py,新建表名为Role
from django.db import models # Create your models here. class Role(models.Model): title = models.CharField(verbose_name="名称", max_length=32)
使用2个命令,生成表
python manage.py makemigrations
python manage.py migrate
修改urls.py,添加路由和视图
from django.conf.urls import url from django.contrib import admin ###视图暂时写在这里 from django.shortcuts import HttpResponse from app01 import models as m1 from app02 import models as m2 def index(request): print(m1.UserInfo) print(m2.Role) return HttpResponse('ok') urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), ]
启动django项目,访问页面:
查看Pycharm控制台输出:
<class 'app01.models.UserInfo'> <class 'app02.models.Role'>
获取app名和类名
修改urls.py
from django.conf.urls import url from django.contrib import admin ###视图暂时写在这里 from django.shortcuts import HttpResponse from app01 import models as m1 from app02 import models as m2 def index(request): print(m1.UserInfo,m1.UserInfo._meta.app_label,m1.UserInfo._meta.model_name) print(m2.Role,m1.UserInfo._meta.app_label,m1.UserInfo._meta.model_name) return HttpResponse('ok') urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^index/', index), ]
刷新页面,查看Pycharm控制台输出:
<class 'app01.models.UserInfo'> app01 userinfo <class 'app02.models.Role'> app01 userinfo
可以发现,app名和表名,都出来了!
二、单例模式
举例1
新建文件a.py
class AdminSite(object): pass obj1 = AdminSite() obj2 = AdminSite() # id表示查看对象的内存地址 print(obj1,id(obj1)) print(obj2,id(obj2))
执行输出:
<__main__.AdminSite object at 0x000001A3175549E8> 1799982762472 <__main__.AdminSite object at 0x000001A3175549B0> 1799982762416
可以看出内存地址不一样,它不是单例模式!
举例2
修改a.py
class AdminSite(object): pass obj1 = AdminSite() obj2 = AdminSite()
创建c.py
import a print(a.obj1,id(a.obj1))
创建b.py
import a print(a.obj1,id(a.obj1)) import c
导入模块关系如下:
c导入了a,b导入了a,同时也导入到c。
那么a会重复导入吗?
执行b.py,输出:
<a.AdminSite object at 0x0000024FA2354E80> 2541047074432 <a.AdminSite object at 0x0000024FA2354E80> 2541047074432
内存地址一致,说明a没有重复导入,这个就是一个最简单的单例模式!
那么以后使用单例模式时,先声明一个类,再实例化。其它模块导入使用时,直接引用变量。
这样,就可以形成一个单例模式,节省内存!
举例3
修改a.py
class AdminSite(object): def __init__(self): self._registry = {} obj1 = AdminSite()
修改b.py
import a a.obj1._registry['k1'] = 11 import c print(a.obj1._registry)
修改c.py
import a a.obj1._registry['k2'] = 22
执行b.py,输出:
{'k2': 22, 'k1': 11}
其它调用者,就可以操作同一个字典。如果key重名,那么后执行,覆盖前端的!
三、路由系统
include
修改untitled项目的urls.py,增加路由
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^rbac/', include('app01.urls')), ]
在app01目录下创建文件urls.py
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^login/', views.login), url(r'^logout/', views.logout), ]
修改app01-->views.py
from django.shortcuts import render,HttpResponse # Create your views here. def login(request): return HttpResponse('login') def logout(request): return HttpResponse('logout')
访问登录页面:http://127.0.0.1:8000/rbac/login/
路由就相当于
url(r'^/rbac/login/', views.login),
再分发一层
修改app01-->urls.py
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^login/', views.login), url(r'^logout/', include('app01.urls2')), ]
修改app01-->urls2.py
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^x1/', views.x1), url(r'^x2/', views.x2), ]
修改app01-->views.py
from django.shortcuts import render,HttpResponse # Create your views here. def login(request): return HttpResponse('login') def logout(request): return HttpResponse('logout') def x1(request): return HttpResponse('x1') def x2(request): return HttpResponse('x2')
访问url:http://127.0.0.1:8000/rbac/logout/x1/
那么路由就相当于这样
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^/rbac/login/', views.login), url(r'^/rbac/logout/x1/', views.login), url(r'^/rbac/logout/x2/', views.login), ]
name
name是为了做url反向解析的
修改app01-->urls.py
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^login/', views.login, name='login'), url(r'^logout/', include('app01.urls2')), ]
修改app01-->urls2.py
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^x1/', views.x1, name='x1'), url(r'^x2/', views.x2, name='x2'), ]
namespace
namespace是为防止url重名
修改 untitled-->urls.py,这个是总路由
from django.conf.urls import url,include from django.contrib import admin urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^rbac/', include('app01.urls',namespace='rbac')), ]
修改app01-->urls.py
from django.conf.urls import url,include from app01 import views urlpatterns = [ url(r'^login/', views.login, name='login'), url(r'^logout/', include('app01.urls2',namespace='logout')), ]
那么urls2.py里面的路由,使用反向解析时,就相当于
rbac:logout:x1
rbac:logout:x2
总结:
include可以随意分层,namespace反向解析时,必须带上命名空间。
假设django没有提供include,怎么办?
看include源码,它返回了3个值
return (urlconf_module, app_name, namespace)
注意:return返回多个值时,它是一个元组!
修改urls.py,修改rbac,它必须返回3个值。最后面的rbac是命名空间
url(r'^/rbac/', (None,None,'rbac')),
再修改,完整代码如下:
第一个值是最重要的,另外2个参数为None也无所谓
from django.conf.urls import url,include from django.contrib import admin from app01 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^rbac/', ([ url(r'^login/', views.login, name='login'), url(r'^logout/', views.logout, name='logout'), ],None,'rbac')), ]
重启django程序,访问页面:http://127.0.0.1:8000/rbac/login/
再分发一次,修改urls.py,要指定3个值
url(r'^rbac/', ([ url(r'^login/', views.login, name='login'), url(r'^logout/', views.logout, name='logout'), url(r'^x1/', (None,None,None)), ],None,'rbac')),
进阶修改
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^rbac/', ([ url(r'^login/', views.login, name='login'), url(r'^logout/', views.logout, name='logout'), url(r'^x1/', ([ url(r'^add/', views.add, name='add'), url(r'^change/', views.change, name='change'), ],None,None)), ],None,'rbac')), ]
修改 app01-->views.py
from django.shortcuts import render,HttpResponse from django.urls import reverse # Create your views here. def login(request): url1 = reverse('rbac:add') print(url1) return HttpResponse('login') def logout(request): return HttpResponse('logout') def x1(request): return HttpResponse('x1') def x2(request): return HttpResponse('x2') def add(request): return HttpResponse('add') def change(request): return HttpResponse('change')
重启django程序,访问页面:http://127.0.0.1:8000/rbac/login/
查看Pycharm控制台输出:
/rbac/x1/add/
可以看到,能反向解析出url
修改urls.py,更改命名空间为xxx
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^rbac/', ([ url(r'^login/', views.login, name='login'), url(r'^logout/', views.logout, name='logout'), url(r'^x1/', ([ url(r'^add/', views.add, name='add'), url(r'^change/', views.change, name='change'), ],None,'xxx')), ],None,'rbac')), ]
修改 app01-->views.py,指定命名空间
重启django程序,访问页面:http://127.0.0.1:8000/rbac/login/
查看Pycharm控制台输出,效果同上
有些项目录音没有写在urls.py里面,那么在其它地方,肯定有操作urlpatterns变量的!
查看admin路由
创建超级用户
python manage.py createsuperuser
修改 app01-->admin.py,注册表
from django.contrib import admin from app01 import models # Register your models here. admin.site.register(models.UserInfo)
登录admin后台,点击表userinfo
查看的url为:
http://127.0.0.1:8000/admin/app01/userinfo/
点击添加,url为
http://127.0.0.1:8000/admin/app01/userinfo/add/
点击修改,url为
http://127.0.0.1:8000/admin/app01/userinfo/1/change/
点击删除,url为
http://127.0.0.1:8000/admin/app01/userinfo/1/delete/
注意:这些URL是自动添加的,执行这一行代码,就添加了4个URL
admin.site.register(models.UserInfo)
它是在路由加载之前操作的!
每一个应用,都有admin.py。它一定是在路由加载之前,就添加了路由!
否则上述几个页面是无法访问的。
那么它是如何做的呢?查看admin模块源码
def autodiscover(): autodiscover_modules('admin', register_to=site)
它调用了autodiscover方法,它是用来做自动发现的。用来动态添加路由!
上面的'admin'指的是admin模块。它会自动寻找每一个应用名下的admin.py文件,并加载!
四、stark组件
stark组件介绍
stark组件是根据Django admin为原型写的一个组件,能够让我们告别增删改查.stark组件是可插拔试的组件,
移植性强,而且只用配置文件就能够得到想要的数据。
注意:这个不是django的组件。是自己根据admin为原型开发的!并没有统一的标准。
stark名字的由来
stark来源于《冰与火之歌》里面的史塔克。
史塔克家族是北境最古老也是最重要的家族,是北境各大小封臣的总领主,在被伊耿一世征服之前曾是独立数千年的北境之王。
名字叫啥都可以,看你的爱好了!貌似大家都会叫stark组件。
为什么要用stark组件
虽然django 提供的admin后台,能快速对一个表做增加改查。但是在生成环境中,是不会用admin后台的。
因为admin只是提供了简单的功能,在企业复杂环境中,需要自己定制功能。那么开发一套适合企业环境的stark组件,尤为重要!比如项目设计到几十张表的时候!
初始工作
创建应用stark并注册
在untitled项目的基础上,创建一个应用stark
这个应用,是专门做增删改查的!
python manage.py startapp stark
修改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', 'stark.apps.StarkConfig', ]
修改 stark-->apps.py
from django.apps import AppConfig class StarkConfig(AppConfig): name = 'stark' def ready(self): # 导入自动发现模块 from django.utils.module_loading import autodiscover_modules # 查找每一个应用下的stark模块,也就是stark.py autodiscover_modules('stark')
注意:这里导入了自动发现模块,并指定模块为stark。那么它会读取settings.py里面注册的每一个应用。并查找应用下的stark.py文件是否存在。存在就加载,否则不加载!
在app01和app02目录下,分别创建stark.py
修改 app01-->stark.py,内容如下:
print(666)
重启django项目,查看Pycharm控制台输出:
666 666
它会执行2次,至于为什么会执行2次。这个就不知道了!
启动步骤
1. 读取配置文件,找到stark组件
2. 在路由匹配之前,会查找所有app名下的stark.py文件
3. 执行stark.py,在路由里面添加数据
注意:如果要应用stark组件,其他应用比如创建stark.py。并做相关配置,就可以使用stark组件了!
配置stark组件
在stark应用目录下,创建server目录,在此目录下新建文件stark.py
class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'start' self.namespace = 'start' def register(self,model_class): # 添加键值对,固定值为1 self._registry[model_class] = 1 print(self._registry) # 打印字典 site = AdminSite() # 实例化类
修改 app01-->stark.py
# 这里的site,指的是实例化后的变量名 from stark.server.stark import site from app01 import models site.register(models.UserInfo) # 注册表
修改 app02-->stark.py
# 这里的site,指的是实例化后的变量名 from stark.server.stark import site from app02 import models site.register(models.Role) # 注册表
重启django项目,查看Pycharm控制台输出:
{<class 'app01.models.UserInfo'>: 1} {<class 'app01.models.UserInfo'>: 1, <class 'app02.models.Role'>: 1} {<class 'app01.models.UserInfo'>: 1} {<class 'app02.models.Role'>: 1, <class 'app01.models.UserInfo'>: 1}
注意:如果输入内容为空!那是因为stark应用下的apps.py没有配置ready方法!!!
由于字典是无序的,所有显示的顺序和大家可能不一样。不要诧异!
从上面的输出,可以看出。现在字典有2个值,分别是
<class 'app02.models.Role'>: 1和<class 'app01.models.UserInfo'>: 1
这是一个单例模式,app01和app02共同操作了同一个字典_registry
修改 stark-->server-->stark.py
class StarkConfig(object): def __init__(self,model_class): self.b = model_class class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'start' self.namespace = 'start' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class self._registry[model_class] = stark_config(model_class) # print(self._registry) # 打印字典 for k, v in self._registry.items(): print(k, v.b) # print(id(k), id(v.b)) site = AdminSite() # 实例化类
重启django项目,查看Pycharm控制台输出:
<class 'app01.models.UserInfo'> <class 'app01.models.UserInfo'> <class 'app02.models.Role'> <class 'app02.models.Role'> <class 'app01.models.UserInfo'> <class 'app01.models.UserInfo'> <class 'app01.models.UserInfo'> <class 'app01.models.UserInfo'> <class 'app02.models.Role'> <class 'app02.models.Role'> <class 'app01.models.UserInfo'> <class 'app01.models.UserInfo'>
从上面的结果可以看出,k和v.b的值是一样的!
为什么k和v.b的值是一样的呢?请参考文章的开头《类可否作为字典的key》里面的高级用法!
需要注意的是,stark_config(model_class)等同于StarkConfig(model_class)
还是一个就是if not None问题。
看一下app01是如何注册UserInfo表的
site.register(models.UserInfo) # 注册表
它并没有传入参数stark_config。那么register方法,会调用stark_config的默认参数,也就是None
修改 stark-->server-->stark.py,把key改规范一点
class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'start' self.namespace = 'start' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { models.UserInfo:StarkConfig(models.UserInfo) models.Role:StarkConfig(models.Role) } """ for k, v in self._registry.items(): print(k,v.model_class) site = AdminSite() # 实例化类
重启django项目,查看Pycharm控制台输出,效果同上!
修改 app02-->stark.py,注册表时,传一个参数
# 这里的site,指的是实例化后的变量名 # StarkConfig表示类 from stark.server.stark import site,StarkConfig from app02 import models class RoleConfig(StarkConfig): pass site.register(models.Role,RoleConfig) # 注册表
修改 stark-->server-->stark.py,打印k和v
class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'start' self.namespace = 'start' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ for k, v in self._registry.items(): print(k,v) site = AdminSite() # 实例化类
重启django项目,查看Pycharm控制台输出
<class 'app01.models.UserInfo'> <stark.server.stark.StarkConfig object at 0x000001DEF35A09B0> <class 'app02.models.Role'> <app02.stark.RoleConfig object at 0x000001DEF35A0860> <class 'app01.models.UserInfo'> <stark.server.stark.StarkConfig object at 0x000001DEF35A09B0> <class 'app01.models.UserInfo'> <stark.server.stark.StarkConfig object at 0x000001FD23D209E8> <class 'app01.models.UserInfo'> <stark.server.stark.StarkConfig object at 0x000001FD23D209E8> <class 'app02.models.Role'> <app02.stark.RoleConfig object at 0x000001FD23D20898>
可以发现,现在_registry字典有2个值了。key和value是不一样的
{
app01.models.UserInfo:StarkConfig(app01.models.UserInfo),
app02.models.Role:RoleConfig(app02.models.Role)
}
UserInfo对应StarkConfig,Role对应RoleConfig。
为什么是这样的呢?请参数面向对象的继承,因为时间关系,没法一一细说。
注意:self指的是实例化对象。如果实例化了StarkConfig,那么self就是StarkConfig类!
下面是一个面向对象的小练习,如果能弄懂,那么上面的结果,也就明白了
""" 第一个列子 class StarkConfig(object): def __init__(self, model_class,site): self.model_class = model_class self.site = site def func(self): print(666) class RoleConfig(StarkConfig): def func(self): print(999) obj1 = StarkConfig(11,22) obj1.func() # obj1是谁的对象?StarkConfig obj2 = RoleConfig(44,55) obj2.func() # obj2是谁的对象?RoleConfig对象 """ """ 第二个列子 class StarkConfig(object): def __init__(self, model_class, site): self.model_class = model_class self.site = site def func(self): print(666) def run(self): self.func() class RoleConfig(StarkConfig): def func(self): print(999) obj1 = StarkConfig(11,22) obj1.run() # 666 obj2 = RoleConfig(44,55) obj2.run() # 999 # self到底是谁?self是谁就是哪个类中先开始超找 """ """ 第三个列子 class StarkConfig(object): def __init__(self, model_class, site): self.model_class = model_class self.site = site def func(self): print(self.site) def run(self): self.func() class RoleConfig(StarkConfig): def func(self): print(self.site) obj1 = StarkConfig(11,22) obj1.run() # 22 obj2 = RoleConfig(44,55) obj2.run() # 55 """
修改 stark-->server-->stark.py,增加urls方法
第一个值是列表,这样做的目的,是为路由分发。
class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ for k, v in self._registry.items(): print(k,v) @property def urls(self): # self.app_name和self.namespace值是一样的,都是stark return [],self.app_name,self.namespace site = AdminSite() # 实例化类
修改untitled-->urls.py,这个是总路由。导入site
from django.conf.urls import url,include from django.contrib import admin from app01 import views from stark.server.stark import site urlpatterns = [ url(r'^admin/', admin.site.urls), # site.urls等同于[],'stark','stark' url(r'^stark/', site.urls), url(r'^rbac/', ([ url(r'^login/', views.login, name='login'), url(r'^logout/', views.logout, name='logout'), url(r'^x1/', ([ url(r'^add/', views.add, name='add'), url(r'^change/', views.change, name='change'), ],None,'xxx')), ],None,'rbac')), ]
修改 stark-->server-->stark.py,增加get_urls方法
class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ for k, v in self._registry.items(): print(k,v) def get_urls(self): urlpatterns = [] return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(),self.app_name,self.namespace site = AdminSite() # 实例化类
修改 stark-->server-->stark.py,增加视图函数x1,x2
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def x1(self, request): return HttpResponse('stark x1') def x2(self, request): return HttpResponse('stark x2') def get_urls(self): urlpatterns = [] urlpatterns.append(url(r'^x1/',self.x1)) urlpatterns.append(url(r'^x2/', self.x2)) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(),self.app_name,self.namespace site = AdminSite() # 实例化类
修改untitled-->urls.py,这个是总路由。删除多余的代码
from django.conf.urls import url,include from django.contrib import admin from app01 import views from stark.server.stark import site urlpatterns = [ url(r'^admin/', admin.site.urls), # 导入stark组件的路由 url(r'^stark/', site.urls), ]
重启django项目,访问url: http://127.0.0.1:8000/stark/x1/
还可以再做一次路由分发
修改 stark-->server-->stark.py,增加4个路径
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def x1(self, request): return HttpResponse('stark x1') def x2(self, request): return HttpResponse('stark x2') def get_urls(self): urlpatterns = [] urlpatterns.append(url(r'^x1/',self.x1)) urlpatterns.append(url(r'^x2/', self.x2)) urlpatterns.append(url(r'^x3/', ([ url(r'^add/', self.x1), url(r'^change/', self.x1), url(r'^del/', self.x1), url(r'^edit/', self.x1), ],None,None))) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(),self.app_name,self.namespace site = AdminSite() # 实例化类
重启django项目,访问url: http://127.0.0.1:8000/stark/x3/add/
这样写太麻烦了,使用for循环
修改 stark-->server-->stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def x1(self, request): return HttpResponse('stark x1') def x2(self, request): return HttpResponse('stark x2') def get_urls(self): urlpatterns = [] # urlpatterns.append(url(r'^x1/',self.x1)) # urlpatterns.append(url(r'^x2/', self.x2)) # urlpatterns.append(url(r'^x3/', ([ # url(r'^add/', self.x1), # url(r'^change/', self.x1), # url(r'^del/', self.x1), # url(r'^edit/', self.x1), # ],None,None))) for k, v in self._registry.items(): # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 app_label = k._meta.app_label model_name = k._meta.model_name # 为每一个表,添加增删改查的url urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), ([ url(r'^add/', self.x1), url(r'^change/', self.x1), url(r'^del/', self.x1), url(r'^edit/', self.x1), ],None,None))) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(),self.app_name,self.namespace site = AdminSite() # 实例化类
重启django项目,访问userinfo表的添加方法
http://127.0.0.1:8000/stark/app01/userinfo/add/
效果如下:
但是urlpatterns固定了,这样不好
修改 stark-->server-->stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def x1(self, request): return HttpResponse('stark x1') def x2(self, request): return HttpResponse('stark x2') def get_urls(self): urlpatterns = [ url(r'^list/$', self.x1), url(r'^add/$', self.x1), url(r'^(?P<pk>d+)/change/', self.x1), url(r'^(?P<pk>d+)/del/', self.x1), ] return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(),self.app_name,self.namespace site = AdminSite() # 实例化类
视图函数的名字不够规范,需要改名
修改 stark-->server-->stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def change_list(self, request): return HttpResponse('stark list') def change_add(self, request): return HttpResponse('stark add') def change_form(self, request, pk): return HttpResponse('stark form') def change_del(self, request, pk): return HttpResponse('stark del') def get_urls(self): urlpatterns = [ url(r'^list/$', self.change_list), url(r'^add/$', self.change_add), url(r'^(?P<pk>d+)/change/', self.change_form), url(r'^(?P<pk>d+)/del/', self.change_del), ] # for k, v in self._registry.items(): # # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 # app_label = k._meta.app_label # model_name = k._meta.model_name # urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None))) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(), self.app_name, self.namespace site = AdminSite() # 实例化类
某一个表要增加方法呢?可以定义extra_url方法,用来扩展
修改 stark-->server-->stark.py
注意:这里要来一个大的变动。将AdminSite相关代码移植到StarkConfig,并在StarkConfig增加extra_url方法
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site def change_list(self, request): return HttpResponse('stark list') def change_add(self, request): return HttpResponse('stark add') def change_form(self, request, pk): return HttpResponse('stark form') def change_del(self, request, pk): return HttpResponse('stark del') def get_urls(self): info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [ url(r'^list/$', self.change_list), url(r'^add/$', self.change_add), url(r'^(?P<pk>d+)/change/', self.change_form), url(r'^(?P<pk>d+)/del/', self.change_del), ] extra = self.extra_url() if extra: # 判断变量不为空 # 扩展路由 urlpatterns.extend(extra) return urlpatterns def extra_url(self): # 额外的路由,由调用者重构 pass @property def urls(self): return self.get_urls() class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def get_urls(self): urlpatterns = [] for k, v in self._registry.items(): # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 app_label = k._meta.app_label model_name = k._meta.model_name urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None))) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(), self.app_name, self.namespace site = AdminSite() # 实例化类
修改 app02-->stark.py,重构extra_url方法。添加新的路由
# 这里的site,指的是实例化后的变量名 # StarkConfig表示类 from stark.server.stark import site,StarkConfig from app02 import models from django.conf.urls import url from django.shortcuts import HttpResponse class RoleConfig(StarkConfig): def sk2(self, request): return HttpResponse('sk2神仙水') def extra_url(self): data = [ url(r'^sk2/$', self.sk2), ] return data site.register(models.Role,RoleConfig) # 注册表
重启django项目,访问新增加的url:
http://127.0.0.1:8000/stark/app02/role/sk2/
效果如下:
那么role表,就有5个url了。
而userinfo表,只有4个url
查看admin相关源码,将url改成和admin的一致
修改 stark-->server-->stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site def changelist_view(self, request): return HttpResponse('stark list') def add_view(self, request): return HttpResponse('stark add') def change_view(self, request, pk): return HttpResponse('stark change') def delete_view(self, request, pk): return HttpResponse('stark delete') def get_urls(self): info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [ url(r'^list/$', self.changelist_view), url(r'^add/$', self.add_view), url(r'^(?P<pk>d+)/change/', self.change_view), url(r'^(?P<pk>d+)/del/', self.delete_view), ] extra = self.extra_url() if extra: # 判断变量不为空 # 扩展路由 urlpatterns.extend(extra) return urlpatterns def extra_url(self): # 额外的路由,由调用者重构 pass @property def urls(self): return self.get_urls() class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def get_urls(self): urlpatterns = [] for k, v in self._registry.items(): # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 app_label = k._meta.app_label model_name = k._meta.model_name urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None))) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(), self.app_name, self.namespace site = AdminSite() # 实例化类
增加别名
修改 stark-->server-->stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse class StarkConfig(object): def __init__(self,model_class,site): self.model_class = model_class self.site = site def changelist_view(self, request): return HttpResponse('stark list') def add_view(self, request): return HttpResponse('stark add') def change_view(self, request, pk): return HttpResponse('stark change') def delete_view(self, request, pk): return HttpResponse('stark delete') def get_urls(self): info = self.model_class._meta.app_label, self.model_class._meta.model_name urlpatterns = [ url(r'^list/$', self.changelist_view, name='%s_%s_changelist' % info), url(r'^add/$', self.add_view, name='%s_%s_add' % info), url(r'^(?P<pk>d+)/change/', self.change_view, name='%s_%s_change' % info), url(r'^(?P<pk>d+)/del/', self.delete_view, name='%s_%s_del' % info), ] extra = self.extra_url() if extra: # 判断变量不为空 # 扩展路由 urlpatterns.extend(extra) return urlpatterns def extra_url(self): # 额外的路由,由调用者重构 pass @property def urls(self): return self.get_urls() class AdminSite(object): def __init__(self): self._registry = {} self.app_name = 'stark' self.namespace = 'stark' def register(self,model_class,stark_config=None): # not None的结果为Ture if not stark_config: # 也就是说,当其他应用调用register时,如果不指定stark_config参数 # 那么必然执行下面这段代码! # stark_config和StarkConfig是等值的!都能实例化 stark_config = StarkConfig # 添加键值对,实例化类StarkConfig,传入参数model_class # self指的是AdminSite类 self._registry[model_class] = stark_config(model_class,self) # print(self._registry) # 打印字典 """ { app01.models.UserInfo:StarkConfig(app01.models.UserInfo) app02.models.Role:RoleConfig(app02.models.Role) } """ # for k, v in self._registry.items(): # print(k,v) def get_urls(self): urlpatterns = [] for k, v in self._registry.items(): # k=modes.UserInfo,v=StarkConfig(models.UserInfo), # 封装:model_class=UserInfo,site=site对象 # k=modes.Role,v=RoleConfig(models.Role) # 封装:model_class=Role,site=site对象 app_label = k._meta.app_label model_name = k._meta.model_name urlpatterns.append(url(r'^%s/%s/' % (app_label, model_name,), (v.urls, None, None))) return urlpatterns @property def urls(self): # 调用get_urls方法 # self.app_name和self.namespace值是一样的,都是stark return self.get_urls(), self.app_name, self.namespace site = AdminSite() # 实例化类
重启django项目,访问url:
http://127.0.0.1:8000/stark/app02/role/list/
效果如下:
从django启动,到每一个表,生成了4个URL。这中间经历了复杂的过程!
流程图
说明:
注意以app01为例:
1. 启动时,执行settings.py。加载INSTALLED_APPS里面的app,从上到下执行!
2.执行到stark应用时,执行apps.py。执行ready方法,调用autodiscover_modules方法!
它会查找每一个app应用下的stark.py文件,并执行文件!
3. 执行stark.py时,执行from stark.server.stark import site。它会调用stark-->server-->stark.py里面的site
site执行了实例化
4. 再执行site.register(models.UserInfo)。它会调用stark-->server-->stark.py里面的register方法
执行self._registry[model_class] = stark_config(model_class,self),调用StarkConfig的__init__方法
self._registry增加key-value。value就是StarkConfig类
5.执行总路由,也就是urls.py,调用site.urls。这里的site就是stark-->server-->stark.py里面的site
执行AdminSite的urls方法。注意,它加了@property。所以可以site.urls执行方法。
6.它里面调用了get_urls方法,执行for循环,将url添加到urlpatterns列表中。以app01的userinfo表为列
url(r'^%s/%s/' % (app_label, model_name,)就相当于url(r'^app01/userinfo/',)
后面的(v.urls, None, None),它是一个元组。这就相当于执行了include。include它返回一个元组。必须有3个值
这里的v.urls,指的就是StarkConfig.urls。为什么v是StarkConfig类?看步骤4的key-value
7. 执行StarkConfig类的urls方法,注意:它加了@property,可以不需要括号,就可以执行。
8. 它调用了get_urls方法。这里的self就是StarkConfig类。执行get_urls方法里面的urlpatterns,它加了4个URL,用来做增删改查的。
9. 判断app应用下start.py是否重构了extra_url方法。如果是,执行自己应用下的extra_url方法。它必须返回一个列表。
这里只有app02重构了extra_url方法。返回了一个列表。执行urlpatterns.extend(extra)。表示在urlpatterns列表中添加一个列表。
10. 此时在总路由中,urlpatterns数据结构如下:
urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^stark/', ([ url(r'^app01/userinfo/', ([ url(r'^list/$', self.changelist_view, name='app01_userinfo_changelist'), url(r'^add/$', self.add_view, name='app01_userinfo_add'), url(r'^(?P<pk>d+)/change/', self.change_view, name='app01_userinfo_change'), url(r'^(?P<pk>d+)/del/', self.delete_view, name='app01_userinfo_del'), ],None,None)), ],None,'stark')), ]
所以可以访问一下url:
http://127.0.0.1:8000/stark/app01/userinfo/list/
效果如下:
完整代码,请访问github