页面搭建包括第一如何获取前端传过来的数据,第二如何在前端渲染出对应标签。

一、后台获取数据并进行处理

在路由系统中,每一个路由都对应着一个处理函数,如下所示:

  def wrapper(self, func):  # 将视图函数加上装饰器,这样可以在处理视图之前之后都可以加上一定的功能
@functools.wraps(func) # 保留原函数的信息
def inner(request, *args, **kwargs):
self.request = request # 将request传给当前对象,在处理视图函数之前
BaseRequestForm(request)
BaseRequestModelForm(request)
return func(request, *args, **kwargs) return inner def get_urls(self):
urlpatterns = [
re_path('list/$', self.wrapper(self.changelist_view), name=self.get_list_url_name ),
re_path('add/$', self.wrapper(self.add_view), name=self.get_add_url_name),
re_path('(?P<pk>\d+)/change/$', self.wrapper(self.change_view), name=self.get_edit_url_name),
re_path('(?P<pk>\d+)/del/$', self.wrapper(self.del_view), name=self.get_del_url_name), ]
extra_urls = self.extra_urls()

其中changelist_view()就是处理显示数据的函数,可以看到被装饰器包裹,其主要目的是为了在执行函数前,加入一些逻辑,列如将request赋值给stark_class,以及赋值给modelform和form,这在之后也是很有用处的。

在列表页要显示的功能目前有搜索,过滤,批量操作,分页等功能

    order_by = ['-id']
list_display = [] # 页面需要展示的字段
model_form_class = None
action_list = []
search_list = []
list_filter = []
list_editable= []
filter_horizontal=[]
has_add_btn=True

在这里需要构建一个分过页的queryset返回给前端进行渲染,在返回的queryset中是已经将search_list,list_filter,order_by过滤后的数据。

search_list条件的构建

...
search_list=[] def get_search_list(self): return self.search_list #######处理搜索功能############
def get_search_condition(self):
search_list = self.get_search_list()
q = self.request.GET.get('q', '') #前端name为q
con = Q()
con.connector = 'OR'
for field in search_list:
con.children.append(('%s__contains' % field, q))
return search_list, con, q
...

list_filter条件构建

...
list_filter = [] def get_list_filter(self): return self.list_filter def get_list_filter_condition(self):
comb_condition = {}
for option in self.get_list_filter():
filter_list = self.request.GET.getlist(option.field)
if filter_list:
comb_condition["%s__in" % option.field] = filter_list
"""
{
title:['a','b'],
}
"""
return comb_condition ...

在这里循环的是option对象,而不是像list_search一样循环取出字段名,因为,如果单纯的在list_filter中放入字段名,那么向choice字段这样的数据取出来的就不是需要的数据,就如同下面这样的。

为了解决choice显示的问题,所以不能单纯的添加字段,所以可以加入一些其它参数来解决,在这里可以添加对象,将数据封存到对象中,当然字典也是可以的。

    list_filter = [
Option('name',),
Option('status',text_func=lambda x:x[1],is_choice=True)
]

class Option(object):
"""
将传入的值进行封装,也就是现在list_filter列表中不是一个个字段而是一个个option对象
""" def __init__(self, field, condition=None, is_choice=False, text_func=None, value_func=None, is_multi=False):
self.field = field # 传递的字段
if not condition:
condition = {}
self.condition = condition # 传递的显示过滤条件
self.is_choice = is_choice
self.text_func = text_func # 中文
self.value_func = value_func
self.is_multi = is_multi # 是否支持多选搜索

这样在后台就可以获取到过滤条件的值comb_condition。

order_by条件的构建

    def get_order_by(self):

        return self.order_by

这样返回给前端的queryse基本就构建完毕了

 queryset = origin_queryset.filter(con).filter(**self.get_list_filter_condition()).order_by(
*self.get_order_by()).distinct()[page.start:page.end] # distinct是为了防止多对多字段中,is_multi=True出项重复数据

