• 快速实现增删改查组件(起步阶段!!!)


    一、相关知识点回顾

        1、什么是反射?

        可以用字符串的方式去访问对象的属性

     2、反射有四种方法?

    hasattr(object,name):判断一个对象是不是有name属性或者方法
    getattr:获取对象的属性或者方法,  需要注意的是,如果返回的是对象的方法,返回出来的是对象的内存地址, 如果需要运行这个方法,可以在后面添加一对()
    setattr:给对象的属性赋值,如果属性不存在,先创建后赋值
    delattr:删除该对象指定的一个属性

     3、创建ModelForm的两种方式

    # 方式一定义ModelForm
       class TestModelForm(ModelForm):
             class Meta:
                 model = self.model_class
                 fields = "__all__"
            
       方式二定义
      Meta = type("Meta", (object,), {"model": self.model_class, "fields": "__all__"})
      TestModelForm = type("TestModelForm", (ModelForm,), {"Meta": Meta})

    二、具体流程以及相关知识点

    1、路由系统

    让url对应视图,这时的视图可以是一个元组,元组的里面放三个参数,第一个是个列表,这两种表示方式都是一样的,用那种都行

    namespace的用法如下

    v =>  ([],None,None)  namespace(是第三个参数),用于区分相同name的url,通过namespace为url添加一个前缀

     如图:

    namespace

    流程:

    首先创建三个应用
          app01
          app02
          strak

    1、一旦运行的时候都会去执行admin.py ,现在我们让你开始执行stark.py 文件,加上下面的这些(参考的是admin的源码,在每一个admin文件的里面点击进入)

    from django.utils.module_loading import autodiscover_modules
    
        class StarkConfig(AppConfig):
            name = 'stark' #应用名称
    
            def ready(self):
                autodiscover_modules('stark')   #在应用中创建的py文件和这个名字一样

    切记一定要在sessings中配置一下:

    'app02.apps.App02Config',
    'stark.apps.StarkConfig',

    2、然后再每个应用下面也创建一个stark.py的文件
           这样就像admin一样了,就开始执行site.redister了


    3、这时候还没有site呢,需要自己实例化一个site
           在应用下创建一个service的文件夹,再创建一个v1.py文件,在里面写代码

    4、在stark里面注册

    需要注意的是:

    v1.site.register(models.UserInfo)   
    ->  执行 StackConfig的 changelist_view方法/add_view....
            
            
        
    class UserInfoConfig(v1.StarkConfig):
            def changelist_view(self,request,*args,**kwargs):
                return HttpResponse('你猜我是谁?')
    
    v1.site.register(models.UserInfo,UserInfoConfig)
    
    ---> 优先查看自己config中是否存在方法,不存在则执行基类 StackConfig的 changelist_view方法/add_view....

    如图:

    5、注册完成之后走urls。仿照admin的urls.。。。v1.site.urls
    6、完了在v1.py中写代码

    class StarkSite(object):
        def __init__(self):
            self._registry ={}  #放置处理请求对应关系
            '''
            _registry = {
                        models.Role: StarkConfig(models.Role,v1.site),
                        models.UserInfo: StarkConfig(models.UserInfo,v1.site)
                        models.UserType: StarkConfig(models.UserType,v1.site)
                        models.Article: StarkConfig(models.Article,v1.site)
                    }
            '''
        def register(self,model_class,stark_config_class=None):
            if not stark_config_class:
                '''stark_config_class是类对象,如果没有这个类就重新赋值,去执行StarkConfig'''
                stark_config_class = StarkConfig
            self._registry[model_class] = stark_config_class(model_class,self)
            #如果用户自己传进去类了,就用自己的,自己的需要继承StarkConfig。如果自己没有就找基类的,自己有就用自己的
    
        def get_urls(self):
            url_list = []
            for model_calss,stark_config_obj in self._registry.items():
                app_name = model_calss._meta.app_label#应用名称
                model_name = model_calss._meta.model_name#表的名称
                cur_url = url(r'^{0}/{1}/'.format(app_name,model_name),(stark_config_obj.urls,None,None))
                #这是的stark_config_obj是上面StarkConfig的实例对象。stark_config_obj.urls就会去找上面类的urls
                url_list.append(cur_url)
            return url_list
        @property #吧方法当属性来用
        def urls(self):
            return (self.get_urls(),None,'stark')  #第三个参数是namesapce

     动态生成类名和应用名图示:

     

    在v1里面有两个类

    - StarkConfig,用于为每一个类生成URL对应关系,并编写视图函数处理用户请求。
                [
                    ^$  -> self.changelist_view
                    ^add/$  -> self.add_view
                    ^delete/$  -> self.delete_view
                    ^change/$  -> self.dchange_view
                ]
                
            - StarkSite    
            是一个容器,用于放置处理请求对应关系。
                        {
                            model.UserInfo: UserInfoConfig(model.UserInfo,self),
                            model.UserType: StarkConfig(model.UserType,self),
                        }    

     具体来写:当然前面的StarkSite类已经写过了,那我们来看看StarkConfig这个类

    以下的功能实现都是在StarkConfig这个类里面的

    功能实现一:展示页面,让页面上动态显示表格

    class StarkConfig(object):
        list_display = []
        def __init__(self, model_class, site):
            self.model_class = model_class
            self.site = site
        def change_list_views(self,request,*args,**kwargs):
            data_list = self.model_class.objects.all()
            '''展示th的信息'''
            head_list = []
            for field_name in self.list_display:
                if isinstance(field_name,str):
                    verbose_name = self.model_class._meta.get_field(field_name).verbose_name
                else:
                    verbose_name = field_name(self,is_header=True)
                # yield {"verbose_name":verbose_name}
                head_list.append(verbose_name)
    
            '''展示td的信息'''
    
            # [["id","name"],["id","name"],["id","name"],]
            new_data_list = []
            for row in data_list:
                temp = []
                for field_name in self.list_display:
                    if isinstance(field_name,str):
                        #如果是字符串类型的就是用getattr的方式,因为对象不能.字符串
                        val = getattr(row,field_name)
                    else:
                        val = field_name(self,row)
                    temp.append(val)
                    # yield {"val":val}
                new_data_list.append(temp)
            return render(request, "stark/change_list_views.html", {"data_list":new_data_list,"head_list":head_list})

    在stark.py 中

    strak.py
        print("sssss6666666")
        from app01 import models
        from stark.service import v1
        from django.utils.safestring import mark_safe
        class UserInfoConfig(v1.StarkConfig):
            def checkbox(self,obj=None,is_header=False):
                if is_header:
                    return "选择"
                return mark_safe("<input type='checkbox' name='zzzz' value='%s'/>"%obj.id)
    
            def edit(self,obj=None,is_header=False):
                if is_header:
                    return "操作"
                return mark_safe("<a href='edit/%s'>编辑</a>"%obj.id)
            list_display = [checkbox,"id","name",edit]
    
        v1.site.register(models.UserInfo,UserInfoConfig)
        v1.site.register(models.Role,UserInfoConfig)
        v1.site.register(models.UserType)

     功能二:当然我们现在把按钮是自己定制的,有与编辑,删除等都是我们很常用的,所以我们可以搞成默认的。在StarkConfig类里写

     # ===============吧删除,编辑,复选框设置默认按钮==================
    
        def checkbox(self,obj=None,is_header=False):
            if is_header:
                return "选择"
            return mark_safe("<input type='checkbox' name='zzzz' value='%s'/>"%obj.id)
    
        def edit(self,obj=None,is_header=False):
            if is_header:
                return "操作"
            return mark_safe("<a href='%s'>编辑</a>"%(self.get_change_url(obj.id),))
    
        def delete(self,obj=None,is_header=False):
            if is_header:
                return "删除"
            #动态跳转路径,反向解析,因为每次都要用到,我们可以吧它封装到一个函数
            return mark_safe("<a href='%s'>删除</a>"%self.get_delete_url(obj.id))
    
        #做默认的删除和编辑。对这个方法重写的时候可以吧权限管理加进去,
        # 当它都什么权限的时候显示什么按钮。
        def get_list_display(self):
            data = []
            if self.list_display:
                data.extend(self.list_display) #在新的列表里面吧list_display扩展进来
                data.append(StarkConfig.edit)  #因为是默认的,直接在类里面去调用edit
                data.append(StarkConfig.delete)
                data.insert(0,StarkConfig.checkbox)
            return data

     功能三:默认显示添加按钮

     show_add_btn = True
        # ======这个方法可自定制(如果把show_add_btn设置为False就不会显示添加按钮)=====
        def get_show_add_btn(self):
            return self.show_add_btn

     功能四:当点击编辑,删除,添加按钮的时候的跳转路径,动态生成

    return render(request, "stark/change_list_views.html",{"add_url":self.get_add_url(),"show_add_btn":self.get_show_add_btn()})

     利用反向解析reverse

     # =================url相关,reverse反向解析=============
        def get_change_url(self,nid):
            name = "stark:%s_%s_change"%(self.model_class._meta.app_label,self.model_class._meta.model_name)
            edit_url = reverse(name,args=(nid,))  #反向解析只要找到他的name属性,就会找到他对应的路径
            return edit_url
    
        def get_add_url(self):
            name = "stark:%s_%s_add" % (self.model_class._meta.app_label, self.model_class._meta.model_name)
            edit_url = reverse(name)
            return edit_url
    
        def get_delete_url(self, nid):
            name = "stark:%s_%s_delete" % (self.model_class._meta.app_label, self.model_class._meta.model_name)
            edit_url = reverse(name,args=(nid,))
            return edit_url
    
        def get_list_url(self):
            name = "stark:%s_%s_changelist" % (self.model_class._meta.app_label, self.model_class._meta.model_name)
            edit_url = reverse(name)
            return edit_url

     功能五:添加,删除,编辑功能(利用MOdelForm)

      model_form_class=None
        def get_model_form_class(self):
            if self.model_form_class:   #如果自己定制了就用自己的,在这就什么也不返回了,如果没有自己定义就返回默认的这个Form
                return self.model_form_class
            # 方式一定义ModelForm
            # class TestModelForm(ModelForm):
            #     class Meta:
            #         model = self.model_class
            #         fields = "__all__"
            # return TestModelForm
            # 方式二定义
            Meta = type("Meta", (object,), {"model": self.model_class, "fields": "__all__"})
            TestModelForm = type("TestModelForm", (ModelForm,), {"Meta": Meta})
            return TestModelForm
    def add_views(self,request,*args,**kwargs): model_form_class = self.get_model_form_class() if request.method=="GET": form = model_form_class() return render(request,"stark/add_view.html",{"form":form}) else: form = model_form_class(request.POST) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, "stark/add_view.html", {"form": form}) def delete_view(self, request,nid, *args, **kwargs): self.model_class.objects.filter(pk=nid).delete() return redirect(self.get_list_url()) def change_views(self, request,nid, *args, **kwargs): model_form_class = self.get_model_form_class() obj = self.model_class.objects.filter(pk=nid).first() if not obj: return redirect(self.get_list_url()) if request.method == "GET": form = model_form_class(instance=obj) return render(request, "stark/edit_view.html", {"form": form}) else: form = model_form_class(data=request.POST,instance=obj) if form.is_valid(): form.save() return redirect(self.get_list_url()) else: return render(request, "stark/edit_view.html", {"form": form})

     功能六:额外扩展url

      # =============路由系统,对应相应的视图函数=====================
        def get_urls(self):
            app_model_name = (self.model_class._meta.app_label,self.model_class._meta.model_name)
            all_url = [
                url(r'^$', self.change_list_views,name="%s_%s_changelist"%app_model_name),
                url(r'^add/$', self.add_views,name="%s_%s_add"%app_model_name),
                url(r'^(d+)/delete/$', self.delete_view,name="%s_%s_delete"%app_model_name),
                url(r'^(d+)/change/$', self.change_views,name="%s_%s_change"%app_model_name),
            ]
            all_url.extend(self.extra_urls())
            return all_url
    
        # ===========额外扩展url(用户可以进行随意扩展)==========
        def extra_urls(self):
            return []
    
        @property
        def urls(self):
            return self.get_urls()

    三、使用

    #!usr/bin/env python
    # -*- coding:utf-8 -*-
    print("sssss6666666")
    from app01 import models
    from django.conf.urls import url
    from stark.service import v1
    from django.shortcuts import render,HttpResponse,redirect
    from django.forms import ModelForm
    class UserInfoConfig(v1.StarkConfig):
        # 1、
        list_display = ["id","name","email"]
        # list_display = []
       # 2、
        def extra_urls(self):
            url_list =[
                url(r'^xxxx/$',self.func),
            ]
            return url_list
    
        def func(self,request):
            return HttpResponse("我是额外添加的路径哦....")
        # 3、
        # show_add_btn=False   #默认是True的,如果不让显示添加按钮可以自定制
    
        # 4、
        def get_model_form_class(self):
            class MyModelForm(ModelForm):
                class Meta:
                    model = self.model_class
                    fields = "__all__"
                    error_messages={
                        "name":{"required":"用户名不能为空"},
                        "email":{"invalid":"邮箱格式不正确"}
                    }
            return MyModelForm
        # 5、
        def delete_view(self, request,nid, *args, **kwargs):
            if request.method=="GET":
                return render(request,"stark/delete_view.html",{"quxiao_url":self.get_list_url()})
            else:
                self.model_class.objects.filter(pk=nid).delete()
                return redirect(self.get_list_url())
    v1.site.register(models.UserInfo,UserInfoConfig)
    
    ===================================================
    class RoleConfig(v1.StarkConfig): list_display = ["id","name"] # list_display = [] def extra_urls(self): url_list =[ url(r'^aaaa/$',self.func), ] return url_list def func(self,request): return HttpResponse("我是额外添加的路径哦....") # show_add_btn=False #默认是True的,如果不让显示添加按钮可以自定制 def get_model_form_class(self): class MyModelForm(ModelForm): class Meta: model = self.model_class fields = "__all__" error_messages={ "name":{"required":"用户名不能为空"}, } return MyModelForm v1.site.register(models.Role,RoleConfig) v1.site.register(models.UserType)
    ======================================================
    class HostConfig(v1.StarkConfig): def ip_port(self, obj= None,is_header=False): if is_header: #如果是True就返回的是th的,默认就是True return "自定义列" return "%s_%s"%(obj.id,obj.port,) #当是False的时候就返回的是td的 list_display = ["id","name","ip","port",ip_port] # =====扩展一个url路径====== def extra_urls(self): url_list = [ url(r'^report/$', self.report_view), ] return url_list def report_view(self,request): return HttpResponse("<h3>这是我给报表另外添加的一个路径</h3>") v1.site.register(models.Host,HostConfig)

    四、总结:

    注意:如果是在应用里面建的static文件,是不用再settings里面配置的,就可以用
        需要知道的知识点
         1、for model_calss,stark_config_obj in self._registry.items():
                app_name = model_calss._meta.app_label#应用名称
                model_name = model_calss._meta.model_name#表的名称
                self.model_class._meta.get_field(field_name).verbose_name  #得到字段的verbose_name
                
        2、   if isinstance(field_name,str):
                        #如果是字符串类型的就是用getattr的方式,因为对象不能.字符串
                        val = getattr(row,field_name)
    
        3、   for field_name in self.list_display:
                    if isinstance(field_name,str):
                        #如果是字符串类型的就是用getattr的方式,因为对象不能.字符串
                        val = getattr(row,field_name)
                    else:  #如果不是字符串传进来的就是函数,所以得加括号调用函数
                        val = field_name(field_name,row)
                    temp.append(val)
                new_data_list.append(temp)  
                
        4、吧方法当属性来用
        @property
        def urls(self):
            return self.get_urls()

    一个小知识:
        1、什么时候加括号,什么时候不加括号
           当需要一个返回值的时候,就去执行函数,加括号
           当你不需要返回什么,直接告诉它函数名,让他去找这个函数名。就不用加括号
    补充:用bootstrap修改样式

     1、include:用include直接把单独的标签可以引入到html中。目的是减少代码的冗余

    {% include "stark/form.html" %}
    stark/form.html
    <form method="post"  class="form-horizontal" novalidate>
        {% csrf_token %}
        {% for field in form %}
            <div class="col-sm-6">
                <div class="form-group">
                    <label for="inputEmail3" class="col-sm-2 control-label">{{ field.label }}</label>
                    <div class="col-sm-10">
                        {{ field }}
                        {{ field.errors.0 }}
                    </div>
                </div>
            </div>
        {% endfor %}
        <div class="col-sm-offset-11 col-sm-1">
            <input type="submit" class="btn btn-primary" value="提交">
        </div>
    </form>

    css样式

    .form-horizontal input[type="text"],input[type='email'],input[type='password'],input[type='checkbox'],input[type='number'],select,textarea{
                display: block;
                width: 100%;
                height: 34px;
                padding: 6px 12px;
                font-size: 14px;
                line-height: 1.42857143;
                color: #555;
                background-color: #fff;
                background-image: none;
                border: 1px solid #ccc;
                border-radius: 4px;
                -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
                box-shadow: inset 0 1px 1px rgba(0, 0, 0, .075);
                -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s;
                -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
                transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
            }

    补充二:需要优化的导入静态文件的方式

    {% load staticfiles %}
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width">
        <title>Title</title>
        <link rel="stylesheet" href="{% static '/bootstrap-3.3.7-dist/css/bootstrap.css'%} ">
        <link rel="stylesheet" href="{% static '/css/stark_form.css' %}">
    </head>
    <body>
    <h3>添加页面</h3>
    {% include "stark/form.html" %}
    </body>
    </html>
  • 相关阅读:
    VS2010调试技巧
    asp.net中Web.Config配置文件详解
    vi进入编辑模式,按向左,向右,向上,向下,出现A,B,C,D字符解决方法
    su root后还是不能使用usermod,useradd等命令,错误描述:bash:usermod:command not found(转自http://myjieli.blog.51cto.com/135162/286462)
    启动VMware出现报错:The VMware Authorization Service is not running
    C++调用被C编译器编译过的函数要加extern "C"(转自http://zhidao.baidu.com/question/193713666.html)
    json,junit运行java.lang.NoClassDefFoundError: org/apache/commons/collections/map/ListOrderedMap
    java生成xml文件
    java连接数据库
    eclipse_javaee运行时总是未响应
  • 原文地址:https://www.cnblogs.com/haiyan123/p/8045303.html
Copyright © 2020-2023  润新知