附录:代码

Files

 stark 
┊----forms
┊----service
┊ ┊----__init__.py
┊ ┊----v1.py

┊----templates
┊----utils
┊ ┊----pagination.py

┊----__init__.py
┊----admin.py
┊----apps.py
....

v1.py

  1 import functools
  2 from types import FunctionType
  3 from django.shortcuts import HttpResponse,render,reverse,redirect
  4 from django.conf.urls import url
  5 from django.utils.safestring import mark_safe
  6 from stark.utils.pagination import Pagination
  7 from django.http import QueryDict
  8 from django import forms
  9 from django.db.models import ManyToManyField,ForeignKey
 10 
 11 
 12 class SearchGroupRow(object):
 13     def __init__(self,title,queryset_or_tuple, option_object,query_dict):
 14         """
 15 
 16         :param title: 组合搜索的列名称
 17         :param queryset_or_tuple: 组合搜索关联获取到的数据
 18         :param option_object: Option对象
 19         :param query_dict: request.GET
 20         """
 21         self.title = title
 22         self.queryset_or_tuple = queryset_or_tuple
 23         self.option_object = option_object
 24         self.query_dict = query_dict
 25 
 26     def __iter__(self):
 27         yield mark_safe('<span class="search_group label label-default">%s</span>'%self.title)
 28         # yield self.title
 29         for item in self.queryset_or_tuple:
 30             text = self.option_object.get_text(item) #性别 /部门
 31             value = self.option_object.get_value(item) #'1' /技术部
 32 
 33             # url_dict = QueryDict(mutable=True)     一样的结果
 34             # url_dict[text] = value
 35             query_dict = self.query_dict.copy() #{'gender': ['1']}  #生成下面URL需要(1)
 36             query_dict._mutable = True
 37 
 38 
 39             if not self.option_object.is_multi:
 40                 request_value_list = query_dict.getlist(self.option_object.field) #获取GET数据 ['2']
 41 
 42                 query_dict[self.option_object.field] = value #生成下面URL需要(2)
 43                 # print(text,str(value),request_value_list)
 44                 if str(value) in request_value_list:
 45                     #通过去除 ?gender=2 重新赋值URL,实现再选取时 自动消失样式
 46                     query_dict.pop(self.option_object.field)
 47                     yield mark_safe('<a class="btn btn-danger active" href="?%s">%s</a>'%(query_dict.urlencode(),text))
 48                 else:
 49                     yield mark_safe('<a class="btn btn-default" href="?%s">%s</a>'%(query_dict.urlencode(),text))
 50 
 51             else:
 52                 multi_request_value_list =query_dict.getlist(self.option_object.field) #['1','2']
 53                 if str(value) in multi_request_value_list:
 54                     multi_request_value_list.remove(str(value))
 55                     query_dict.setlist(self.option_object.field,multi_request_value_list)
 56                     yield mark_safe('<a class="btn btn-danger active" href="?%s">%s</a>'%(query_dict.urlencode(),text))
 57                 else:
 58                     multi_request_value_list.append(str(value))
 59                     query_dict.setlist(self.option_object.field,multi_request_value_list)
 60                     yield mark_safe('<a class="btn btn-default" href="?%s">%s</a>'%(query_dict.urlencode(),text))
 61 
 62 class Option(object):
 63     def __init__(self,field,is_multi=False,db_condition=None,text_func=None,value_func=None):
 64         """
 65         :param field: 组合搜索关联的字段
 66         :param is_multi: 是否支持多选
 67         :param db_condition: 数据库关联查询时的条件
 68         :param text_func: 此函数用于组合搜索按钮 展示 文本或者图案
 69         :param value_func: 此函数用于显示组合搜索按钮值
 70         """
 71         self.field = field
 72         self.is_multi = is_multi
 73         if not db_condition:
 74             db_condition = {}
 75         self.db_condition = db_condition
 76         self.text_func = text_func
 77         self.value_func = value_func
 78 
 79         self.is_choice = False
 80 
 81     def get_db_condition(self):
 82         return self.db_condition
 83 
 84     def get_queryset_or_tuple(self,model_class,request,*args,**kwargs):
 85         """
 86 
 87         :param model_class:
 88         :param request:
 89         :param args:
 90         :param kwargs:
 91         :return:
 92         """
 93         field_object = model_class._meta.get_field(self.field) #choice:app01.UserInfo.gender #FK:app01.UserInfo.depart
 94 
 95         title = field_object.verbose_name
 96         if isinstance(field_object,ForeignKey) or isinstance(field_object,ManyToManyField):
 97             db_condition = self.get_db_condition()
 98             #### 返回的是QuerySet类型 ####
 99             #print(field_object.remote_field.model.objects.filter(**db_condition)) <QuerySet [<Depart: 技术部>, <Depart: 美术部>]>
