zoukankan      html  css  js  c++  java
  • Django之stark组件1

    stark组件

    stark组件是根据Django admin为原型写的一个组件,能够让我们告别增删改查.stark组件是可插拔试的组件,

    移植性强,而且只用配置文件就能够得到想要的数据

    一、stark组件路由分发

    admin用这一条路由就实现了注册表单*4的url。

    路由分发的原理:

    知识一:admin之路由分发原理:
    def text01(request):
        return  HttpResponse('text01')
    def text02(request):
        return  HttpResponse('text02')
    def text03(request):
        return  HttpResponse('text03')
    urlpatterns = [
        path('chen/',(
                [path('text01/',text01),
                 path('text02/',text02),
                 path('text03/',text03),
                 ],
                None,None))
    ]
            由一个路由分发出来三个 第一个none是namespace,第二个是项目名称
            
            一级:
            path('chen/',(
            [
            path()
            path()
            path()
            ],None,None))
            
    由一个路由分发出来三个,第一个路由又可以分发出来两个,二级路由.
    
     第一个none是namespace,第二个是项目名称
     
        二级:
        path('chen/',(
            [
            path(
                [
                    path(),
                    path(),
                ],None,None))
            ]
            ,None,None))
            
    路由分发原理

    单例模式:

    ***公共的数据***
    一个类只允许实例一个对象
    ***为了数据统一****

    怎么生成单例模式?

    方式一:__new__

            __new__
        class Singleton(object):
               _instance = None
                    def __new__(cls, *args, **kwargs):
            # 第一次生成对象的时候走:
                    if not cls._instance:
                    cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs) 
            # 第二次走的时候直接走这里
                         return cls._instance  
    class MyClass(Singleton):  
        a = 1
    
    #那么每次实例对象的时候都是指向 同一个内存地址.
    #实例MyClass的时候都是 同一个对象
    View Code

    方式二:python模块

    python模块是天然的单例模式:

    1.不管模块哪里导入,只要是再次导入都是从.pyc导入,都是一个内存地址
        因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,
       就会直接加载 .pyc 文件,而不会再次执行模块代码。
    2.我们只需把模块的对象实例化,每次调用的时候都调用这个对象,就可以获得一个单例对象了。

    class StarkSite(object):
        """注册model对应的配置类(MondelStark或用户自定制)"""
        def __init__(self):
            self._registry={}
            #self--->site单例对象
    
        def register(self,model,stark_class=None):
            if not stark_class:
                stark_class=MondelStark
            self._registry[model] = stark_class(model,self)
    
        def get_urls(self):
            # self--->site单例对象
            temp=[]
            for model,stark_class_obj in self._registry.items():
                model_name=model._meta.model_name
                app_label =model._meta.app_label
                temp.append(path('%s/%s/'%(app_label,model_name),stark_class_obj.get_url_dispath))
                '''
                path('repository/book/'BookStark(book,).get_url_dispath)
                path('repository/author/'BookStark(author,).get_url_dispath)
                
                '''
            return temp
    
        @property
        def urls(self):
            return self.get_urls(),None,None
    
    site=StarkSite()
    单例

    每次调用site就是单例对象

    说完单例模式,再说回路由的分发:

    stark.site就是一个单例,里面进行注册我们的models

    为什么我们要用单例模式???

    为了能够把model注册到同一个对象里面,我们就可以实现数据统一调度。

    StarkSite形成单例类的代码:

    #单例的类
    class StarkSite(object):
        """注册model对应的配置类(MondelStark或用户自定制)"""
        def __init__(self):
            self._registry={}
            #self--->site单例对象
    
        def register(self,model,stark_class=None):
            if not stark_class:
                stark_class=MondelStark
            self._registry[model] = stark_class(model,self)
    
        def get_urls(self):
            # self--->site单例对象
            temp=[]
            for model,stark_class_obj in self._registry.items():
                model_name=model._meta.model_name
                app_label =model._meta.app_label
                temp.append(path('%s/%s/'%(app_label,model_name),stark_class_obj.get_url_dispath))
                '''
                path('repository/book/'BookStark(book,).get_url_dispath)
                path('repository/author/'BookStark(author,).get_url_dispath)
                
                '''
            return temp
    
        @property
        def urls(self):
            return self.get_urls(),None,None
    View Code

    在register()方法里面,我们在注册的前提

    大前提!!!!!!!

    ***思考***

    我们里在直接调用这个register方法?

    那么里面注册了数据了吗?

    答案是没有的,

    ***思路***

    在每次开启项目的时候,能够自动执行某个py文件进行注册

    from repository import models
    from stark.server.stark import site
    from stark.server.stark import MondelStark
    引入
    #我们需要在stark项目的app里:
    from django.apps import AppConfig
    from django.utils.module_loading import autodiscover_modules
    
    class StarkConfig(AppConfig):
        name = 'stark'
        def ready(self):
            autodiscover_modules('stark',)
    
    
    #每次启动都会执行每个项目的stark.py文件,那么一开启项目就把model注册了.
    
    
    ###########其他项目注册model##########
    site.register(models.Book,BookStark)
    
    site.register(models.Author,AuthorStark)
    
    site.register(models.publish)
    自动执行py文件

    在其他项目stark.py我们可以自己进行配置类的书写

    from stark.server.stark import MondelStark
    
    class BookStark(MondelStark):
    pass
    View Code

    如何通过模型类获得字符串名称,和该模型所在的app名称:

    我们需要构建的是一级分发:

    第一个是model所属项目的名称/第二个是model类的类名

    (path('%s/%s'%(app_label,model_name),))

     for model,class_obj in admin.site._registry.items():
    
        print(model._meta.model_name) #打印出该模型的名称
    
        print(model._meta.app_label)  #打印出该模型的app的名称
        
    View Code

    二级分发我们需要写在配置类里面:

    为什么不能写在单例?

    从图中可以看出,如果是单例对象的话,每个model类对应的视图函数都是一样的

    我们想要的是每一个model类都需要4个视图函数,

    所以我们只能把二级分发放在配置类里面,让每个配置类都生成四个相对应的视图函数

        def url_dispath(self):
            # self--->stark_class_obj--->每一个单独的配置类.
            temp = []
            model_name = self.model._meta.model_name
            app_label = self.model._meta.app_label
            temp.extend([path('add/', self.add_view,name="%s_%s_add"%(app_label,model_name)),
                         re_path('^(d+)/delete/', self.delete_view,name="%s_%s_delete"%(app_label,model_name)),
                         re_path('^(d+)/change/', self.change_view,name="%s_%s_change"%(app_label,model_name)),
                         path('', self.show_list,name="%s_%s_list"%(app_label,model_name))])
            return temp
    
    
    #起别名,目的是为了反向查询的时候能够查到相对应的url
    二级分发

    构建表结构:

    自定制表头:

    配置类继承了MondelStark的配置类

    class BookStark(MondelStark):
    
        list_display=['id','name','price']
    
    site.register(models.Book,BookStark)

     构建表格

     

    构建表头知识补充:

    #如果客户自定制了配置list_display 那么实例化的时候就先在用户自定义的类里面找
    #有则返回给后端......没有再去他的父类里面找list_display为空.

    属性的反射

    属性和方法都可以进行反射

        ###################
        反射:
        class B(object):
            def__init__(self,name):
                self.name=name
        chen=B('chenxuming')
        s='name'
        
        ret=getattr(chen,s)
        print(ret)  ---->'chenxuming'
    属性的反射

    如何将表头换成中文:

    val = self.config.model._meta.get_field(field).verbose_name
    header_list.append(val)

    class Book(models.Model):
        name = models.CharField(max_length=64,verbose_name='书名')
        price= models.IntegerField()
        
        name=Book._meta.get_field('name')
        #name拿到的是title字段的对象
        print(name)
        print(type(name))
        #可以取里面的属性
        name.max_length  --->64
            name.verbose_name--->'书名'
    View Code

    #判断是否是函数的字段
    if callable():

    from django.utils.safestring import mark_safe
    mark_safe(安全调用标签)

    构建表格的代码

        def new_list_display(self):
              ''''构建初始化列表的字段''   
            temp=[]
            temp.append(MondelStark.checkbox)
            temp.extend(self.list_display)
            temp.append(MondelStark.get_delete_msg)
            if not self.list_display_links:
                temp.append(MondelStark.get_edit_msg)
            return temp
    
        def get_headers(self):
            # 构建表头:      self.new_list_display=[checkbox,'name','price',delete,edit]
            header_list = []
            for field in  self.config.new_list_display:
                if callable(field):
                    val = field(self.config, header=True)
                    header_list.append(val)
                else:
                    if field == '__str__':
                        val =  self.config.model_name.upper()
                        header_list.append(val)
                    else:
                        val =  self.config.model._meta.get_field(field).verbose_name
                        header_list.append(val)
            return header_list
    
    
        def get_body(self):
            # 表数据的创建
            new_list = []
            for obj in self.data_list:
                item_list = []
                for item in  self.config.new_list_display:
                    if callable(item):
                        val = item(self.config, obj)
                    else:
                        val = getattr(obj, item)
                        if item in  self.config.list_display_links:
                            val = mark_safe('<a href="%s">%s</a>' % ( self.config.get_edit_url(obj), val))
                    item_list.append(val)
                new_list.append(item_list)
            return new_list
    
    [[数据],[数据],[数据]]
    
    ##########表头,部分表数据的函数#########
    
     def checkbox(self,obj=None,header=False):
            if header:
                return mark_safe('<input id="choice_all" type="checkbox">')
    
            return mark_safe('<input class="item" type="checkbox" name="selected_id" value="%s">'%obj.id)
    
        def get_edit_msg(self,obj=None,header=False):
            if header:
                return "操作"
    
            _url=self.get_edit_url(obj)
            return mark_safe('<a href="%s">编辑</a>' % _url)
    
        def get_delete_msg(self,obj=None,header=False):
            if header:
                return "操作"
            _url=self.get_delete_url(obj)
            return mark_safe('<a href="%s">删除</a>'%_url)
    构建表格

    增:

    增和改都是基于ModelForm来实现的。

    如果用户自定制

    Stark_Model_Form=自定制modelform的类名
    class BookStark(MondelStark):
        list_display=['id','name','price']
        Stark_Model_Form=ModelFormBook
        list_display_links = ['name']
    
    
    
    class ModelFormBook(ModelForm):
        """自定制ModelForm类"""
        class Meta:
            model=models.Book
            fields='__all__'
    
            labels={
                    'name':'书名',
                    'price':'价格',
                    'pub':'出版社',
                    'author':'作者',
            }
    
    
        def get_model_class(self):
            '''判断是否自定制了ModelForm'''
            if not self.Stark_Model_Form:
                from django.forms import ModelForm
                class ModelDeMo(ModelForm):
                    class Meta:
                        model = self.model
                        fields = '__all__'
                return ModelDeMo
            else:
                return self.Stark_Model_Form
    
        def add_view(self,request):
            '''增加的视图函数'''
            # self--->stark_class_obj--->每一个单独的配置类.
            ModelDeMo=self.get_model_class()
            if request.method=='GET':
    
                form =ModelDeMo()
                return render(request, 'oprate/add.html', {'form':form})
    
            if request.method=='POST':
                form = ModelDeMo(request.POST)
                if form.is_valid():
                    form.save()
                    return redirect(self.get_list_url())
                else:
                    return render(request,'oprate/add.html',{'form':form})
    
    ###########前端#########
    <form class="form-horizontal col-sm-7" method="post" novalidate>
        {% csrf_token %}
        {% for data in form  %}
            <label>{{ data.label }}</label>
            {{ data }}
            <div class="errors-form">{{ data.errors.0 }}</div>
        {% endfor %}
    
        <button type="submit" class="btn btn-success">提交</button>
    </form>
    add

    改:

    和增加差不多

        def change_view(self,request,nid):
            '''改 视图函数'''
            # self--->stark_class_obj--->每一个单独的配置类.
            ModelDeMo=self.get_model_class()
            change_obj=self.model.objects.filter(id=nid).first()
            if request.method=='GET':
                form=ModelDeMo(instance=change_obj)
                return render(request,'oprate/edit.html',{'form':form})
    
            if request.method=='POST':
                show_url = self.get_list_url()
                #instance=change_obj
                # form.save()
                #执行的是update操作
                form=ModelDeMo(data=request.POST,instance=change_obj)
                if form.is_valid():
                    form.save()
                    return redirect(show_url)
                else:
                    return render(request, 'oprate/edit.html', {'form': form})
    
    
    
    ###前端###
    
    <form class="form-horizontal col-sm-7" method="post" novalidate>
        {% csrf_token %}
        {% for data in form  %}
            <label>{{ data.label }}</label>
            {{ data }}
            <div class="errors-form">{{ data.errors.0 }}</div>
        {% endfor %}
    
        <button type="submit" class="btn btn-success">提交</button>
    </form>
    change

    删:

    删要注意的是需要跳转到一个页面,确保用户误点

        def delete_view(self,request,nid):
            # 删除视图函数
            # self--->stark_class_obj--->每一个单独的配置类.
            del_obj = self.model.objects.filter(id=nid).first()
            show_url = self.get_list_url()
    
            if request.method=='GET':
    
                return render(request,'oprate/delete.html',{'show_url':show_url})
            if request.method=='POST':
                if del_obj:
                    del_obj.delete()
                    return redirect(show_url)
    
    
    ###前端######
    
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <h1>删除页面</h1>
    <form action="" method="post" novalidate>
        {% csrf_token %}
        <input type="submit" value="确认删除">
        <a href="{{ show_url }}">取消</a>
    </form>
    
    </body>
    </html>
    View Code

     search

    用户能够自己配置进行模糊查询

    Q方法的补充

    from django.db.models import Q
    
    Q的两种玩法:
    
    第一种:
    查询字段必须是字段
        Book.objects.filter(Q(title='yuan')|Q(price=123))
        
    第二种
    查询字段可以是字符串:
    
    #实例化一个Q对象
    search_connction=Q()
    #或查询默认是and
    search_connction.connector='or'
    
    for search_fiile in self.search_fiile   #self.search_fiile 用户自定制的['name','price']
        #append里面是一个元组
        #search_connction.children.append((search_fiile,'查询的内容'))
        search_connction.children.append((search_fiile+'__contains','查询的内容'))模糊查询
    
            data_list = self.model.objects.filter(search_list)
    Q两种方法

    stark实现search

    需要自定制字段:

    search_fields = ['name']
    def get_search_connection(self,request):
            '''获取模糊查询的Q'''
            self.key_word=request.GET.get('q','')
            search_connction=Q()
            if self.key_word:
                search_connction.connector='or'
                for fields in self.search_fields:
                    search_connction.children.append((fields+'__icontains',self.key_word))
            return search_connction
    
    
    search_list=self.get_search_connection(request)
    
    data_list = self.model.objects.filter(search_list)
    
    
    ##前端##
    {% if showlist.config.search_fields %}
            <form action="" method="get" class="pull-right">
                <input type="text" name="q" value="{{ showlist.config.key_word }}"><button>查询</button>
            </form>
            {% endif %}
    View Code

     

  • 相关阅读:
    Kuangbin带你飞 专题二十 斜率DP
    牛客每日一题3月
    2020 SWJTU-ICPC Training Round #2(18年福建省赛)部分题解
    codeforces每日一题31-40
    SWJTU校队训练&Codeforces&Atcoder&&牛客三月补题
    Kuangbin带你飞-专题九连通图
    POJ 3667 Hotel(线段树区间合并)
    AtCoder Beginner Contest 157(题解)
    2.22专项测试复盘
    2.21专项测试复盘
  • 原文地址:https://www.cnblogs.com/chenxuming/p/9308049.html
Copyright © 2011-2022 走看看