day063 CRM项目之stark组件第一天(初步写stark组件)

本节内容:

1、写stark的前期准备工作
2、stark组件之启动
3、stark组件之注册功能
4、stark组件之类变量查询
5、stark组件之url二级分发
6、静态文件和模板的引入问题
7、stark组件展示表格的体数据(即展示记录)
8、stark组件之展示表头数据
9、stark组件之默认列(为所有的查看页面默认显示编辑、删除、选择按钮)

一、写stark的前期准备工作

准备工作:
1、stark也是一个app(用startapp stark创建),目标把这个做成一个可插拔的组件

2、settings文件下的INSTALLED_APPS 路径要配置好

3、写好sites.py中的site类,实例化出一个类对象,其他文件都直接引用这个类对象(单例模式),
4、当然啦,你的模型类文件也要准备好,使用哪个数据库也要确定




二、stark组件之启动

启动所有app下的stark.py文件
(在stark文件夹下的apps.py文件中的class StarkConfig(AppConfig):添加该方法)

def ready(self):    # 这一句自动去加载所有的app下的stark.py文件
autodiscover_modules("stark")

“python

添加位置:在stark文件夹下的apps.py文件

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

class StarkConfig(AppConfig):
name = ‘stark’

def ready(self):  # 该方法默认去加载所有APP下的stark.py文件
    autodiscover_modules("stark")
## 三、stark组件之注册功能
    这里主要做两件事:
    1、在stark源码中,写好我们的starksite类,并实例化出一个site对象(单例对象供注册使用),
    2、在相应的APP下,注册site
