zoukankan      html  css  js  c++  java
  • Sansa组件

    诉求

      仿照admin组件,实现对表的URL分配管理。

    实现思路

      1.在settings.py文件中注册APP,注册示例为:

    'app01.apps.App01Config',
    'app02.apps.App02Config',
    ‘stark_demo.apps.StarkDemoConfig',
    

      2. 在每一个APP中的apps.py 文件中添加

    1 from django.apps import AppConfig
    2 from django.utils.module_loading import autodiscover_modules
    3 
    4 class App01Config(AppConfig):
    5     name = 'app01'
    6 
    7     def ready(self):
    8         autodiscover_modules('stark',)

    实现在Django项目启动时,扫描每个APP项目下的stark.py文件的文件,执行其中的代码,注册每个APP下的model,为每一个model生成增删改查四条URL。

    来一张流程图进行说明。

    Starksite类和Modelstark类的创建

      1 from django.conf.urls import url
      2 from django.shortcuts import HttpResponse, render, reverse,redirect
      3 from django.utils.safestring import mark_safe
      4 from django.forms import ModelForm
      5 from app01.models import *
      6 from app02.models import *
      7 
      8 # 针对使用stark组件的默认样式类
      9 
     10 
     11 class Modelstark(object):
     12     list_display = ["__str__"]
     13     list_display_link = ["__str__"]
     14     model_form = None
     15     # init 方法在实例化类的时候执行
     16 
     17     def __init__(self, model, site):
     18         self.model = model
     19         self.site = site
     20         self.label_model = (self.model._meta.app_label, self.model._meta.model_name)
     21     '''
     22     功能:
     23         将显示、编辑、删除、增加页面的url 封装到函数中。
     24     函数名:
     25         def get_add_url(self)
     26         def get_del_url(self,obj)
     27         def get_edit_url(self,obj)
     28         def get_list_url(self)
     29     '''
     30     def get_add_url(self):
     31         add_url = reverse("%s_%s_add" % self.label_model, )
     32         return add_url
     33 
     34     def get_del_url(self,obj):
     35         del_url = reverse("%s_%s_del" % self.label_model, args=(obj.pk,))
     36         return del_url
     37 
     38     def get_edit_url(self,obj):
     39         edit_url = reverse("%s_%s_edit"% self.label_model,args=(obj.pk,))
     40         return edit_url
     41 
     42     def get_list_url(self):
     43         list_url = reverse("%s_%s_show"%self.label_model,)
     44         return list_url
     45     '''
     46     功能:
     47         为显示页面右侧的添加按钮生成动态的URL
     48     函数名:
     49         def add_btn(self,obj=None,header=False)
     50     '''
     51     def add_btn(self,obj=None,header=False):
     52         if header:
     53             pass
     54         return mark_safe("<a href='%s' type='button' class='btn btn-success btn-lg pull-right'>添加</a>"%self.get_add_url())
     55     '''
     56     功能:
     57         为显示页面生成编辑、删除和复选框的标签
     58     函数名:
     59         def edit(self,obj=None,header=False)
     60         def delete(self,obj=None,header=False)
     61          def checkbox(self,obj=None,header=False)
     62     '''
     63     def edit(self,obj=None,header=False):
     64         if header:
     65             return "操作"
     66         return mark_safe("<a href='%s''>编辑</a>"%self.get_edit_url(obj))
     67 
     68     def delete(self,obj=None,header=False):
     69         if header:
     70             return "操作"
     71         return mark_safe("<a href='%s''>删除</a>" %self.get_del_url(obj))
     72 
     73     def checkbox(self,obj=None,header=False):
     74         if header:
     75             return mark_safe("<input type='checkbox' id='action-toggle'>")
     76         pass
     77 
     78         return mark_safe("<input type='checkbox' value='%s'>"%obj.pk)
     79 
     80         pass
     81     '''
     82     功能:
     83         为每一个类生成modelform,用于渲染标签
     84         判断用户是否定义了model_form,如果定义了则用用户自己的类,没有则用默认的modelForm
     85         备注:
     86             显示中文错误提示信息的解决思想是:
     87                 在样式类中定义一个 model_form = None 的静态变量,在 def default_modelform(self) 函数中判断 model_form = None的bool值,若为False,
     88                 则表明用户没有自定义 model_form ,因此走默认的modelForm.
     89                 若model_form 为True,则表明用户对要注册的表定义了modelForm,因此用户会在自己的 XXXConfig类中声明 model_form = 自定义的modelForm,
     90                 此时用用户自定义的 modelForm
     91     函数名:
     92         def mdelform(self)
     93     '''
     94     def default_modelform(self):
     95         class modelForm(ModelForm):
     96             class Meta:
     97                 model = self.model
     98                 fields = "__all__"
     99         if not self.model_form:
    100             return modelForm
    101         else:
    102             return self.model_form
    103     '''
    104        功能:
    105             显示、编辑、增加、删除4个视图函数
    106        函数名:
    107             def show_list(self, request)
    108             def add_list(self, request)
    109             def edit_list(self, request,id)
    110              def del_list(self, request,id)
    111        '''
    112     def show_list(self, request):
    113         data_list = self.model.objects.all()
    114         # 显示表头名称
    115         header_list = []
    116         for i in self.real_list_display():
    117             if callable(i):
    118                 # 获取函数名:函数名.__name__
    119                 # header_list.append(i.__name__) -----> low版
    120                 header_list.append(i(self, header=True))
    121             else:
    122                 if i == "__str__":
    123                     header_list.append(self.model._meta.model_name.upper())
    124                 else:
    125                     header_list.append(self.model._meta.get_field(i).verbose_name)
    126 
    127         # print(self.list_display)
    128         # 首先循环每一条记录
    129         """
    130         需要构建的样式为:
    131         [
    132             ["id1","name1"],
    133             ["id2","name2"],
    134             ["id3","name3"],
    135         ]
    136         """
    137         # 显示数据
    138         ret_data_list = []
    139         for obj in data_list:
    140             tmp_list = []
    141             # 遍历显示的字段,i 指的是字段名称
    142             for i in self.real_list_display():
    143                 if callable(i):
    144                     val = i(self, obj)
    145                 else:
    146                     # val 为反射后的value
    147                     val = getattr(obj, i)
    148                     # 判断当前的 字段名称 是否在 list_display_link 中,在的话让该字段对应的值作为a标签
    149                     if i in self.list_display_link:
    150                         val = mark_safe("<a href='%s'>%s</a>"%(self.get_edit_url(obj),val))
    151                 tmp_list.append(val)
    152             ret_data_list.append(tmp_list)
    153         # 显示添加按钮
    154         btn_list = []
    155         # 使用类.函数 的方式需要传self,但是使用类的对象.方法的方式不需要传self
    156         val = Modelstark.add_btn(self)
    157         btn_list.append(val)
    158 
    159         return render(request, "show_list.html", locals())
    160 
    161     def add_list(self, request):
    162         modelForm = self.default_modelform()
    163         errors = {}
    164         if request.method == "POST":
    165             form = modelForm(request.POST)
    166             if form.is_valid():
    167                 form.save()
    168                 return redirect(self.get_list_url())
    169             else:
    170                 return render(request,"add.html",locals())
    171         form = modelForm()
    172         return render(request,"add.html",locals())
    173 
    174     def edit_list(self, request,id):
    175         obj = self.model.objects.filter(id=id).first()
    176         modelForm = self.default_modelform()
    177         if request.method == "POST":
    178             form = modelForm(request.POST,instance=obj)
    179             if form.is_valid():
    180                 form.save()
    181                 return redirect(self.get_list_url())
    182             else:
    183                 pass
    184         form = modelForm(instance=obj)
    185         return render(request,"edit.html",locals())
    186 
    187     def del_list(self, request,id):
    188         if request.method == "POST":
    189             self.model.objects.filter(id=id).delete()
    190             return redirect(self.get_list_url())
    191         list_url = self.get_list_url()
    192         return render(request,"delete.html",locals())
    193     '''
    194     功能:
    195         在显示页面要真正显示的字段,对list_display进行扩展
    196     函数名:
    197         def real_list_display(self)
    198     '''
    199     def real_list_display(self):
    200         new_list_display = []
    201         new_list_display.extend(self.list_display)
    202         new_list_display.append(Modelstark.edit)
    203         new_list_display.append(Modelstark.delete)
    204         new_list_display.insert(0,Modelstark.checkbox)
    205         return new_list_display
    206     '''
    207     功能:
    208         为没一个注册的model生成增删改查四条URL
    209     函数名:
    210         def get_url_func(self)
    211     '''
    212     def get_url_func(self):
    213         tmp = []
    214         app_name = self.model._meta.app_label
    215         model_name = self.model._meta.model_name
    216         ret = (app_name, model_name)
    217         tmp.append(url("^$", self.show_list, name="%s_%s_show" %ret))
    218         tmp.append(url("^add/$", self.add_list, name="%s_%s_add" %ret))
    219         tmp.append(url("^edit/(d+)/$", self.edit_list, name="%s_%s_edit" %ret))
    220         tmp.append(url("^del/(d+)/$", self.del_list, name="%s_%s_del" %ret))
    221         '''
    222         在访问URL之前就已经分别为每张表创建了4条URL
    223         '''
    224         return tmp
    225 
    226 
    227 # 创建stark类,实例化Starksite,用于注册model
    228 
    229 
    230 
    231 class Starksite(object):
    232 
    233     def __init__(self):
    234         # 保存表的注册信息,保存的格式为:以model类为键,以该model实例化样式对象为值
    235         self._registry = {}
    236 
    237     # 类的注册函数
    238     def register(self, model, modelconfig=None):
    239         '''
    240         实现model的注册
    241         :param model: 要注册的类
    242         :param modelconfig: 该注册类的样式对象
    243         :return: None
    244         '''
    245         
    246         '''
    247         判断用户是否自己定义了样式类,如果没有,此时的modelconfig为None,则用默认的ModelStark样式类进行实例化注册;
    248         若用户自定义了注册类的样式对象,则使用用于自定的样式对象
    249         '''
    250         if not modelconfig:
    251             modelconfig = Modelstark
    252         # model是每次循环注册的表,self是实例化的Startksite类的实例化对象
    253         '''
    254         在对注册的model进行样式实例化的时候,modelconfig类实际上是Modelstark类的实例化,实例化要执行类的__init__函数,init函数的定义为:
    255             def __init__(self, model, site):
    256                 self.model = model
    257                 self.site = site
    258                 self.label_model = (self.model._meta.app_label, self.model._meta.model_name)
    259             此时实例化的方式为:类名.__init__() 方式,因此需要传self。
    260             另外需要注意的是modelconfig(model,self)中的self是哪个类的实例化对象
    261             当在注册类的时候没有传入制定的样式类,那么这里的self是Modelstark类的实例化,
    262             但是,当用户传入定制的样式类时,此时的self是modelconfig类的实例化
    263         '''
    264         self._registry[model] = modelconfig(model, self)
    265 
    266     def get_urls(self):   
    267         '''
    268         生成表的一级和二级URL
    269         :return: tmp 
    270         '''
    271         tmp = []
    272         '''
    273         item():使字典中的键值对以元组的形式显示
    274         model: 注册的model类
    275         model_config:该类对应的样式类对象
    276         app_label:以字符串形式获取类所在的APP
    277         model_name:以字符串的获取类名
    278         '''
    279         for model, model_config in self._registry.items():
    280             app_label = model._meta.app_label
    281             model_name = model._meta.model_name
    282             #  为什么不能去掉None
    283             u = url("^%s/%s/" % (app_label, model_name), (model_config.get_url_func(), None, None))
    284             tmp.append(u)
    285         return tmp
    286     '''
    287     把urls函数做成静态方法,urls.py 中执行urls函数不需要加()
    288     '''
    289     @property
    290     def urls(self):
    291         return self.get_urls(), None, None
    292 
    293 
    294 # 创建单例对象,在每一个app中的stark文件中调用
    295 site = Starksite()

    各功能的实现思路

    一级与二级URL的设计思路

      在注册完表后,执行urls.py文件,执行

    1 urlpatterns = [
    2     url(r'^admin/', admin.site.urls),
    3     url(r'^stark/', site.urls),
    4 ]

      site为类Starksite的单例实例化对象,site.urls 调用类下的urls方法,而urls方法实际上是执行get_urls(self) 方法,为每一个model首先生成一级URL,其次调用类的样式对象下的get_url_func(self)

    函数,生成二级URL,同时为每一个增删改查URL创建别名,用于反向解析。

    显示页面的数据显示

      1.数据显示的思路

        首先类中定义一个 list_display = ["__str__"]的静态变量,此静态变量在用于没有重写该变量时,则默认显示该对象的 def __str__(self) 方法的返回值。 

        将显示的数据以 [ [1,"python",12,"<a>编辑</a>"],[2,"java",23,"<a>编辑</a>"],[3,"php",111,"<a>编辑</a>"],]的形式在后后台处理成功后,循环判断要显示的数据是一个字符串还是可执行函数,若是可执行函数则执行函数后追加保存到列表中,若是字符串则直接追加保存在列表中。

        PS:

         1.getattr(obj,str) 函数用于反射,实现通过对象的字段名名称找到该字段对应的值。

         2.要循环的字段实际上是new_list_display, 即对list_display进行扩展,是默认显示的字段有复选框、对象名称、编辑、删除

        def real_list_display(self):
            new_list_display = []
            new_list_display.extend(self.list_display)
            new_list_display.append(Modelstark.edit)
            new_list_display.append(Modelstark.delete)
            new_list_display.insert(0,Modelstark.checkbox)
            return new_list_display

      2.编辑和删除a标签的实现

        把编辑和删除的a标签分别作为一个函数,使该函数的返回值为 mark_safe("<a>编辑</a>"),在循环要显示的字段对象的数据时,执行该函数。

        PS:

          mark_safe()函数实现前端safe相同的功能,使django不转移标签对象。

      3.表头的实现

        根据list_display 循环显示表头,当遇到“__str__”时,找到该该对象的“__str__“”方法的返回值,当遇到制定的字段名称,如public时,则使用 self.model._meta.get_field(i).verbose_name获取该字段的verbose_name,追加到列表中。

        PS:

         get_field(arg) 可以获取到model表中该arg字段对象,该对象可以调用字段的属性,如verbose_name。

      4.让字段作为a标签,实现跳转到编辑页面的实现

        在循环显示数据的时候, 判断通过getattr()方法获取的字段值是否在list_display_link中,如果在,则使用mark_safe()使该value成为a标签。

      5. ModelForm 组件实现页面的增删改查

        只需要为要进行form渲染的类继承ModelForm,即可。

      6.使用ModelForm实现显示中文错误信息

         在样式类中创建一个model_form = None的静态变量,在创建 ModelForm 类的函数 def default_modelform(self)中判断model_form的值,值为None,则使用默认的modelform,如果为True,则使用用户stark.py中定义的样式类。

    在每个APP中stark.py文件的创建

     1 from .models import *
     2 # 对单例对象的调用
     3 from stark_demo.service.sites import site,Modelstark
     4 from django.forms import ModelForm
     5 
     6 
     7 class BookModelForm(ModelForm):
     8     '''
     9     重写model的modelform类
    10     '''
    11     class Meta:
    12         model = Book
    13         fields = "__all__"
    14         error_messages = {
    15             "title":{"required":"不能为空"},
    16             "public":{"required":"不能为空"}
    17         }
    18 
    19 
    20 class BookConfig(Modelstark):
    21 
    22     list_display = ["id","title","public"]
    23     list_display_link = ["id","title",]
    24     model_form = BookModelForm
    25 
    26 
    27 site.register(Book,BookConfig)
  • 相关阅读:
    Redis学习笔记(九、Redis总结)
    菜鸟刷面试题(二、RabbitMQ篇)
    RabbitMQ学习笔记(八、RabbitMQ总结)
    MongoDB学习笔记(七、MongoDB总结)
    菜鸟刷面试题(一、Java基础篇)
    朋友圈点赞
    队列变换
    犯二的程度
    猴子选大王
    最大销售增幅
  • 原文地址:https://www.cnblogs.com/liuyinzhou/p/8576144.html
Copyright © 2011-2022 走看看