django-admin 仿写stark组件action,filter筛选过滤,search查询
写在StandLi里面的方法都是通过ModelSubject这个类里面的stand_li方法,在它里面用StandLi这个类实例化出来一个对象,这个实例化出来的对象把数据传给前端HTML模板进行渲染,所以StandLi这个类里面的方法如果你找不到就是在给前端传数据用的
tag.py
- from django.conf.urls import url
- from django.shortcuts import render, redirect, reverse
- from django.utils.safestring import mark_safe
- from django.forms import ModelForm # 这个ModelForm里面封装了很强大的功能,要把源码过一遍
- from django.db.models import ForeignKey, ManyToManyField
- from django.utils.http import urlencode
- import copy
- # 这个类主要帮我们处理多级过滤的a标签,我们之前是把多级过滤的a标签给写到get_filter_link_tags这个函数里面,
- # 后来为了实现功能解耦,避免单个函数代码量过大,就把这个功能封装成了一个类,以便于阅读,以及功能扩展
- class LinkTagsGen(object):
- def __init__(self, data, filter_field, request):
- self.data = data
- self.filter_field = filter_field
- self.request = request
- def __iter__(self):
- """
- 所有的可迭代对象内部都是实现了__iter__方法,我们把数据写到这里就是实现的数据的可迭代
- :return: yield 多级过滤的A标签
- """
- current_id = int(self.request.GET.get(self.filter_field.filter_name, 0))
- params = copy.deepcopy(self.request.GET)
- params._mutable = True
- if params.get(self.filter_field.filter_name):
- del params[self.filter_field.filter_name]
- _url = "%s?%s" % (self.request.path_info, params.urlencode())
- yield mark_safe("<a href='%s'>All</a>" % _url)
- else:
- yield mark_safe("<a href='#' class='active'>All</a>")
- for item in self.data: # self.data是一个个的queryset集合以及元祖,((1,'已出版'),(2,'未出版')),
- # <QuerySet[<Publish:人民出版社>,<Publish:北京出版社>]>
- pk, text = None, None
- if self.filter_field.filter_obj.choices:
- pk, text = item[0], item[1]
- elif isinstance(self.filter_field.filter_obj, ForeignKey) or isinstance(self.filter_field.filter_obj, ManyToManyField):
- pk, text = item.pk, item
- params[self.filter_field.filter_name] = pk
- _url = "%s?%s" % (self.request.path_info, params.urlencode())
- if current_id == pk:
- link_tag = "<a class='active' href='%s'>%s</a>" %(_url, text)
- else:
- link_tag = "<a href='%s'>%s</a>" % (_url, text)
- yield mark_safe(link_tag)
- # 为每一个过滤的字段封装成整体类
- class FilterField(object):
- def __init__(self, filter_name, filter_obj):
- self.filter_name = filter_name
- self.filter_obj = filter_obj
- def get_data(self):
- if isinstance(self.filter_obj, ForeignKey) or isinstance(self.filter_obj, ManyToManyField):
- return self.filter_obj.rel.to.objects.all()
- elif self.filter_obj.choices:
- return self.filter_obj.choices
- # 服务于ModelSubject下面的stand_li,我们把stand_li里面的很多方法给封装到这个类里面实现功能解耦,
- # 主要是为了减轻我们的StandLi里面的代码量
- class StandLi(object):
- def __init__(self, config, request, queryset):
- """
- :param config: 它就是我们下面的类ModelSubject所传过来的它的self实例对象,
- 我们在这里要使用那些方法和变量就需要把它的这个实例对象拿过来,否则如下搬过来的代码块都会失效
- :param request: 我们这个类是在下面的ModelSubject里面调用然后在那里实例化出来的对象,所以这个request是它传过来的
- :param queryset: 同上,这个queryset也是ModelSubject所传过来的参数,供下面的代码调用
- """
- self.config = config
- self.request = request
- self.queryset = queryset
- # 生成分页器
- path = self.request.path_info
- params = self.request.GET
- page_num = request.GET.get('page', 1) # 如果没有找到page,就返回1,也就是第一页
- from file.utensil.page import MyPage
- count = queryset.count()
- page = MyPage(page_num, count, path, params)
- self.pagination = page
- data_list = self.queryset[page.start:page.end]
- self.data_list = data_list
- # page_html = page.page_html() # 这里我们可以把page_html方法直接在前端HTML模板里面引用
- # actions 实现批量操作功能
- self.actions = self.config.get_actions() # [patch_init, patch_delete]
- # print('actions', self.actions)
- # filter 实现筛选功能
- self.list_filter = self.config.list_filter
- # 实现多级过滤的类里面封装的一个函数
- def get_filter_link_tags(self):
- for filter_name in self.list_filter:
- filter_obj = self.config.model._meta.get_field(filter_name)
- filter_field = FilterField(filter_name, filter_obj)
- # print("filter_field", filter_field.get_data())
- """
- filter_field <QuerySet [<Publish: 长春出版社>, <Publish: 香港中文大学出版社>, <Publish: 中信出版社>]>
- filter_field ((0, '已出版'), (1, '未出版'))
- filter_field <QuerySet [<Writer: White>, <Writer: Black>, <Writer: Miss Lin>]>
- """
- val = LinkTagsGen(filter_field.get_data(), filter_field, self.request)
- yield val
- # 这里是使用两个yield去实现的多级过滤
- # 展示筛选条件
- # def get_filter_link_tags(self): # list_filter=['state','publish','authors']
- #
- # for filter_name in self.list_filter:
- # current_id = int(self.request.GET.get(filter_name, 0)) # 这里加上int之后我们点击超链接标签的时候就会有字体颜色的变化
- # # current_id = self.request.GET.get(filter_name, 0) # 这里没有加上int点击超链接的时候不会有变化
- # # print('current_id', current_id)
- # filter_obj = self.config.model._meta.get_field(filter_name)
- # # print('filter_obj', filter_obj)
- # filter_field = FilterField(filter_name, filter_obj)
- # # print("filter_field",filter_field)
- # def inner(filter_field, current_id):
- # # print(filter_field.get_data())
- #
- # # 这里得出的结果是我们的多对多字段和一对多字段的所有关联数据
- # # <QuerySet [<Publish: 长春出版社>, <Publish: 香港中文大学出版社>, <Publish: 中信出版社>]>
- # # <QuerySet [<Writer: White>, <Writer: Black>, <Writer: Miss Lin>]>
- #
- # for obj in filter_field.get_data():
- # if isinstance(filter_field.filter_obj, ForeignKey) or \
- # isinstance(filter_field.filter_obj, ManyToManyField):
- # # link_tags=[]
- # params = copy.deepcopy(self.request.GET)
- # params._mutable = True
- # params[filter_field.filter_name] = obj.pk
- #
- # if current_id == obj.pk:
- # yield mark_safe("<a class='active' href='?%s'>%s</a>" % (params.urlencode(), obj))
- # else:
- # yield mark_safe("<a href='?%s'>%s</a>" % (params.urlencode(), obj))
- # elif filter_field.filter_obj.choices:
- # params = copy.deepcopy(self.request.GET)
- # params._mutable = True
- # params[filter_field.filter_name] = obj[0]
- # if current_id == obj[0]:
- # yield mark_safe("<a class='active' href='?%s'>%s</a>" % (params.urlencode(), obj[1]))
- # else:
- # yield mark_safe("<a href='?%s'>%s</a>" % (params.urlencode(), obj[1]))
- # else:
- # # params = copy.deepcopy(self.request.GET)
- # # params._mutable = True
- # # params[filter_field.filter_name] = obj
- # # yield mark_safe("<a href='?%s'>%s</a>" % (params.urlencode(), obj))
- # ...
- # yield inner(filter_field, current_id)
- # 把自定义的action内容放到一个列表里面,以键值对的数据类型
- def handle_actions(self):
- temp = []
- for action_func in self.actions:
- temp.append({'name': action_func.__name__, "desc": action_func.desc})
- return temp
- # 获取表头数据
- def get_header(self):
- # 生成表头数据
- # ['id','title','price',edit]
- header_list = []
- for field in self.config.get_list_display():
- if callable(field):
- ret = field(self, is_header=True)
- header_list.append(ret)
- else:
- if field == '__str__': # 这里是判断我们的list_display列表里面是否有我们自定义传入的值,如果没有的话,
- # 就是直接等于我们在静态属性里面设定的那个默认的'__str__',也就是说如果这一步判断成立,
- # 那么就证明我们的用户没有自定义展示的字段,我们就需要自己给浏览器一个字段去展示,那个字段就是我们这里所设定的那个大写的表名
- header_list.append(self.config.model._meta.model_name.upper()) # 我们这里的操作是
- else:
- obj = self.config.model._meta.get_field(field) # 我们的list_display里面是一个个的字符串,
- # 把字符串放到get_field里面来可以把我们的字符串转换成类对象,
- header_list.append(obj.verbose_name) # 我们这里的verbose_name在model里面是内置方法,
- # 我们的verbose_name本质上是对我们的字段进行描述的,比如我们的book里面的title可以在字段约束里面设
- # verbose_name='书名',类似于这样,把它变成中文,然后我们在前端HTML模板里面渲染的时候就可以渲染出来中文了,
- # 而不是使用默认的英文,当然了我们如果不设置verbose_name的值那么就使用默认的title作为字段名传到浏览器
- return header_list
- # 获取表单数据
- def get_body(self):
- # 生成表单数据列表(我们把这个函数挪到上面这个类里面来之后,把循环遍历的数据改动了,之前是把当前表格的数据取出来之后就直接遍历它,
- # 后来我们有了搜索功能,那么就不能遍历表格里面的所有数据了,需要把我们过滤查询出来的数据给遍历出来
- # ret = self.config.model.objects.all().count()
- # print('self.list_display', self.list_display)
- data_list = []
- for obj in self.data_list: # 我们遍历这个queryset集合得到的obj是它的每一个对象
- temp = []
- for field in self.config.get_list_display(): # 我们遍历list_display得到每一个字符串
- if callable(field):
- # res = field(obj) # @@@更上面的特殊标识的代码块相呼应
- res = field(self.config, obj) # &&& 这里跟上面同样标识的代码块相呼应的,上面我们使用的类名去调用函数名,
- # 得到的是一个函数,这里就是给所调用的函数传参的,self,和obj都是我们传给函数的参数;
- # 如果我们使用self这个对象去调用函数名的方法的话,就不需要再传一个self作为参数进去了,我们两种方法都可以,需要对应上即可
- else:
- res = getattr(obj, field) # 使用getattr方法去判断该对象是否具有,field属性方法,
- # getattr里面需要两个参数(类对象,字符串属性方法)
- if field in self.config.list_display_links: # 我们这里是判断表单里面的字段是否在links表格里面被自定义作为可跳转标签,
- # 如果答案是肯定的,那么我们就需要把a标签给拼出来
- res = self.config.get_link_tag(obj, res)
- temp.append(res)
- data_list.append(temp)
- # print('data_list', data_list)
- """
- 我们最终得到的数据类型是如下格式:列表套着列表
- [
- 使用orm语句得到的每一个类对象,有几个表格就有几个对象
- ]
- list_display=['id','title',]
- [
- [1,'python',<a>编辑</a>],
- [2,'java',<a>编辑</a>],
- ]
- """
- return data_list
- class ModelSubject(object):
- """
- 我们在这里模拟admin源码里面的ModelAdmin,
- """
- list_display = ["__str__"] # 我们在这里给空列表里面加上"__str__",它就相当于是一个默认值,
- model_form_class = None # 为下面我们判断用户是否有自定义ModelForm校验方式而做铺垫
- search_fields = []
- list_display_links = [] # 为我们后面用户是否有自定义可跳转字段做铺垫
- # 就像我们的函数里面有默认值的参数一样,如果有传参就使用我们的自定义传参,如果没有传参就使用我们默认的参数也就是这个字符串,
- # 这里是为了给我们后面的代码做铺垫,我们的目的是在我们的数据展示页面里面默认就会把复选框和编辑还有删除按钮都加上,
- # 在这里把空列表里面添加上一个默认的字符串,是为了我们后面往该列表里面添加默认固定数据也就是复选框和编辑删除按钮做铺垫
- actions = []
- list_filter = [] # 多级过滤
- # 静态内置方法
- def __init__(self, model, site):
- self.model = model # 当我们生成一个实例化对象的时候需要把model这个参数传进来,
- # 必须要传,它是位置参数,然后我们所传入的那个model就是我们在models.py里面定义的每一个表名也就是类名
- self.site = site
- self.namespace = '{}_{}'.format(self.model._meta.app_label, self.model._meta.model_name)
- # self.app_model_name = (self.model._meta.app_label, self.model._meta.model_name) # 这里写得跟上面一句是一样的效果,
- # 这里调用的时候需要有两个%s,因为这里是一个元祖,而我们上面的namespace是一个字符串,不是一个元祖,所以只需要一个%s即可,调用的时候就这点区别
- # 我们这里的namespace是因为会频繁使用到所以就把它作为一个内置静态属性写入到这里,其他地方如果要调用它就直接使用self.namespace即可
- # .format的方法:'{}_{}'.format(a,b)
- # 默认actions批量删除
- def patch_delete(self, queryset):
- queryset.delete()
- return None
- patch_delete.desc = '批量删除'
- # 获取真正展示的actions
- def get_actions(self):
- temp = []
- temp.extend(self.actions) # [patch_init,patch_delete]
- temp.append(ModelSubject.patch_delete)
- return temp
- # 获取展示页面的url
- def get_stand_url(self):
- stand_url = reverse('%s_standlist' % self.namespace)
- return stand_url
- # 获取编辑页面的url
- def get_edit_url(self, obj):
- edit_url = reverse('%s_edit' % self.namespace, args=(obj.pk,))
- return edit_url
- # 获取删除页面的url
- def get_dele_url(self, obj):
- dele_url = reverse('%s_dele' % self.namespace, args=(obj.pk,))
- return dele_url
- # 获取增加页面的url
- def get_add_url(self):
- add_url = reverse('%s_add' % self.namespace)
- return add_url
- # 展示页面默认附带的编辑按钮
- def edit(self, obj=None, is_header=False):
- if is_header:
- return '操作'
- return mark_safe('<a href="%s">编辑</a>' % reverse('%s_edit' % self.namespace, args=(obj.pk,)))
- # 展示页面默认附带的删除按钮
- def dele(self, obj=None, is_header=False):
- if is_header:
- return '删除'
- return mark_safe("<a href='%s'>删除</a>" % reverse('%s_dele' % self.namespace, args=(obj.pk,)))
- # 展示页面附带的默认复选框
- def checkbox(self, obj=None, is_header=False):
- if is_header:
- return mark_safe("<input id='action-toggle' type='checkbox'>")
- return mark_safe("<input type='checkbox' value='%s' name='_selected_action'>" % obj.pk)
- # 展示页面默认显示按钮被存放的列表
- def get_list_display(self):
- new_li = []
- new_li.extend(self.list_display) # 我们这里的extend是把它后面的列表里面的数据都取出来放到我们自己的这个列表里面来
- if not self.list_display_links:
- new_li.append(ModelSubject.edit) # &&& 跟如下同样特征的代码块相呼应我们在这里使用类名去调用函数名,得到的是一个函数的方法,
- # 函数如果有参数是需要我们传参数的;但是我们如果使用self去调用的话,self就是实例化出来的对象,
- # 而我们的对象去调用函数方法的时候就不需要去传自己了也就是self,
- new_li.append(ModelSubject.dele)
- new_li.insert(0, ModelSubject.checkbox) # 把checkbox放到第一个位置,使用insert插入到索引为0
- """
- # @@@ 跟下面特殊标识的代码块相呼应
- new_li.append(self.edit)
- new_li.append(self.dele)
- new_li.insert(0,self.checkbox)
- """
- return new_li
- # 模糊查询
- def get_search_condition(self):
- from django.db.models import Q
- search_condition = Q()
- search_condition.connector = 'or'
- if self.search_fields: # 如果用户有自定义的查询字段,我们就走这个if下面的代码,
- key_word = self.request.GET.get('q') # 取出用户输入的input里面的值,
- if key_word:
- for search_field in self.search_fields: # 遍历用户自定义的查询字段列表,
- search_condition.children.append((search_field + "__contains", key_word))
- return search_condition
- # 处理用户自定义的link超链接字段标签,然后让超链接携带url键值对参数方法,供get_body使用
- def get_link_tag(self, obj, val):
- params = self.request.GET
- params = copy.deepcopy(params)
- params._mutable = True
- # from django.http import QueryDict
- # qqx = QueryDict(mutable=True)
- qqx = {} # 这里只写一行,等效于上面的两行,当然了前提是我们要引入urlencoded
- qqx['list_filter'] = params.urlencode()
- whh = mark_safe("<a href='{}?{}'>{}</a>".format(self.get_edit_url(obj), urlencode(qqx), val))
- return whh
- # 获取多级过滤的数据
- def get_filter_condition(self):
- from django.db.models import Q
- fiter_condition = Q()
- for field, val in self.request.GET.items():
- if field in self.list_filter:
- fiter_condition.children.append((field, val))
- return fiter_condition
- # 展示页面
- def stand_li(self, request):
- # print(self.model)
- # 所以我们在这里可以获取到当前的url里面的表名,然后直接使用orm语句即可得到当前表格的所有信息
- if request.method == 'POST':
- # print('request.POST.get', request.POST.get('action'))
- # print('request.POST.getlist', request.POST.getlist("_selected_action"))
- # 打印出来的结果是request.POST.getlist ['on', 'on'] 这个on是从何而来的,我的input里面的所有value值都设定的是obj.pk,
- # 这个obj.pk是有值的,
- # 为什么这里打印出来的getlist是两个on?我们的input标签上面有name值,
- # 然后我们使用request.POST.get后面的括号里面放的是name属性的值,然后它的返回值是我们的input标签里面的value值,
- # 都说了是value值,怎么还能加上s呢?简直愚蠢,
- pk_list = request.POST.getlist("_selected_action")
- queryset = self.model.objects.filter(pk__in=pk_list)
- func_name = request.POST.get("action")
- func = getattr(self, func_name)
- ret = func(queryset)
- self.request = request
- # 关于search的模糊查询
- search_condition = self.get_search_condition()
- # action
- # a=self.model.objects.all().count() # 这样就是可以获取我们的queryset集合的总数据长度,
- # 然后就可以用它去传给我们的分页组件,用它也可以,直接用count就能获取数据长度,或者是用len也行,我之前都是用len获取的
- # filter多级过滤,
- get_filter_condition = self.get_filter_condition()
- queryset = self.model.objects.filter(search_condition).filter(get_filter_condition)
- add_url = self.get_add_url()
- sl = StandLi(self, request, queryset) # 这里是把我们的StandLi这个类所需要的参数都传给它,然后通过StandLi实例化出来的一个对象
- # 然后在这里实例化出来一个对象我在这里调用那个对象就能够使用那个类里面的封装的方法了
- return render(request, 'file/hello.html', locals())
- # ModelForm校验添加和编辑页面
- def get_modelform_class(self):
- from django.forms import widgets
- class AllModelForm(ModelForm):
- class Meta:
- model = self.model
- fields = '__all__'
- if not self.model_form_class: # 这里的model_form_class在上面被定义了默认是None,
- # 我们的分发下去的App里面自定义的file文件里面注册model类的时候实例化出来的对象,在注册的时候传过来的这个变量
- return AllModelForm
- else:
- return self.model_form_class
- # ModelForm校验数据添加页面
- def add_view(self, request):
- FormClass = self.get_modelform_class()
- if request.method == 'GET':
- form = FormClass()
- return render(request, 'file/add.html', {'form': form})
- else:
- data_list = FormClass(data=request.POST)
- if data_list.is_valid():
- data_list.save()
- return redirect(self.get_stand_url())
- else:
- return render(request, 'file/add.html', {'form': data_list})
- # ModelForm校验数据编辑页面
- def edit_view(self, request, id):
- edit_list = self.model.objects.filter(pk=id).first()
- FormClass = self.get_modelform_class()
- if request.method == 'GET':
- data_list = FormClass(instance=edit_list)
- return render(request, 'file/edit.html', {'form': data_list})
- else:
- data_list = FormClass(data=request.POST, instance=edit_list)
- if data_list.is_valid():
- data_list.save()
- return redirect(self.get_stand_url())
- else:
- return render(request, 'file/edit.html', {'form': data_list})
- # 数据删除页面
- def dele_view(self, request, id):
- del_obj = self.model.objects.filter(pk=id).first()
- if request.method == 'GET':
- stand_url = self.get_stand_url()
- return render(request, 'file/dele.html', {'del_obj': del_obj, 'list_url': stand_url})
- else:
- del_obj.delete()
- return redirect(self.get_stand_url())
- # 获取url,此为第二次分发
- def get_urls(self):
- temp = []
- temp.append(url(r'^$', self.stand_li, name='%s_standlist' % self.namespace))
- temp.append(url(r'^(\d+)/dele/', self.dele_view, name='%s_dele' % self.namespace))
- temp.append(url(r'^(\d+)/edit/', self.edit_view, name='%s_edit' % self.namespace))
- temp.append(url(r'^add/', self.add_view, name='%s_add' % self.namespace))
- return temp
- @property
- def urls(self):
- return self.get_urls()
- class Stark(object):
- """
- 我们这里面的功能是可以跟上面的类写到一起去的,但是我们为了功能解耦,所以就分开写了,这里的主要功能就是
- 生成registry的字典,把键值对生成,然后我们最终的结果是要得到一个实例化对象,供我们后面的程序调用,这里的类才是主要的,核心的代码块
- 而我们上面的那个ModelSubject是辅助我们这里的功能,它之所以分发出去是为了便于扩展其他的功能,我们的自定义样式,
- 还有很多的方法和参数,就像我们的admin里面的ModelAdmin一样,长达1400多行代码,单独把它分离出去便于功能的扩展
- """
- def __init__(self):
- self._registry = {} # 这里是定义一个私有属性,就是为了避免被子类修改
- # 注册model表
- def register(self, model, model_config=None): # 我们是仿照着admin的源码写的组件,这里的model_config默认值是None,
- # 我们在传参的时候,如果给它传值,那么就使用我们传入的值替换掉这个None
- # 它的源码里面有这几个参数,我们也要按照顺序把这几个参数加进来
- if not model_config:
- model_config = ModelSubject # 我们这里的model_config我们上面的类ModelSubject实例化出来的对象,
- # 它是上面的类所实例化出来的对象,这一句写得明明白白的,这大白话再看不懂就真是白学了,
- self._registry[model] = model_config(model, self)
- # 获取url,第一次分发
- def get_urls(self):
- li = []
- for model, model_config in self._registry.items(): # 我们在这里所循环的model_config就是
- # 我们往上数第四行所实例化出来的那个model_config,它是上面的ModelSubject这个类所实例化出来对象,
- model_name = model._meta.model_name # 这里的._meta.model_name是获取字符串格式的类名,
- app_label = model._meta.app_label # 这里的._meta.app_labe获取的是字符串格式的App名,都是为了跟url做匹配,
- sli = url(r'%s%s/' % (app_label, model_name), (model_config.urls, None, None)) # 我们这里的model_config,
- # 它后面的.urls是在调用一个私有方法,我们的私有方法就是使用.urls来调用,不用加上括号,
- # 因为有@property这个装饰器在里面起到的作用,然后我们需要找到model_config这个实例对象是哪个类生成的,
- # 然后找到该类所拥有的方法,从里面找到urls,届时,那个urls就是我们在这里调用的那个urls了,
- # 所以关键的点就是我们的model_config,老师讲课的时候一再地强调过这个model_config从何而来,这个是关键,
- li.append(sli)
- return li
- # 我们最终的数据结构就是这样的,嵌套多层
- # [
- # url(
- # r'',(
- # [
- # (url(r'',views.add)),
- # (url(r'',views.edit)),
- # ],
- # none,none)
- # )
- # ]
- @property
- def urls(self):
- return self.get_urls(), None, None
- site = Stark()
tag.py
HTML模板渲染:
- <!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, initial-scale=1">
- <link rel="stylesheet" href="/static/plugins/bs/css/bootstrap.css">
- <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
- <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
- <title>Title</title>
- <style>
- .filter a {
- padding: 3px 6px;
- border: 1px solid #336699;
- color: white;
- background-color: pink;
- }
- .active {
- background-color: #336699 !important;
- color: white !important;
- }
- </style>
- </head>
- <body>
- <div class="jumbotron">
- <div class="container">
- <h1>数据展示</h1>
- <h2>code change the world</h2>
- </div>
- </div>
- <div class="container">
- <div class="row">
- <div class="col-md-8">
- <a href="{{ add_url }}">
- <button class="btn btn-primary" value="添加">添加数据</button>
- </a>
- {% if sl.config.search_fields %}
- <div class="pull-right form-group">
- <form action="" method="get" class="form-inline">
- <input type="text" class="form-control" name="q" value="">
- <input type="submit" class="btn btn-info" value="search">
- </form>
- </div>
- {% endif %}
- <form action="" method="post">
- {% csrf_token %}
- <div>
- <select class="form-control" name="action" id="" style="width:200px;margin:8px 2px;
- display:inline-block;vertical-align:-1px">
- <option value="">---------</option>
- {% for item in sl.handle_actions %}
- <option value="{{ item.name }}">{{ item.desc }}</option>
- {% endfor %}
- </select>
- <button type="submit" class="btn btn-primary">Go</button>
- </div>
- <table class="table table-stripped table-hover">
- <thead>
- <tr>
- {% for foo in sl.get_header %}
- <td>{{ foo }}</td>
- {% endfor %}
- </tr>
- </thead>
- <tbody>
- {% for data in sl.get_body %}
- <tr>
- {% for item in data %}
- <td>{{ item }}</td>
- {% endfor %}
- </tr>
- {% endfor %}
- </tbody>
- </table>
- </form>
- <div class="text-center">
- <nav aria-label="Page navigation">
- <ul class="pagination">
- {{ sl.pagination.page_html|safe }}
- </ul>
- </nav>
- </div>
- </div>
- <div class="col-md-3">
- <div class="filter">
- {% for filter_link_tag in sl.get_filter_link_tags %}
- <div class="well">{% for data in filter_link_tag %}
- <div>{{ data }}</div>
- {% endfor %}
- </div>
- {% endfor %}
- </div>
- </div>
- </div>
- </div>
- <script src="/static/js/hello.js">
- {# 我们的js代码里面需要注意单引号和双引号的区别,不能轻易改写,还有选择器,组合选择器之间需要空格#}
- </script>
- </body>
- </html>
前端HTML模板
静态文件:
- $("#action-toggle").click(function(){
- if($(this).prop("checked")){
- $("tbody :checkbox").prop("checked",true);
- }else{
- $("tbody :checkbox").prop("checked",false);
- }
- });
js代码
django-admin 仿写stark组件action,filter筛选过滤,search查询的更多相关文章
- day 69crm(6) stark组件 action 和 多层过滤效果
前情提要: 今天学的是stark 组件的 action 和多层过效果 一: action (自定制函数多选功能效果) 1: 学习 观点明确: 2: 多选效果前端和后端进行的操作 2& ...
- 自定义admin管理工具(stark组件)
自定义admin管理工具(stark组件) 创建项目 了解了admin的功能后,我们可以开始仿照admin编写我们自己的管理工具stark组件 首先创建一个新的项目,并创建三个app stark就是我 ...
- CRM系统之stark组件流程分析
CRM系统主要通过自定义stark组件来实现的(参照admin系统自定义): STARK组件: 1 admin组件 1 如何使用admin 2 admin源码 3 创建自己的admin组件:stark ...
- stark组件配置,二层URL
1.django的admin配置 2 stark组件开发 3.2层url分发 4.小结 1.django的admin配置 model.py from django.db import models # ...
- s111 stark组件
内容回顾: 1. 类当做key 2. django中的model所在app名称.以及小写类名. def index(request): # print(m1.UserInfo,m1.UserInfo. ...
- stark组件之批量操作【模仿Django的admin】
一.先看下django的admin是如何实现批量操作 首先在配置类中定义一个函数 然后我们为这个函数对象设置一个属性,这个属性主要用来显示在select标签中显示的文本内容 最后把函数对象放到一个ac ...
- stark组件之pop操作【模仿Django的admin】
一.先看下什么django的admin的pop到底是个什么东西 其实就是这么一个东西, a.在添加页面,在一对多和多对多的项后加了一个+号 b.点击这个加号,会弹出对应的添加 页面,在新的添加 c.添 ...
- stark组件之搜索【模仿Django的admin】
一.先看下django的admin是如何做搜索功能的 配置一个search_fields的列表就可以实现搜索的功能 class testbook(admin.ModelAdmin): # 第一步,定义 ...
- stark组件之路由分发【模仿Django的admin】
一.先看下django的admin是如何进行路由分发的 1.先看下django的admin的url路径有哪些 其实很简单,假如有一个书籍表,那么每张表对应四个url,增.删.改.查 查看的url ht ...
随机推荐
- bootstrap的treeview使用方法
首先引入文件: <link href="./css/bootstrap.css" rel="stylesheet"> <script src= ...
- Confluence 6 数据库支持的驱动
数据库 驱动已捆绑? JDBC 驱动 备注 更多信息 PostgreSQL 9.4-1202 JDBC 41 driver download 我们推荐你使用 JDBC 4 的驱动. 如果你希望使用更新 ...
- SpringData分页功能
在SpringData中实现分页功能我们需要将接口实现PagingAndSortingRepository这个接口提供了分页查询的方法 Page<T> findAll(Pageable p ...
- tp3.2 事务
public function exchangeTransfer($user_id, $type, $money, $config, $other_id = 0) { $r['code'] = ERR ...
- ural1018依赖背包-边权
其实用点权更简单,但这种做法是边权的 /* 依赖背包问题 dp[u][k]表示u结点往下共走k步的最大值 */ #include<iostream> #include<cstring ...
- C++ Primer 笔记——控制内存分配
1.当我们使用一条new表达式时,实际执行了三步操作. new表达式调用一个名为operator new ( 或者operator new[] ) 的标准库函数.该函数分配一块足够大的,原始的,未命名 ...
- Tomcat配置域名/IP访问及其中遇到的问题注意事项
1.先在tomcat下的conf下找到server.xml文件,用记事本打开后,首先对端口号进行修改,以前一直以为8080是默认的端口号,其实默认的端口号是80 <Connector port= ...
- js call() 笔记
var ctrl = function() {}; ctrl.view = function() { return { show: function() { console.log("vie ...
- 阿里云人脸识别测试接口出错 返回Body:{ "errno": 1031, "err_msg": "Invalid Image URL.", "request_id": "cdbe2927-e1bb-4eb1-a603-8fcd4b0b7fc8" }
错误信息如下 返回Body:{ "errno": 1031, "err_msg": "Invalid Image URL.", " ...
- tomcat安装出现的闪退问题
如果闪退 在该文件中结尾添加pause 可以检测到路径问题是不是有问题