项目要求:
模仿django自带的admin组件,开发一套属于我们自己的start组件
今日项目重点:
重点一:单例模式,需要理解基于模块的单例模式具体是怎么回事,及其作用
重点二:路由的二级分发
重点三:对于self什么情况指的是理解
首先,我们先来说一下基于模块的单例模式,
单例顾名思义就是只有一个实例
我们现在一个py文件里定义好如下的类
class F: def __init__(self,name): self.name=name def sname(self): print(self.name) f=F('alex')
print('ok')
然后在另一个py文件中导入我们实例化的对象小f
from 基础知识.a import f print(id(f)) from 基础知识.a import f print(id(f)) #输出结果
#ok #1845270931384 #1845270931384
我们明明导入了两次模块 为啥只打印出一个ok呐 因为这是python独有的一个机制 它会把第一次导入的模块 保存到一个地方 如果下面还导入模块 并不会使用 而是从第一个那拿 我们所需要的
但是,如果导入的是大F,那就相当于重新实例化得到一个新的对象 而每一个对象都有属于自己的一块内存空间
from 基础知识.a import F print(id(F('alex'))) print(id(F('alex'))) #输出结果 # ok # 3024850486216 # 3024850485320
如果对类与对象的内存不是很清楚 可以看下图
路由的二级分发:
首先来介绍一个路由分发的一个标准([],None,None)列表中 放分发的路由,第一个None是,,,第二个None指的是app暂时用不到 我们先用None来代替
二级路由分发的最基本的方式:
这么写的话 路由分发少的时候 还好 如果路由分发很多的时候 就会很乱 所以我们可以用下列方法代替
self:
在我们看源码去封装一个功能或者理解源码是什么意思的时候 我们一定要注意一个问题 那就是self到底指的是哪个对象
只有确定了这一点才能继续往走 self所代表的对象不同 整个类所要做的事当然也就不同 就向我们之前所说的 每个类的实例化对象
即使实例化的值是一样的但是还是完全不同的两个对象
下面开始我们的项目:
首先第一步 我们要先重新建一个django项目,
然后在命令行里 重新创建一个项目用来写我们自定义的stark组件的源代码
然后在app01下加入stark
接下来就需要我们进去配置文件中将stark配置成项目启动 stark也会跟着启动
然后将stark中的app里加一个启动文件
接下来我们测试一下,在app01下的stark.py文件中加print("ok")然后启动django项目看看 会不会直接打印ok
测试成功 说明我们的准备工作已经做好
先在stark文件下建一个service的包 ,并在里面创建一个stark.py
然后在url里导入 跟admin一样做成一个方法 项目启动就可以执行 项目启动就能执行
然后我们再去导入的文件里写我们自定义的源码
class ModelStark(): def __init__(self,model): self.model = model class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model, self) site = StarkSite()
这就是个单例生成的对象都是相同的所以所占的把内存空间都是相同 那_register字典里的值不会重置,只要生成一个对象就会添加一对键值对 这就是单例的好处
接下来我们需要写路由分发
class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) def get_urls(self): temp = [ ] for model_class, config_obj in self._registry.items(): print("===>", model_class, config_obj) model_name = model_class._meta.model_name app_label = model_class._meta.app_label print("===>", app_label, model_name) temp.append(url(r'^%s/%s/' % (app_label, model_name), config_obj.urls)) ''' 创建url: url("app01/book/$",self.list_view), url("app01/book/add$",self.add_view), url("app01/book/(d+)/change/$",self.change_view), url("app01/book/(d+)/delete/$",self.delete_view), url("app01/publish/$",self.list_view), url("app01/publish/add$",self.add_view), url("app01/publish/(d+)/change/$",self.change_view), url("app01/publish/(d+)/delete/$",self.delete_view), ''' return temp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
因为我们将urls封装成属性 所以我们可以在url中 直接加点调用一个函数
这里要声明一个问题,如果按照下面的写法,会出现一个问题
class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request,id): return HttpResponse("change_view") def delete_view(self, request,id): return HttpResponse("delete_view") def get_urls(self): temp=[ url("^$",self.list_view), url("^add/$",self.add_view), url("^(d+)/change_view/$",self.change_view), url("^(d+)/delete_view$",self.delete_view), ] return temp @property def urls(self): return self.get_urls(),None,None def get_urls1(self): temp = [ ] for model_class, config_obj in self._registry.items(): print("===>", model_class, config_obj) model_name = model_class._meta.model_name app_label = model_class._meta.app_label print("===>", app_label, model_name) temp.append(url(r'^%s/%s/' % (app_label, model_name), config_obj.urls)) ''' 创建url: url("app01/book/$",self.list_view), url("app01/book/add$",self.add_view), url("app01/book/(d+)/change/$",self.change_view), url("app01/book/(d+)/delete/$",self.delete_view), url("app01/publish/$",self.list_view), url("app01/publish/add$",self.add_view), url("app01/publish/(d+)/change/$",self.change_view), url("app01/publish/(d+)/delete/$",self.delete_view), ''' return temp @property def urls(self): return self.get_urls1(), None, None site = StarkSite()
因为site = StarkSite()是单例所以会导致不管谁来调用self都是相同的 这就会导致所有的页面的样式都会是相同的 ,这就违背了 我们要写的组件 我们要写的组件就是为了可实现,页面可以自定义
以下就是完整的路由分发
from django.conf.urls import url from django.shortcuts import HttpResponse,redirect,render class ModelStark(): def __init__(self,model): self.model = model def list_view(self,request): #用户访问的模型表: self.model print("self.model:",self.model) print("self.list_display",self.list_display) queryset=self.model.objects.all() return render(request,"stark/list_view.html",{'queryset':queryset}) def add_view(self, request): return HttpResponse("add_view") def change_view(self, request,id): return HttpResponse("change_view") def delete_view(self, request,id): return HttpResponse("delete_view") def get_urls(self): temp=[ url("^$",self.list_view), url("^add/$",self.add_view), url("^(d+)/change_view/$",self.change_view), url("^(d+)/delete_view$",self.delete_view), ] return temp @property def urls(self): return self.get_urls(),None,None class StarkSite(object): def __init__(self): self._registry = {} def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) def get_urls1(self): temp = [ ] for model_class, config_obj in self._registry.items(): print("===>", model_class, config_obj) model_name = model_class._meta.model_name app_label = model_class._meta.app_label print("===>", app_label, model_name) temp.append(url(r'^%s/%s/' % (app_label, model_name), config_obj.urls)) ''' 创建url: url("app01/book/$",self.list_view), url("app01/book/add$",self.add_view), url("app01/book/(d+)/change/$",self.change_view), url("app01/book/(d+)/delete/$",self.delete_view), url("app01/publish/$",self.list_view), url("app01/publish/add$",self.add_view), url("app01/publish/(d+)/change/$",self.change_view), url("app01/publish/(d+)/delete/$",self.delete_view), ''' return temp @property def urls(self): return self.get_urls1(), None, None site = StarkSite()
但是我们还会遇到一个问题:前端页面传值
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body> <h3>数据展示</h3> <ul> {% for item in queryset %} <li>{{ item }}</li> {% endfor %} </ul> </body> </html>
这就需要我们告诉前端页面需要打印什么字段
这就用到自定义
from app01 import models from stark.service.strak import site,ModelStark class BookConfig(ModelStark): list_display = ["title","price"] site.register(models.Book,BookConfig) site.register(models.Publish) site.register(models.Author) site.register(models.AuthorDetail)
自定义样式如何在前端页面展示 我们下个博客更新
还有一点 本文并没有写models 不过建表就需要自己动手了