```python
# stark.py文件源码
from django.shortcuts import HttpResponse,render

from django.urls import path,re_path

class ModelStark():  # 配置类

    list_display = ["__str__"]
    def __init__(self,model):
        self.model=model

class StarkSite():
    '''
    # StarkSite: 基本类
    # model: 注册模型类
    # ModelStark: 注册模型类的配置类
    '''

    def __init__(self):  # 定义这个字典在url二级分发时体现出来作用,
        self._registry = {} # model_class class -> admin_class instance

    # 注册方法,关键的两步
    def register(self,model,stark_class=None): # 传参,注册模型类和对应的配置类,这里传的都是类名,所以在调用方法的时候,实际上是调用函数,所以要传self
        stark_class = stark_class or ModelStark  # 若自定制有子类配置类对象则用传入的子类的,没有用默认父类的
        self._registry[model] = stark_class(model) #  该模型类为键,该模型了的配置类为值

site=StarkSite()
# app01下的时stark.py文件代码
from stark.service.sites import site,ModelStark from . import models site.register(models.Book,BookConfig) # 这里暂时先不传参,该参数为用户自定义的配置类 site.register(models.Publish) 
Python

四、stark组件之类变量查询

回顾我们的面向对象的知识:
类变量的查询的先后顺序(有继承关系的):
1、首先在自己对象的内存空间中找该变量,找不到的话
2、就到自己的类空间中找,还找不到的话
3、就到自己的父类空间中找,一直逐级往上找,再找不到的话,就报错

五、stark组件之url二级分发

这里我们模仿,admin组件的使用静态方法进行url二级分发
1、首先在urls中配置path路径,(这一步属于用户操作)
2、在基本类中配置好一级分发
3、在配置类中配置好二级分发
# stark.py文件下的代码

class ModelStark(): # 配置类 # urls二级分发 def get_urls(self): temp = [ path('',self.list_view), path('add/',self.add_view), re_path('(\d+)/change/',self.change_view), re_path('(\d+)/delete/',self.delete_view), ] return temp # 将一个方法变成一个属性 @property def urls(self): return self.get_urls(), None, None class StarkSite(): ''' # StarkSite: 基本类 # model: 注册模型类 # ModelStark: 注册模型类的配置类 ''' def get_urls(self): temp = [] for model, config_obj in self._registry.items(): # {Book:Bookconfig(Book),Publish:ModelStark(Publish)} model_name = model._meta.model_name # 拿到该表的小写表名 app_label = model._meta.app_label # 拿到该表所在的APP名称 temp.append( path('%s/%s/' % (app_label, model_name),config_obj.urls) # 对象直接点该属性,这是一个方法封装的属性 ) ''' 最终效果: # 1 path('app01/book/',Bookconfig(Book).urls), path('app01/book/',Bookconfig(Book).list_view), path('app01/book/add',Bookconfig(Book).add_view), path('app01/book/(\d+)/change/',Bookconfig(Book).change_view), path('app01/book/(\d+)/delete/',Bookconfig(Book).delete_view), ''' return temp @property # 将一个方法变成属性,这样在使用的时候就可以不用加括号,直接点 def urls(self): return self.get_urls(), None, None # 用户项目中的urls.py文件中配置path路径 from stark.service.sites import site urlpatterns = [ path('admin/', admin.site.urls), path('stark/',site.urls), ] 
Python

六、静态文件和模板的引入问题

主要这里我们要将stark组件做成可插拔式的,所有静态文件和模板文件都要放在我们的stark文件夹下。
这样就可以保证用户在使用我们的stark组件时,不会缺少配置文件。

七、stark组件展示表格的体数据(即展示记录)

这个统一在最后面的实例中有详解

八、stark组件之展示表头数据

这个统一在最后面的实例中有详解

九、stark组件之默认列(为所有的查看页面默认显示编辑、删除、选择按钮)

1、下面是今天的所有代码实例

用户app01下的models.py文件
from django.db import models

# Create your models here.

# Create your models here. class Book(models.Model): title = models.CharField( max_length=32,verbose_name="书籍名称") pub_date=models.DateField(verbose_name="出版日期") price=models.DecimalField(max_digits=5,decimal_places=2,verbose_name="价格") publish=models.ForeignKey(to="Publish",to_field="id",on_delete=models.CASCADE,null=True) authors=models.ManyToManyField("Author",db_table="book2authors") # 创建关系表 def __str__(self): return self.title class Publish(models.Model): name=models.CharField( max_length=32,verbose_name="名字") city=models.CharField( max_length=32) email=models.CharField(max_length=32) def __str__(self): return self.name class Author(models.Model): name=models.CharField( max_length=32) age=models.IntegerField() #books=models.ManyToManyField("Book") ad=models.OneToOneField("AuthorDetail",null=True,on_delete=models.CASCADE) def __str__(self): return self.name class AuthorDetail(models.Model): birthday=models.DateField() telephone=models.BigIntegerField() addr=models.CharField( max_length=64) # author=models.OneToOneField("Author",on_delete=models.CASCADE) def __str__(self): return str(self.telephone) 
Python
stark.py源码
from django.shortcuts import HttpResponse,render

from django.urls import path,re_path from django.core.exceptions import FieldDoesNotExist # 引入这个错误类型 from app01.models import * from django.utils.safestring import mark_safe # 告诉前端不要把我这个写的标签转义,直接渲染我写的这个标签 class ModelStark(): # 配置类 list_display = ["__str__"] def __init__(self,model): self.model=model # 选择,删除,编辑 列 def _checkbox(self, obj=None, is_header=False): if is_header: return "选择" return mark_safe("<input type='checkbox'>") # 注意引号啊,要细心 def _edit(self,obj=None,is_header=False): # obj是当前表记录的对象 if is_header: return "编辑" app_label = obj._meta.app_label model_name = obj._meta.model_name # 这里先暂时写成这个动态url,后面我们使用url反向解析来解决这个问题 return mark_safe("<a href='/stark/%s/%s/%s/change/'>编辑</a>" %(app_label,model_name,obj.pk)) def _delete(self,obj=None,is_header=False): # obj是当前表记录的对象 if is_header: return "删除" app_label = obj._meta.app_label model_name = obj._meta.model_name return mark_safe("<a href='/stark/%s/%s/%s/delete/'>删除</a>" %(app_label,model_name,obj.pk)) # 让所有的查看页面都默认带上这三列选项,选择,删除,编辑 def get_new_list_display(self): new_list_display=[] new_list_display.extend(self.list_display) # 将当前的要显示的列表遍历添加到这个新列表中 new_list_display.insert(0,ModelStark._checkbox) # 在第一个位置插入选择列 new_list_display.append(ModelStark._edit) # 后面添加编辑,删除功能列 new_list_display.append(ModelStark._delete) return new_list_display def list_view(self,request): # self ; 模型类对应的配置类对象,可能是自定义配置类对象,也可能是默认配置类ModelStark对象 # self.model: 当前访问表的模型类 # header_list=["名称","价格","出版日期","出版社"] # 展示当前表头数据 header_list=["名称","价格","出版日期","出版社"] header_list = [] for field in self.get_new_list_display(): try: field_obj = self.model._meta.get_field(field) # 拿到该字段的对象 header_list.append(field_obj.verbose_name) # verbose.name是字段对象的一个属性,默认是字段名,可以在模型类设置等于中文 except FieldDoesNotExist as e: if field == "__str__": # 特例,不传参,使用父类的默认值"__str__",如:publish表这时拿到的是__str__字符串 val = self.model._meta.model_name.upper() else: val = field(self,is_header=True) # 调用子类的函数,因为是类名直接调用所以此时是方法,需要传self参数 header_list.append(val) # 展示当前表体数据 data = [] # 最终传给模板文件的样式:[["西游记",price],[title,price],] queryset = self.model.objects.all() # 拿到一个queryset的集合对象,元素为每一本书或每一个模型类的对象(表的数据每一条记录) # print(queryset) for obj in queryset: temp = [] for field in self.get_new_list_display(): if callable(field): # 多对多字段会调用函数(类名调用方法即调用函数) val = field(self,obj) # 执行函数要传参数self, else: val = getattr(obj,field) # 这里要注意拿到的field从列表中取出来是一个字符串,需要用反射来拿 # 如果是__str__它会去执行,拿到返回值 temp.append(val) data.append(temp) print("data最终效果",data) return render(request, "stark/list_view.html", locals()) def add_view(self,request): # self ; 模型类对应的配置类对象,可能是自定义配置类对象,也可能是默认配置类ModelStark对象 # self.model: 当前访问表的模型类 return HttpResponse("add_view") def change_view(self,request,id): # self ; 模型类对应的配置类对象,可能是自定义配置类对象,也可能是默认配置类ModelStark对象 # self.model: 当前访问表的模型类 return HttpResponse("change_view") def delete_view(self,request,id): # self ; 模型类对应的配置类对象,可能是自定义配置类对象,也可能是默认配置类ModelStark对象 # self.model: 当前访问表的模型类 return HttpResponse("delete_view") # urls二级分发 def get_urls(self): temp = [ path('',self.list_view), path('add/',self.add_view), re_path('(\d+)/change/',self.change_view), re_path('(\d+)/delete/',self.delete_view), ] return temp # 将一个方法变成一个属性 @property def urls(self): return self.get_urls(), None, None class StarkSite(): ''' # StarkSite: 基本类 # model: 注册模型类 # ModelStark: 注册模型类的配置类 ''' def __init__(self): # 定义这个字典在url二级分发时体现出来作用, self._registry = {} # model_class class -> admin_class instance def register(self,model,stark_class=None): # 传参,注册模型类和对应的配置类,这里传的都是类名,所以在调用方法的时候,实际上是调用函数,所以要传self stark_class = stark_class or ModelStark # 若自定制有子类配置类对象则用传入的子类的,没有用默认父类的 self._registry[model] = stark_class(model) # 该模型类为键,该模型了的配置类为值 def get_urls(self): temp = [] for model, config_obj in self._registry.items(): # {Book:Bookconfig(Book),Publish:ModelStark(Publish)} model_name = model._meta.model_name # 拿到该表的小写表名 app_label = model._meta.app_label # 拿到该表所在的APP名称 temp.append( path('%s/%s/' % (app_label, model_name),config_obj.urls) # 对象直接点该属性,这是一个方法封装的属性 ) return temp @property def urls(self): return self.get_urls(), None, None site=StarkSite() 
Python
用户app01下的stark.py
print("app01>>>>>")

from stark.service.sites import site,ModelStark from . import models class BookConfig(ModelStark): def show_authors(self,obj=None,is_header=False): # 需要自定义这个方法,在显示的时候用方法来调用,表头和表体显示不一样 if is_header: return "作者" return " ".join([obj.name for obj in obj.authors.all()]) list_display = ["title","price","pub_date",show_authors] # 这里直接publish拿到的是该表的一个object对象 site.register(models.Book,BookConfig) site.register(models.Publish) site.register(models.Author) site.register(models.AuthorDetail) 
Python
stark文件夹下的查看模板文件list_view.py文件
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css"> </head> <body> <h3>数据列表</h3> <div class="container-fluid"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <table class="table table-hover table-striped"> <thead> <tr> {% for item in header_list %} <th>{{ item }}</th> {% endfor %} </tr> </thead> <tbody> {% for item in data %} <tr> {% for val in item %} <td>{{ val }}</td> {% endfor %} </tr> {% endfor %} </tbody> </table> </div> </div> </div> </body> </html> 
Python
 

猜你喜欢

转载自www.cnblogs.com/yipianshuying/p/10278488.html