其中origin_queryset是预留的钩子函数,可以重写这个方法进行进一步的筛选。

...

######获取queryset对象,根据需求重新此方法进行筛选
def get_queryset(self,request,*args,**kwargs):
return self.model_class.objects origin_queryset=self.get_queryset(request,*args,**kwargs) ...

二、前端过滤功能url构建

上述过程主要是处理前端传过来的数据,但是这些传递过来的url都是怎么构建的呢?尤其是过滤功能,而且搜索过滤等功能都需要在原先url的基础上进行进一步的筛选,其本质就是url参数的变化,在这里首先介绍一个知识点就是django的QueryDict的应用。请求中知道request.GET以及request.POST得到的数据都是QueryDict类型,在urllib中字典形式可以转化为GET形式参数,django中也是可行的。

from urllib.parse import urlencode

url_dict={'name':'fg','age':34}

print(urlencode(url_dict))  #age=34&name=fg

通过一次GET请求,传入a=1&b=2参数

def query_dict(request):
query_dict=request.GET
print(query_dict)#<QueryDict: {'a': ['1'], 'b': ['2']}>
query_dict.copy()
query_dict._mutable = True
query_dict['name']='fg'
print(query_dict)#<QueryDict: {'a': ['1'], 'name': ['fg'], 'b': ['2']}>
print(query_dict.urlencode())#a=1&b=2&name=fg
return HttpResponse('...')

通过这种方式不仅可以构建url并且可以保留原先的搜索条件

这里主要说一下list_filter在页面上url的构建,首先将过滤 的数据从数据库中取出来,用于作为过滤条件。

    def list_filter_rows(self):
#####################组合搜索 可以通过yield返回一个个的RowQueryset对象#############
list_filter = self.stark_class.get_list_filter() # 获取对象列表['Option()','Option()']
for option in list_filter:
_field_obj = self.stark_class.model_class._meta.get_field(option.field) # 取到每一个字段对象
row_queryset = option.get_queryset(_field_obj, self.stark_class.model_class,
self.stark_class) # 取到数据库中对应的一行数据
yield row_queryset

循环list_filter得到每一个option对象,并且调用option类中get_queryset()方法,注意返回的是每一个字段对象对应的一行数据。

    def get_queryset(self, _field_obj, model_class, view_class):

        if isinstance(_field_obj, ForeignKey) or isinstance(_field_obj,ManyToManyField):  # 如果对应字段对象是Foreignkey类型,就取出另一张表中的数据
# row_queryset=_field_obj.remote_field.model.objects.filter(**self.condition) #rel如果不行就是用remote_field
row_queryset = RowQueryset(_field_obj.remote_field.model.objects.filter(**self.condition), self, view_class) # 传入self是因为需要用到option中的一些参数text_func
else:
if self.is_choice:
# row_queryset=_field_obj.choices
row_queryset = RowQueryset(_field_obj.choices, self, view_class)
else:
# row_queryset=model_class.objects.filter(**self.condition)
row_queryset = RowQueryset(model_class.objects.filter(**self.condition), self, view_class)
return row_queryset

在这里对每一个字段对象进行判断,ForeignKey、ManyToMany,choice还是普通的字段。并且将每一个字段对象的处理交给RowQueryset类进行处理。这里知道RoWQueryset类中接收的要不就是queryset的集合要不就是choice的元组对象,其次是option对象以及stark_class.。

class RowQueryset(object):

    def __init__(self, row_queryset, option, view_class):
