##CRM版本一实现功能
#1、新建一个stark组件 组件就是应用
一个项目可以有多个应用
一个应用可以用在多个项目中 #2、参考admin源码 实现路由分发 #3、数据展示 表头展示 表单展示 #4、自定义数据列 #5、反向解析 #掌握技术点 from app01 import models models.Book._meta.app_label #获得模型表所在的应用名'app01' models.Book._meta.model_name #获得模型表对应的字符串名'book' from app01 import models models.Book._meta.get_field('title') <django.db.models.fields.CharField: title> # 获取字段对象 models.Book._meta.get_field('title').verbose_name '书名' models.Book._meta.get_field('price').verbose_name # 获取字段对象verbose_name属性 当你没有指定的时候默认是字段字符串名'price'
##models 模型表结构
from django.db import models # Create your models here. class Author(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) age=models.IntegerField() # 与AuthorDetail建立一对一的关系 authorDetail=models.OneToOneField(to="AuthorDetail",on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): nid = models.AutoField(primary_key=True) birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) def __str__(self): return self.addr class Publish(models.Model): nid = models.AutoField(primary_key=True) name=models.CharField( max_length=32) city=models.CharField( max_length=32) email=models.EmailField() def __str__(self): return self.name class Book(models.Model): nid = models.AutoField(primary_key=True) title = models.CharField(max_length=32,verbose_name='书名') publishDate=models.DateField(verbose_name='出版日期') price=models.DecimalField(max_digits=5,decimal_places=2, verbose_name='价格') # 与Publish建立一对多的关系,外键字段建立在多的一方 publish=models.ForeignKey(to="Publish",to_field="nid",on_delete=models.CASCADE) # django 2.0版本必须写 1.0默认 # 与Author表建立多对多的关系,ManyToManyField可以建在两个模型中的任意一个,自动创建第三张表 authors=models.ManyToManyField(to='Author',) def __str__(self): return self.titleView Code
##修改启动文件 C:\starkpro\stark\apps.py
启动 django一启动就要执行每一个应用下的stark.py(单独新建的一个文件)文件(django默认会启动admin.py文件) 配置文件中注册 INSTALLED_APPS = [ 'stark.apps.StarkConfig', ] 在StarkConfig类中 固定写ready方法 from django.apps import AppConfig from django.utils.module_loading import autodiscover_modules class StarkConfig(AppConfig): name = 'stark' def ready(self): # 项目启动就会自动查找每一个应用下的stark.py文件 return autodiscover_modules('stark')
##注册源码
#模拟Django应用程序下每一个admin.py文件注册功能 #路径: C:\starkpro\stark\service\stark.py #基础注册模板: class ModelStark(object): def __init__(self,model): self.model = model class StarkSite(object): def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) @property def urls(self): return self.get_urls(), None, None site = StarkSite() #配置路由urls:注意:自定义生成的site对象点urls,这里的urls不是属性而是一个方法被property修饰的方法 from django.conf.urls import url from django.contrib import admin from stark.service.stark import site urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^stark/', site.urls), ]
##开始实现一级路由分发:C:\starkpro\stark\service\stark.py
from django.conf.urls import url from django.shortcuts import HttpResponse class ModelStark(object): def __init__(self,model): self.model = model class StarkSite(object): def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) def test(self,request): return HttpResponse('test') def get_urls(self): #先定义一个列表,因为要给调用者返回列表 tmp = [] #循环字典_registry for model_class,config_obj in self._registry.items(): # print(model_class) #<class 'app01.models.Author'> 类字符串 # print(config_obj) #<stark.service.stark.ModelStark object at 0x000001A79CC58C18> 配置类对象 #获得模型表所在的应用名 app_label = model_class._meta.app_label # 获得模型表对应的字符串名 model_name = model_class._meta.model_name tmp.append( url(r'^%s/%s/'%(app_label,model_name),self.test) ) return tmp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
##stark二级路由设计
用配置对象解决二级路由。解决的问题是:不同表对应不同的对象,展示到页面上的内容也不一样,一次不能直接使用同一对象site来进行路由二级分发,不然不同路径内容却是一样的 操作文件:C:\starkpro\stark\service\stark.py from django.conf.urls import url from django.shortcuts import HttpResponse class ModelStark(object): def __init__(self,model): self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样 def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 print(self.model) return HttpResponse('list') def add_view(self, request): return HttpResponse('add') def edit_view(self, request, id): return HttpResponse('edit') def delete_view(self, request, id): return HttpResponse('delete') @property def urls(self): #此处的self是指配置类对象 tmp = [ url(r'^$',self.list_view), url(r'^add/',self.add_view), url(r'^edit/(\d+)/',self.edit_view), url(r'^delete/(\d+)/',self.delete_view), ] return tmp,None,None class StarkSite(object): def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) def test(self,request): return HttpResponse('test') def get_urls(self): #先定义一个列表,因为要给调用者返回列表 tmp = [] #循环字典_registry for model_class,config_obj in self._registry.items(): # print(model_class) #<class 'app01.models.Author'> 类字符串 # print(config_obj) #<stark.service.stark.ModelStark object at 0x000001A79CC58C18> 配置类对象 #获得模型表所在的应用名 app_label = model_class._meta.app_label # 获得模型表对应的字符串名 model_name = model_class._meta.model_name tmp.append( url(r'^%s/%s/'%(app_label,model_name),config_obj.urls) ) return tmp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
##动态展示数据:
def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) queryset = self.model.objects.all() # 表头展示 header_list = [] for field in self.list_display: if field == '__str__': #当用户没有指定list_display 默认展示当前表的大写名字 val = self.model._meta.model_name.upper() else: val = self.model._meta.get_field(field).verbose_name header_list.append(val) #表单展示 body_list = [] #格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]] for obj in queryset: tmp = [] for field in self.list_display:#注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段 val = getattr(obj,field) #通过反射获取obj对象中field字段所对应的值 tmp.append(val) body_list.append(tmp) return render(request,'stark/list_view.html',locals()) #前端: <div class="container"> <div class="row"> <h2 class="text-center">数据展示</h2> <table class="table table-striped table-bordered table-hover"> <div class="col-md-8 col-md-offset-2"> <thead> <tr> {% for foo in header_list %} <td>{{ foo }}</td> {% endfor %} </tr> </thead> <tbody> {% for body in body_list %} <tr> {% for foo in body %} <td> {{ foo }} </td> {% endfor %} </tr> {% endfor %} </tbody> </div> </table> </div> </div>
##自动生成数据:
1、通过给定函数参数默认值,来对函数附加额外功能 2、checkbox、编辑、删除 默认所有的表都生成这三个字段 在注册stark文件 from stark.service.stark import site,ModelStark from app01 import models from django.utils.safestring import mark_safe site.register(models.Author) site.register(models.AuthorDetail) class BookConfig(ModelStark): list_display = ['title','price','publishDate'] site.register(models.Book,BookConfig) site.register(models.Publish) C:\starkpro\stark\service\stark.py from django.conf.urls import url from django.shortcuts import HttpResponse,render,redirect from django.utils.safestring import mark_safe class ModelStark(object): list_display = ['__str__',] def __init__(self,model): self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样 def check_box(self,is_header=False): if is_header: return '选择' return mark_safe('<input type="checkbox"/>') def edit_col(self,is_header=False): if is_header: return '编辑' return mark_safe('<a href=''>编辑</a>') def delete_col(self,is_header=False): if is_header: return '删除' return mark_safe('<a href=''>删除</a>') def get_new_list(self): tmp=[] tmp.append(ModelStark.check_box) tmp.extend(self.list_display) tmp.append(ModelStark.edit_col) tmp.append(ModelStark.delete_col) return tmp def list_view(self, request): #查看self.model <class 'app01.models.Book'> 那张表查看就代表谁 # print(self.model) queryset = self.model.objects.all() # 表头展示 header_list = [] for field_or_func in self.get_new_list(): if isinstance(field_or_func,str): if field_or_func == '__str__': #当用户没有指定list_display 默认展示当前表的大写名字 val = self.model._meta.model_name.upper() else: val = self.model._meta.get_field(field_or_func).verbose_name else: val = field_or_func(self,is_header=True) header_list.append(val) #表单展示 body_list = [] #格式定义 [[obj1.title,obj1.price],[obj2.title,obj2.price],[]] for obj in queryset: tmp = [] for field_or_func in self.get_new_list():#注意这里的list_display查找顺序,先查自己的,在查全局的,然后循环要展示的字段 if isinstance(field_or_func,str): val = getattr(obj,field_or_func) #通过反射获取obj对象中field字段所对应的值 else: val = field_or_func(self) tmp.append(val) body_list.append(tmp) return render(request,'stark/list_view.html',locals()) def add_view(self, request): return HttpResponse('add') def edit_view(self, request, id): return HttpResponse('edit') def delete_view(self, request, id): return HttpResponse('delete') @property def urls(self): #此处的self是指配置类对象 tmp = [ url(r'^$',self.list_view), url(r'^add/',self.add_view), url(r'^edit/(\d+)/',self.edit_view), url(r'^delete/(\d+)/',self.delete_view), ] return tmp,None,None class StarkSite(object): def __init__(self, name='admin'): self._registry = {} # model_class class -> admin_class instance def register(self, model, admin_class=None, **options): if not admin_class: admin_class = ModelStark self._registry[model] = admin_class(model) def test(self,request): return HttpResponse('test') def get_urls(self): #先定义一个列表,因为要给调用者返回列表 tmp = [] #循环字典_registry for model_class,config_obj in self._registry.items(): # print(model_class) #<class 'app01.models.Author'> 类字符串 # print(config_obj) #<stark.service.stark.ModelStark object at 0x000001A79CC58C18> 配置类对象 #获得模型表所在的应用名 app_label = model_class._meta.app_label # 获得模型表对应的字符串名 model_name = model_class._meta.model_name tmp.append( url(r'^%s/%s/'%(app_label,model_name),config_obj.urls) ) return tmp @property def urls(self): return self.get_urls(), None, None site = StarkSite()
##反向解析
1、二级urls取别名: def __init__(self,model): self.model = model #self.model是指拿到当前对象所对应的模型表名,即四张表对应都不一样 self.app_label = self.model._meta.app_label #直接给对象初始化应用名 self.model_name = self.model._meta.model_name #直接给对象初始化表名 @property def urls(self): #此处的self是指配置类对象 tmp = [ url(r'^$',self.list_view,name="%s_%s_%s"%(self.app_label,self.model_name,'list')),#应用名+表明+操作 url(r'^add/',self.add_view,name="%s_%s_%s"%(self.app_label,self.model_name,'add')), url(r'^edit/(\d+)/',self.edit_view,name="%s_%s_%s"%(self.app_label,self.model_name,'edit')), url(r'^delete/(\d+)/',self.delete_view,name="%s_%s_%s"%(self.app_label,self.model_name,'delete')), ] 2、后端用到 reserse obj为一个对象,因为编辑和删除时需要用到id,在访问的url链接中也会拼接一个id,所以再表单渲染那执行函数的时候传入obj def get_reverse_url(self,type,obj=None): if obj: _url = reverse("%s_%s_%s" % (self.app_label, self.model_name, type), args=(obj.pk,)) else: _url = reverse("%s_%s_%s" % (self.app_label, self.model_name, type)) return _url def edit_col(self,is_header=False,obj=None): if is_header: return '编辑' _url = self.get_reverse_url('edit',obj) return mark_safe('<a href="%s">编辑</a>'%_url) def delete_col(self,is_header=False,obj=None): if is_header: return '删除' _url = self.get_reverse_url('delete',obj) return mark_safe('<a href="%s">删除</a>'%_url) 3、函数根据参数传入的不同返回不同的结果