##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.title
View 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、函数根据参数传入的不同返回不同的结果