""" :param row_queryset: 封装的row_queryset的数据
:param option: 每一个option对象
"""
self.row_queryset = row_queryset
self.option = option
self.view_class = view_class # 这是changeView类,里面封装了请求的request对象 def __iter__(self): # 为了循环这个对象,实现iter方法,iter返回的是什么,页面显示的就是什么 yield """<div class="whole">"""
##################生成全部选项的url############
total_query_dict = self.view_class.request.GET.copy() # 深拷贝一份
total_query_dict._mutable = True
origin_url_list = self.view_class.request.GET.getlist(self.option.field) # 获取所有GET的搜索参数[],['2'],['3']
if origin_url_list: # 请求中有值,就将自己字段去掉
total_query_dict.pop(self.option.field)
yield """<a href="?%s">全部</a>""" % total_query_dict.urlencode()
else:
yield """<a class="active" href="?%s">全部</a>""" % total_query_dict.urlencode()
yield """</div>"""
yield """<div class="others">""" for obj in self.row_queryset: # 循环得到的要不就是queryset中的对象,要不就是元组对象
query_dict = self.view_class.request.GET.copy() # 深拷贝一份
query_dict._mutable = True # 修改参数
if not self.option.is_multi: # 支持单选
query_dict[self.option.field] = self.option.get_value(obj) # 获取数据库中对应的值
val = self.option.get_value(obj) # 从数据库中取出值与之前请求作比较,看是否加入选中的样式
if str(val) in origin_url_list:
query_dict.pop(self.option.field) # 点击第二次后会移除自身
yield '<a class="active" href="?%s">%s</a>' % (
query_dict.urlencode(), self.option.get_text(obj)) # 引入text_func是为了解决choice,元组的问题
else:
yield '<a href="?%s">%s</a>' % (
query_dict.urlencode(), self.option.get_text(obj)) # 引入text_func是为了解决choice,元组的问题
else:
multi_value_list = self.view_class.request.GET.getlist(self.option.field) # 获取请求的所有搜索参数
val = self.option.get_value(obj)
if str(val) in origin_url_list:
multi_value_list.remove(str(val)) # 如果请求中已经存在就将其移除
query_dict.setlist(self.option.field, multi_value_list) # 将已经变化的参数重新设置到querydict中
yield '<a class="active" href="?%s">%s</a>' % (
query_dict.urlencode(), self.option.get_text(obj)) # 引入text_func是为了解决choice,元组的问题 else:
multi_value_list.append(val)
query_dict.setlist(self.option.field, multi_value_list)
yield '<a href="?%s">%s</a>' % (
query_dict.urlencode(), self.option.get_text(obj)) # 引入text_func是为了解决choice,元组的问题
yield """</div>"""

在前端页面上只需要循环这个对象就执行内部的__iter__()方法,拿到其执行的结果,从上面的代码可以看出来,基本就是从请求中取出参数值与数据库中取出的值做比较,如果存在就让前端的显示加上active选中的样式,并且将querydict赋值,在这里支持单选和多选的多选的道理与单选类似,只不过设置querydict的值略有不同而已。

        {% for row in cl.list_filter_rows %}<!--前端渲染list_filter-->
<div class="row">
{% for obj in row %}
{{ obj|safe }}
{% endfor %}
</div>
{% endfor %}