100             return SearchGroupRow(title,field_object.remote_field.model.objects.filter(**db_condition),self,request.GET) #self是Option类对象
101         else:
102             #### 获取choice中的数据 / 返回的是元祖类型 ####
103             self.is_choice = True
104             # print(field_object.choices)  ((1, '男'), (2, '女'))
105             return SearchGroupRow(title,field_object.choices,self,request.GET)
106 
107     def get_text(self,field_object):
108         if self.text_func:  #如果自定义了函数,则用自己的
109             return self.text_func(field_object)
110 
111         if self.is_choice:
112             return field_object[1]
113 
114         return str(field_object)
115 
116     def get_value(self,field_object):
117         if self.value_func:  #自定制
118             return self.value_func(field_object)
119 
120         if self.is_choice:
121             return field_object[0]
122 
123         return field_object.pk
124 
125 
126 def get_choice_text(title,field):
127     """
128     对于Stark组件中定义列时,choice如果想要显示中文信息,调用此方法即可
129     :param title: 表头名称(自定义)
130     :param field: 字段名称(需要提取的)
131     :return:
132     """
133     def inner(self,obj=None,is_header=None):
134         if is_header:
135             return title
136         method = "get_%s_display" %field
137         return getattr(obj,method)()
138 
139     return inner
140 
141 def get_m2m_text(title, field):
142     """
143     对于Stark组件中定义列时,显示m2m文本信息
144     :param title: 表头名称
145     :param field: 字段名称
146     :return:
147     """
148 
149     def inner(self, obj=None, is_header=None, *args, **kwargs):
150         if is_header:
151             return title
152         queryset = getattr(obj, field).all()
153         text_list = [str(row) for row in queryset]
154         return ','.join(text_list)
155 
156     return inner
157 
158 class StarkHandler(object):
159 
160     per_page_count = 10
161     model_form = False
162 
163 
164     def __init__(self,site,model_class,prev):
165         """
166         :param site: 一个对象
167         :param model_class: 数据库表的类
168         :param prev: url前缀
169         """
170         self.site = site
171         self.model_class = model_class
172         self.prev = prev
173 
174     list_display = []
175     def get_list_display(self):
176         """
177         获取页面上应该显示的列,预留自定义扩展
178         :return:
179         """
180         field_list = []
181         field_list.extend(self.list_display)
182         return field_list
183 
184     has_add_btn = True
185     def get_add_btn(self,**kwargs):
186         if self.has_add_btn:
187             return mark_safe('<a href="%s" class="btn btn-danger">添加</a>'%self.reverse_add_url(**kwargs))
188         return None
189 
190     action_list = []
191     def get_action_list(self):
192         """
193         处理批量操作等自定义方法
194         :return:
195         """
196         return self.action_list
197 
198     def get_queryset(self,**kwargs):
199         return self.model_class.objects
200 
201     order_list = []
202     def get_order_list(self):
203         return self.order_list or ['id']
204 
205     search_list = []
206     def get_search_list(self):
207         return self.search_list
208 
209     search_group = []
210     def get_search_group(self):
211         return self.search_group
212 
213     def get_search_group_condition(self,request):
214         condition = {}
215         for option_object in self.get_search_group():
216             if option_object.is_multi:
217                 value_list = request.GET.getlist(option_object.field) #tags=[1,2]
218                 if not value_list:
219                     continue
220                 condition['%s__in' %option_object.field] = value_list
221             else:
222                 value = request.GET.get(option_object.field)
223                 if not value:
224                     continue
225                 condition[option_object.field] = value
226 
227         return condition
228 
229     def multi_delete(self,request):
230         """
231         批量删除
232         :param request:
233         :return:
234         """
235         pk_list = request.POST.getlist('pk')
236         self.model_class.objects.filter(id__in=pk_list).delete()
237 
238     multi_delete.text = '一键删除'
239 
240     list_template = None
241     def list_view(self,request,*args,**kwargs):
242 
243         ###################### 处理action #####################
244 
245         action_list = self.action_list
246         action_dict = {func.__name__:func.text for func in action_list}
247 
248         if request.method == 'POST':
249             func_name = request.POST.get('action')
250             if func_name and func_name in action_dict:  #逻辑优化,防止被 方法乱入
251                 func = getattr(self,func_name)
252                 func(request)
253 
254 
255         ###################### 1.搜索(有值才会显示搜索框) #####################
256         search_list = self.get_search_list()
257         search_value = request.GET.get('q','')
258 
259         from django.db.models import Q
260         conn = Q()
261         conn.connector = 'OR'
262 
263         if search_value:
264             #Q,用于构造复杂的ORM查询条件
265             for item in search_list:
266                 conn.children.append((item,search_value))
267 
268         ######################### 2.获取排序 ###############################
269         order_list = self.get_order_list()
270 
271         #组合搜索条件字典
272         search_dict = self.get_search_group_condition(request)
273 
274         #自定义方法筛选后的结果
275         queryset = self.get_queryset(**kwargs)
276         # print(queryset)
277         queryset = queryset.filter(conn).filter(**search_dict).all().order_by(*order_list)
278 
279         ###################### 3.处理分页(使用组件) #######################
280         all_count = queryset.count()
281         query_params = request.GET.copy() # ?=page=1&name='李四'
282         query_params._mutable = True  #query_params['page']默认是不可以修改的
283 
284         pager = Pagination(
285             current_page=request.GET.get('page'),
286             all_count=all_count,
287             base_url=request.path_info,
288             query_params=query_params,
289             per_page=self.per_page_count,
290         )
291 
292         ###################### 4.处理表格 ##############################
293         list_display = self.get_list_display()
294         # 4.1处理表头
295         header_list = []
296         if list_display:
297             for multi_key in list_display:
298                 if isinstance(multi_key,FunctionType):  #判断 传入值是否为函数
299                     verbose_name = multi_key(self,obj=None,is_header=True)
300                 else:
301                     verbose_name = self.model_class._meta.get_field(multi_key).verbose_name
302                 header_list.append(verbose_name)
303         else:
304             header_list.append(self.model_class._meta.model_name)
305 
306         # 4.2处理表的内容
307         data_list = queryset[pager.start:pager.end]
308 
309         body_list = []
310         for row in data_list:  #row 是UserInfo object (1)
311             row_list = []
312 
313             if list_display:
314                 for multi_key in list_display:
315                     if isinstance(multi_key,FunctionType):
316                         row_list.append(multi_key(self,row,is_header=False,*args,**kwargs))
317                     else:
318                         row_list.append(getattr(row,multi_key))  #获取UserInfo object (1)的属性
319             else:
320                 row_list.append(row)
321 
322             body_list.append(row_list)
323 
324         ###################### 5.处理添加按钮 ##############################
325         add_btn = self.get_add_btn(**kwargs)  #是一个URL
326 
327         ###################### 6.处理组合搜索 ##############################
328         search_group_row_list = []
329         search_group = self.get_search_group() # ['gender', 'depart']
330         for keyword_object in search_group:  #keyword是一个Option类实例对象
331             row = keyword_object.get_queryset_or_tuple(self.model_class,request,*args,**kwargs)
332             #返回的是一个SearchGroupRow对象,且可迭代
333             search_group_row_list.append(row)
334 
335 
336         return render(request,
337                       self.list_template or 'list.html',
338                       {'body_list':body_list,
339                        'header_list':header_list,
340                        'pager':pager,
341                        'add_btn':add_btn,
342                        'search_list':search_list,
343                        'search_value':search_value,
344                        'action_dict':action_dict,
345                        'search_group_row_list':search_group_row_list})
346 
347     def add_view(self,request,*args,**kwargs):
348         """
349         添加视图
350         :param request:
351         :return:
352         """ 
353 
354         model_form = self.get_model_form()
355         if request.method == 'GET':
356             form = model_form
357             return render(request, 'change.html', {'form': form})
358 
359         form = model_form(data=request.POST)
360         if form.is_valid():
361             response =  self.save(request,form,False,*args,**kwargs)
362             return response or redirect(self.reverse_list_url(**kwargs))
363         return render(request,'change.html',{'form':form})
364 
365     def get_change_object(self, request, pk, *args, **kwargs):
366         return self.model_class.objects.filter(pk=pk).first()
367 
368     def change_view(self,request,pk,*args,**kwargs):
369         """
370         编辑视图
371         :param request:
372         :param pk:
373         :return:
374         """
375         checked_obj = self.get_change_object(request, pk, *args, **kwargs)
376 
377         if not checked_obj:
378             return render(request,'rbac\error.html')
379 
380         model_form = self.get_model_form()
381         if request.method == 'GET':
382             form = model_form(instance=checked_obj)
383             return render(request, 'change.html', {'form': form})
384 
385         form = model_form(data=request.POST,instance=checked_obj)
386         if form.is_valid():
387             response = self.save(request, form, True, *args, **kwargs)
388             return response or redirect(self.reverse_list_url(**kwargs))
389         return render(request, 'change.html', {'form': form})
390 
391     def delete_object(self, request, pk, *args, **kwargs):
392         self.model_class.objects.filter(pk=pk).delete()
393 
394     def delete_view(self,request,pk,*args,**kwargs):
395         """
396         删除视图
397         :param request:
398         :param pk:
399         :return:
400         """
401         checked_obj  = self.model_class.objects.filter(pk=pk).first()
402         if not checked_obj:
403             return render(request,'rbac\error.html',)
404 
405         list_url = self.reverse_list_url(**kwargs)
406         if request.method == 'GET':
407             return render(request,'delete.html',{'list_url':list_url})
408 
409         response = self.delete_object(request, pk, *args, **kwargs)
410         return response or redirect(list_url)
411 
412     def save(self,request,form,is_update,*args,**kwargs):
413         form.save()
414 
415     def get_model_form(self):
416         if self.model_form:
417             return self.model_form
418 
419         class DynamicModelForm(forms.ModelForm):
420             class Meta:
421                 model = self.model_class
422                 fields = "__all__"
423 
424             def __init__(self, *args, **kwargs):
425                 super(DynamicModelForm, self).__init__(*args, **kwargs)
426                 # 统一给ModelForm生成字段添加样式
427                 for name, field in self.fields.items():
428                     field.widget.attrs['class'] = 'form-control'
429 
430         return DynamicModelForm
431 
432     def display_edit(self,obj=None,is_header=None):
433         """
434         生成<编辑>a标签
435         :param obj:
436         :param is_header:
437         :return:
438         """
439         if is_header:
440             return "编辑操作"
441         change_url = self.reverse_change_url(pk=obj.pk)
442         return mark_safe('<a href="%s">编辑</a>'%change_url)
443 
444     def display_delete(self,obj=None,is_header=None):
445         """
446         生成<删除>a标签
447         :param obj:
448         :param is_header:
449         :return:
450         """
451         if is_header:
452             return "删除操作"
453         delete_url = self.reverse_delete_url(pk=obj.pk)
454         return mark_safe('<a href="%s">删除</a>'% delete_url)
455 
456     def display_checkbox(self,obj=None,is_header=None):
457         """
458         生成checkbox 批量操作
459         :param obj:
460         :param is_header:
461         :return:
462         """
463         if is_header:
464             return "选择"
465         return mark_safe('<input type="checkbox" name="pk" value="%s">'%obj.pk)
466 
467 
468     #视图函数放在这里是因为可以以后重写或者扩展(继承该类即可)!
469     def get_urls(self):
470         """
471         生成视图函数
472         :return:
473         """
474         patterns = [
475             url(r'^list/$', self.wapper(self.list_view), name=self.get_list_url_name),
476             url(r'^add/$', self.wapper(self.add_view), name=self.get_add_url_name),
477             url(r'^change/(?P<pk>\d+)/$', self.wapper(self.change_view), name=self.get_change_url_name),
478             url(r'^delete/(?P<pk>\d+)/$', self.wapper(self.delete_view), name=self.get_delete_url_name),
479         ]
480 
481         patterns.extend(self.extra_urls())
482         return patterns
483 
484     def extra_urls(self):
485         return []
486 
487     def get_url_name(self,param):
488         """
489         返回别名(所有别名最后在这里处理)
490         :param param:
491         :return:
492         """
493         app_name = self.model_class._meta.app_label
494         model_name = self.model_class._meta.model_name
495         if self.prev:
496             return '%s_%s_%s_%s' %(app_name,model_name,self.prev,param) #Web_customer_public_list
497         return '%s_%s_%s' %(app_name,model_name,param)
498 
499     ######################### 生成带搜索条件的URL ########################
500     def reverse_add_url(self,**kwargs):
501         name = "%s:%s" % (self.site.namespace, self.get_add_url_name)  #stark:Web_customer_public_list
502         url = reverse(name,kwargs=kwargs)
503 
504         if not self.request.GET:
505             add_url = url
506         else:
507             param = self.request.GET.urlencode()  # page=1
508 
509             new_query_dict = QueryDict(mutable=True)
510             new_query_dict['_filter'] = param  # <QueryDict: {'_filter': ['page=1']}>
511 
512             add_url = "%s?%s" % (url, new_query_dict.urlencode(()))
513 
514         return add_url
515 
516     def reverse_list_url(self,**kwargs):
517         name = "%s:%s" % (self.site.namespace, self.get_list_url_name)
518         url = reverse(name,kwargs=kwargs)
519         if not self.request.GET:
520             list_url = url
521         else:
522             param = self.request.GET.get('_filter')
523             # print(param)  #page=1
524             if not param:
525                 return redirect(url)
526             list_url = "%s?%s" % (url, param)
527 
528         return list_url
529 
530     def reverse_change_url(self,*args,**kwargs):
531         name = "%s:%s" % (self.site.namespace, self.get_change_url_name)
532         url = reverse(name,args=(*args,),kwargs=kwargs)
533         if not self.request.GET:
534             change_url = url
535         else:
536             param = self.request.GET.urlencode()  # page=1
537 
538             new_query_dict = QueryDict(mutable=True)
539             new_query_dict['_filter'] = param  # <QueryDict: {'_filter': ['page=1']}>
540 
541             change_url = "%s?%s" % (url, new_query_dict.urlencode(()))
542         return change_url
543 
544     def reverse_delete_url(self,*args,**kwargs):
545         name = "%s:%s" % (self.site.namespace, self.get_delete_url_name)
546         url = reverse(name,args=(*args,),kwargs=kwargs)
547         if not self.request.GET:
548             delete_url = url
549         else:
550             param = self.request.GET.urlencode()  # page=1
551 
552             new_query_dict = QueryDict(mutable=True)
553             new_query_dict['_filter'] = param  # <QueryDict: {'_filter': ['page=1']}>
554 
555             delete_url = "%s?%s" % (url, new_query_dict.urlencode(()))
556 
557         return delete_url
558 
559     def reverse_commons_url(self,name,*args,**kwargs):
560         """
561         反向生成有别名的URL
562         :param name: 别名
563         :param args:
564         :param kwargs:
565         :return:
566         """
567         name = "%s:%s" % (self.site.namespace, name)
568 
569         url = reverse(name,args=(*args,),kwargs=kwargs )
570 
571         if not self.request.GET:
572             commons_url = url
573         else:
574             param = self.request.GET.urlencode()  # page=1
575 
576             new_query_dict = QueryDict(mutable=True)
577             new_query_dict['_filter'] = param  # <QueryDict: {'_filter': ['page=1']}>
578 
579             commons_url = "%s?%s" % (url, new_query_dict.urlencode(()))
580 
581         return commons_url
582     ###################################################################
583 
584     def wapper(self,func):
585         @functools.wraps(func)
586         def inner(request,*args,**kwargs):
587             self.request = request
588             return func(request,*args,**kwargs)
589         return inner
590 
591     @property
592     def get_list_url_name(self):
593         """
594         获取列表页面URL的name
595         :return:
596         """
597         return self.get_url_name('list')
598 
599     @property
600     def get_add_url_name(self):
601         """
602         获取列表页面URL的name
603         :return:
604         """
605         return self.get_url_name('add')
606 
607     @property
608     def get_change_url_name(self):
609         """
610         获取列表页面URL的name
611         :return:
612         """
613         return self.get_url_name('change')
614 
615     @property
616     def get_delete_url_name(self):
617         """
618         获取列表页面URL的name
619         :return:
620         """
621         return self.get_url_name('delete')
622 
623 
624 class StarkSite(object):
625     def __init__(self):
626         self._registry = []
627         self.app_name = 'stark'
628         self.namespace = 'stark'
629 
630     def register(self, model_class, handler_class=None,prev=None):
631         """
632 
633         :param model_class:models中的数据库相关的类(是一个类!!)
634         :param handler_class:处理请求的视图函数所在的类
635         :param prev:url前缀
636         :return:
637         """
638         print('hello,zifeng')
639         """
640         [
641             {"model_class":models.Userinfo,'handler':UserinfoHanler(model.Userinfo)}
642         ]
643         
644         [
645         {'model_class': <class 'app01.models.UserInfo'>, 这是类!
646         'handler': <app01.stark.UserinfoHandler object at 0x00000293A125A8D0>  这是对象!}
647         ]
648         """
649         if not handler_class:
650             handler_class = StarkHandler
651         self._registry.append({'prev':prev,'model_class':model_class,'handler':handler_class(self,model_class,prev)})
652 
653 
654     def get_urls(self):
655         patterns = []
656         for item in self._registry:
657             prev = item['prev']
658             model_class = item['model_class']
659             handler = item['handler']
660             app_name = model_class._meta.app_label
661             model_name = model_class._meta.model_name
662 
663             if prev:
664                 patterns.append(url(r'^%s/%s/%s/'%(app_name,model_name,prev),(handler.get_urls(),None,None)))
665             else:
666                 patterns.append(url(r'^%s/%s/' % (app_name, model_name), (handler.get_urls(), None,None)))
667 
668         # patterns.append()
669         return patterns
670 
671     @property
672     def urls(self):
673         return self.get_urls(),self.app_name,self.namespace
674 
675 
676 site = StarkSite()
View Code

apps.py

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

猜你喜欢

转载自www.cnblogs.com/steven2020/p/10714427.html