zoukankan      html  css  js  c++  java
  • 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
     
  • 相关阅读:
    Yield Usage Understanding
    Deadclock on calling async methond
    How to generate file name according to datetime in bat command
    Run Unit API Testing Which Was Distributed To Multiple Test Agents
    druid的关键参数+数据库连接池运行原理
    修改idea打开新窗口的默认配置
    spring boot -thymeleaf-url
    @pathvariable和@RequestParam的区别
    spring boot -thymeleaf-域对象操作
    spring boot -thymeleaf-遍历list和map
  • 原文地址:https://www.cnblogs.com/yipianshuying/p/10278488.html
Copyright © 2011-2022 走看看