stark组件之显示页面搭建(四)的更多相关文章

  1. stark组件之显示页面内容搭建(六)

    之前主要介绍了前端页面list_fiter功能的显示,但是list_display功能的展示并没有过多介绍,这里介绍一下是如何实现的. 可以看到凡是蓝线圈起来的都是通过字段名反射一个个取出来的,红线的 ...

  2. stark组件之删除页面内容搭建(八)

    删除页面没有太多的内容和功能 def del_view(self, request,pk,*args,**kwargs): """ 处理删除表弟 :param reque ...

  3. stark组件之pop页面,按钮,url,页面

      1.Window open() 方法 2.admin的pop添加按钮 3.stark之pop功能 3.知识点总结 4.coding代码 1.Window open() 方法 效果图   2.adm ...

  4. 24.stark组件全部

    admin组件: 博客里面的图片的是在太难弄了,有大哥会弄给我贴一片博客,我一个一个加太累了,没有加 admin参考:https://www.cnblogs.com/yuanchenqi/articl ...

  5. stark组件开发之列表页面应用示例

    已经解决的,自定义的扩展函数,功能.但是 不可能返回. 一个 固定的页面把!  应该是,点击那条 记录之后的编辑, 就会跳转到相应的,编辑页面.所以 这个标签的  <a href="/ ...

  6. stark组件开发之列表页面定制列

    先看一张页面展示的效果图: 看一看我的  model 表!是什么样子: 看一看数据库是什么样子: 看 页面展示图,有表头. 有数据.模型表中,每一个字段, 都指定了 verbose_name. 如何解 ...

  7. 【技术博客】Flutter—使用网络请求的页面搭建流程、State生命周期、一些组件的应用

    Flutter-使用网络请求的页面搭建流程.State生命周期.一些组件的应用 使用网络请求的页面搭建流程 ​ 在开发APP时,我们常常会遇到如下场景:进入一个页面后,要先进行网络调用,然后使用调用返 ...

  8. 【django之stark组件】

    一.需求 仿照django的admin,开发自己的stark组件.实现类似数据库客户端的功能,对数据进行增删改查. 二.实现 1.在settings配置中分别注册这三个app # Applicatio ...

  9. django 之 stark组件

    ----------------------------------------------------------------烦恼没完没了,内心动荡不安,呜呼哀哉. 一.有个特殊的需求,需要用sta ...

随机推荐

  1. 【插件开发】—— 10 JFace开发详解

    前文回顾: 1 插件学习篇 2 简单的建立插件工程以及模型文件分析 3 利用扩展点,开发透视图 4 SWT编程须知 5 SWT简单控件的使用与布局搭配 6 SWT复杂空间与布局搭配 7 SWT布局详解 ...

  2. 安装MySQL需要注意的事项

    一.安装MySQL之后,怎样启动MySQL,以及登录.查看数据库操作? 用管理员身份运行cmd或power shell 二.当然有可能会出现不能在cmd或power shell中登录数据库账户 造成这 ...

  3. 网站SEO优化如何让百度搜索引擎绝的你的网站更有抓取和收录价值呢?_孙森SEO

    今天孙森SEO为大家唠唠网站到底该如何优化才会让百度搜索引擎绝的你的网站更有抓取和收录价值呢? 第一方面:网站创造高品质的内容,可以为用户提供独特的价值. 1.百度作为搜索引擎,网站内容必须满足 搜索 ...

  4. 安装privoxy后curl 操作

    如果讲privoxy服务关掉 sudo /etc/init.d/privoxy restart 这时候发现 curl www.baidu.com 也没法正常工作,直接显示的是无法连接到相应端口还是 主 ...

  5. (转载)Python一篇学会多线程

    Python 一篇学会多线程 链接:https://www.cnblogs.com/yeayee/p/4952022.html  多线程和多进程是什么自行google补脑,廖雪峰官网也有,但是不够简洁 ...

  6. [USACO 2011 Nov Gold] Cow Steeplechase【二分图】

    传送门:http://www.usaco.org/index.php?page=viewproblem2&cpid=93 很容易发现,这是一个二分图的模型.竖直线是X集,水平线是Y集,若某条竖 ...

  7. 员工管理系统(集合与IO流的结合使用 beta3.0 BufferedReader / ObjectOutputStream)

    Employee.java package cn.employee_io; public class Employee { private String empId; private String n ...

  8. css超出部分显示省略号

    单行文本 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  9. SQLServer 2012 高效分页

    SQLSERVER2012 出新分页功能啦!!!近两天我在自己工作机的PC(没有并发,单一线程)上做了SqlServer  2000/ (2005/2008)/2012三个版本下的分页性能比较. 大致 ...

  10. Java对象创建

    今天发现一个问题: 如果加上第一个输出,那么两个per1的对象是不一样的,如果不加,那么下一个输出的对象的是和第一个是一致的? 思考为什么???? 代码如下: package com.lgq.serv ...