添加功能在前面的编辑基础上继承,相对来说就简单太多,没有太多的修改。
1. 添加–创建页面
1.1 创建页面路由
1 urlpatterns = [ 2 url(r'^$', views.index, name='table_index'), 3 url(r'^(\w+)/(\w+)/$', views.display_objects, name='display_objects'), 4 url(r'^(\w+)/(\w+)/(\d+)/edit/$', views.table_object_edit,name="table_object_edit"), 5 url(r'^(\w+)/(\w+)/add/$', views.table_object_add,name="table_object_add"),#添加页面的路由 6 ]
1.2 创建页面模板文件
在templates/king_admin/
目录下创建模板文件:table_object_add.html
,并继承编辑文件内容:
1 {% extends 'king_admin/table_object_edit.html' %} 2 3 {% block top %} 4 <div class="panel-heading"> 5 <button class="btn btn-success pull-right" ><a href="{% url 'king_admin:display_objects' app_name table_name %}" style="color: white">返回</a></button> 6 </div> 7 {% endblock %}
上面的块内容包含的是返回键按钮。
1.3 创建页面视图函数
添加功能的视图函数和编辑页面基本上是大同小异:
1 def table_object_add(request, app_name, table_name): 2 admin_class = site.enabled_admins[app_name][table_name] 3 model_form = create_model_form(request, admin_class) 4 5 if request.method == 'POST': 6 form_object = model_form(request.POST) 7 if form_object.is_valid(): 8 form_object.save() 9 return redirect('/king_admin/{app_name}/{table_name}'.format(app_name = app_name, 10 table_name = table_name)) 11 else: 12 form_object = model_form() 13 14 return render(request, 'king_admin/table_object_add.html', {'admin_class': admin_class, 15 'form_object': form_object, 16 "app_name": app_name, 17 "table_name": table_name})
其中的redirect()
比较关键,添加后返回的url
。
这里有一个错误会产生,原因是动态form:model_form在实例化的时候是None,而我们的添加新数据页面是继承table_object_change.html页面的,该页面用到了form_object.instance方法,会报一下错误:
需要修改tags.py文件,
1 from django import template 2 from django.utils.safestring import mark_safe 3 from kingadmin.utils import filters_to_text 4 5 register = template.Library() 6 7 8 @register.simple_tag 9 def table_verbose_name(admin_class): 10 return admin_class.model._meta.verbose_name 11 12 13 @register.simple_tag 14 def create_page_num(contacts, ordering, _q, filter_text): 15 """ 16 返回分页按钮的html方式 17 :param contacts: Paginator.page(num) 18 :return: 19 """ 20 page_num_html = '' 21 dot_sign = False 22 for number in contacts.paginator.page_range: 23 btn_element = """<li class="{0}"><a href="?page={1}&o={2}&_q={3}&{4}">{5}</a></li>""" 24 li_class = '' 25 if number < 3 \ 26 or number > contacts.paginator.num_pages - 2 \ 27 or abs(number - contacts.number) <= 2: # 前三页,后2页,当前页的前后2页 28 if number == contacts.number: # 页码等于当前页 29 li_class = "active" 30 dot_sign = False 31 page_num_html += btn_element.format(li_class, number, ordering, _q, filter_text, number) 32 else: 33 if not dot_sign: 34 page_num_html += '<li><a>...</a></li>' 35 dot_sign = True 36 return mark_safe(page_num_html) 37 # for number in contacts.paginator.page_range: 38 # if number < 3 or number > contacts.paginator.num_pages - 2 or abs(contacts.number - number) <= 2: # 前两页或最后两页 #} 39 # if number == contacts.number: 40 # page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, number) 41 # dot_sign = False 42 # else: 43 # dot_sign = False 44 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 45 # elif contacts.paginator.num_pages < 7: # 总页数为6,直接显示页码 46 # dot_sign = False 47 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 48 # elif contacts.paginator.num_pages >= 7: # 7页以上 49 # temp = contacts.paginator.num_pages / 2 50 # if type(temp) is int: # 能整除,偶数页,显示中间四页 51 # if temp - 1 <= number <= temp + 2: # 中间四页 52 # if number == contacts.number: # 判断当前页 53 # page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, 54 # number) 55 # dot_sign = False 56 # else: 57 # dot_sign = False 58 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 59 # else: # 非中间四页 60 # page_num_html += """<li><a href="#">...</a></li>""" 61 # else: # 不能整除,奇数页,显示中间三页 62 # if int(temp) <= number <= temp + 2: # 中间三页 63 # if number == contacts.number: 64 # page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, 65 # number) 66 # dot_sign = False 67 # else: 68 # dot_sign = False 69 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 70 # else: # 非中间三页 71 # if not dot_sign: 72 # page_num_html += """<li><a href="#">...</a></li>""" 73 # dot_sign = True 74 # return mark_safe(page_num_html) 75 76 77 @register.simple_tag 78 def field_verbose_name(filter_condition, admin_class, filter_conditions_customer): 79 """ 80 返回表中的字段的verbose_name,取代英文 81 :param filter_condition: string 82 :param admin_class: class 83 :return: 84 """ 85 if hasattr(admin_class.model, filter_condition): 86 field_class = admin_class.model._meta.get_field(filter_condition) 87 name = field_class.verbose_name 88 choices = field_class.choices 89 selected_value = '' 90 label_html = """<label for={0}>{1}</label>""".format(field_class.name, name) # label content 91 select_html = """<select class="form-control" id="{0}" name="{1}">""".format(field_class.name, field_class.name) 92 # '<option>1</option></select>' # select content 93 94 # selected 95 if field_class.name in filter_conditions_customer: 96 selected_value = filter_conditions_customer[field_class.name] 97 98 if choices or type(field_class).__name__ == 'ForeignKey': # 外键 99 for item in field_class.get_choices(): 100 if str(item[0]) == selected_value: 101 select_html += """<option value={0} selected>{1}</option>""".format(item[0], item[1]) 102 else: 103 select_html += """<option value={0}>{1}</option>""".format(item[0], item[1]) 104 select_html += '</select>' 105 group_html = label_html + select_html 106 107 return mark_safe(group_html) 108 else: 109 return 'there is no %s' % filter_condition 110 111 112 @register.simple_tag 113 def ret_field_value(request, query_set, fields_name, page, order, filter_conditions_customer, search_text): 114 """ 115 返回admin_class中list_display包含字段对应的一行数据,并组装成html格式 116 :param request: 117 :param query_set: class instanceme 118 :param fields_name: 119 :param page: 120 :param order: 121 :param filter_conditions_customer: 122 :param search_text: 123 :return: 124 """ 125 row_data = '' 126 filter_text = filters_to_text(filter_conditions_customer) 127 for k, field_name in enumerate(fields_name): 128 # options的数据类型如下: 129 # ((0, '转介绍'), 130 # (1, 'QQ群'), 131 # (2, '官网'), 132 # (3, '百度推广'), 133 # (4, '51CTO'), 134 # (5, '知乎'), 135 # (6, '市场部推广')) 136 # """<th><span><input type="checkbox"></span></th>""" 137 field_type = query_set._meta.get_field(field_name) 138 options = field_type.choices 139 option_value = getattr(query_set, field_name) 140 if options: # 处理多选字段,即choices属性不为空 141 option_means = [item for item in options if item[0] == option_value][0][1] 142 unit_data = '<td>{0}</td>'.format(option_means) 143 elif type(option_value).__name__ == 'datetime': # 处理时间格式 144 option_value = option_value.strftime("%Y-%m-%d %H:%M:%S") 145 unit_data = '<td>{0}</td>'.format(option_value) 146 elif k == 0: 147 unit_data = '<td><a href="{0}/{1}/edit?page={2}&o={3}&_q={4}&{5}">{6}</a></td>'.format( 148 request.path, 149 query_set.id, 150 page, 151 order, 152 search_text, 153 filter_text, 154 option_value, 155 ) 156 elif type(field_type).__name__ == 'ManyToManyField': # 处理多对多字段 157 field_values = getattr(query_set, field_name).all() 158 temp = '' 159 for k, v in enumerate(field_values): 160 temp += v.name + ',' 161 temp = temp.rstrip(',') 162 unit_data = '<td>{0}</td>'.format(temp) 163 else: 164 unit_data = '<td>{0}</td>'.format(option_value) 165 row_data += unit_data 166 row_data = '<tr><td><span><input type="checkbox" tag="object_checkbox" value="{0}"></span></td>{1}</tr>'.format( 167 query_set.id, 168 row_data 169 ) 170 return mark_safe(row_data) 171 172 173 @register.simple_tag 174 def ret_getattr(query_set, field_name): 175 return hasattr(query_set, field_name) 176 177 178 @register.simple_tag 179 def create_row(query_set_obj, admin_class): 180 element = '' 181 for row in admin_class.list_display: 182 183 field_obj = admin_class.model._meta.get_field(row) 184 if field_obj.choices: 185 row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))() 186 else: 187 row_data = getattr(query_set_obj, row) 188 if type(row_data).__name__ == 'datetime': 189 row_data = row_data.strftime('%Y-%m-%d %H:%M:%S') 190 191 element += "<td>{0}</td>".format(row_data) 192 return mark_safe(element) 193 194 195 @register.simple_tag 196 def create_page_element(page, filter_conditions): 197 page_btns = '' 198 filters = '' 199 for k, v in filter_conditions.items(): 200 filters += '&{0}={1}'.format(k, v) 201 add_dot_ele = False # 标志符 202 for page_num in page.paginator.page_range: # query_set.paginator.page_range: range(1,n),分的总页数, 203 # page_num:每页的页码 204 # query_set.paginator.num_pages: 一共分了多少页 205 # query_set.number: 页对应的页码 206 if page_num < 3 or \ 207 page_num > page.paginator.num_pages - 2 or \ 208 abs(page.number - page_num) <= 2: # 代表最前2页或最后2页 #abs判断前后1页 209 element_class = "" 210 if page.number == page_num: 211 add_dot_ele = False 212 element_class = "active" 213 page_btns += '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' % (element_class, 214 page_num, 215 filters, 216 page_num) 217 else: 218 if not add_dot_ele: 219 page_btns += '<li><a href="#">...</a></li>' 220 add_dot_ele = True 221 222 return mark_safe(page_btns) 223 224 225 @register.simple_tag 226 def render_filter_element(condition, admin_class, filter_conditions): 227 ''' 228 229 :param condition: 字符串, list_filter中的一个 230 :param admin_class: 数据库中的数据表类 231 :param filter_conditions: 字典,key=list_filter中的一个, value=前端传回的对应的option的value值 232 :return: 233 ''' 234 # 初始化下拉框 235 select_element = """<select class='form-control' name={0}><option value=''>------ 236 </option>""".format(condition) 237 field_object = admin_class.model._meta.get_field(condition) # 获取字段, admin_class中的字段 238 # 字段处理, 默认不选中 239 selected = '' # choice处理 240 if field_object.choices: # 遍历choices值 241 for choice_item in field_object.get_choices()[1:]: 242 # print(choice_item) 243 # 判断选择条件是否和choice值相等, 244 if filter_conditions.get(condition) == str(choice_item[0]): 245 # 被选中 246 selected = 'selected' 247 select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0], 248 selected, choice_item[1]) 249 selected = '' 250 # 外键处理 251 if type(field_object).__name__ == 'ForeignKey': 252 for choice_item in field_object.get_choices()[1:]: 253 # 判断选择条件是否和choice值相等 254 if filter_conditions.get(condition) == str(choice_item[0]): 255 # 被选中 256 selected = 'selected' 257 select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0], 258 selected, choice_item[1]) 259 selected = '' 260 select_element += '</select>' 261 return mark_safe(select_element) 262 263 264 @register.simple_tag 265 def ret_search_help(admin_class): 266 help_info = '' 267 if admin_class.search_fields: 268 # help_info += '搜索:' 269 for item in admin_class.search_fields: 270 help_info += item + '、' 271 else: 272 help_info += '未定义搜索字段' 273 274 return help_info 275 276 277 @register.simple_tag 278 def create_table_title(fields, order_after, filter_conditions_customer, search_text): 279 """ 280 281 :param fields: 282 :param order_after: 283 :param filter_conditions_customer: 284 :return: 285 """ 286 # """<th><span><input type="checkbox"></span>""" 287 # """<a href="?o={{ field.name }} style="display:block;font-size:14px;">{{ field.verbose_name }}</a>""" 288 # 添加一列checkbox 289 ele_checkbox = """<th><span><input type="checkbox" id="test" οnclick="select_all_checkbox(this);"></span></th>""" 290 # filter_text 291 filter_text = '' 292 for k, v in filter_conditions_customer.items(): 293 temp = k + '=' + v 294 filter_text += temp + '&' 295 filter_text = filter_text.rstrip('&') 296 # 添加title 297 ele_title = '' 298 # 设置标题的href 299 for field in fields: 300 temp = order_after.lstrip('-') 301 if temp == field.name: 302 ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format( 303 filter_text, 304 order_after, 305 search_text, 306 field.verbose_name 307 ) 308 else: 309 ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format( 310 filter_text, 311 field.name, 312 search_text, 313 field.verbose_name 314 ) 315 table_title = ele_checkbox + ele_title 316 return mark_safe(table_title) 317 318 319 @register.simple_tag 320 def get_horizontal_tag_values(field, admin_class, form_object): 321 field_obj = getattr(admin_class.model, field.name) 322 query_sets_all = field_obj.rel.to.objects.all() 323 try: # 在添加页面时,form_object是空实例,获取tags字段数据的时候会报错 324 instance_field = getattr(form_object.instance, field.name) 325 except ValueError as e: 326 print(e) 327 return query_sets_all 328 else: 329 query_sets_select = instance_field.all() 330 diff_query_sets = query_sets_all.difference(query_sets_select) 331 return diff_query_sets 332 333 334 @register.simple_tag 335 def get_horizontal_field_value(field, form_object): 336 try: # 在添加页面时,form_object是空实例,获取tags字段数据的时候会报错 337 field_obj = getattr(form_object.instance, field.name) 338 except ValueError as e: 339 print(e) 340 return None 341 else: 342 selected_list = field_obj.all() 343 return selected_list
后台打印的错误信息如下:
/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6 /Users/pp/Documents/workplace/pycharm/51cto/ProjectCRM/manage.py runserver 8000
Performing system checks...
System check identified no issues (0 silenced).
January 27, 2018 - 00:49:49
Django version 1.11.7, using settings 'ProjectCRM.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
"<CustomerInfo: QQ: -- Name:None>" needs to have a value for field "id" before this many-to-many relationship can be used.
"<CustomerInfo: QQ: -- Name:None>" needs to have a value for field "id" before this many-to-many relationship can be used.
[27/Jan/2018 00:49:57] "GET /kingadmin/CRM/customerinfo/add HTTP/1.1" 200 15589
这个暂时没有想到更好的解决办法,只能先通过这种方式进行解决。
如果有更好的方法,后续进行更新,有知道的也可以指点一下,非常感谢。
最后效果如下:
讨论:
其实在这个添加页面还有个问题没有解决:从table_list.html(列出所有表中的数据)跳转到table_object_add.html过程中,页码、检索、排序、搜索等自定义操作的数据没有一起传递,当数据添加完成后,再返回的时候这些数据是丢失掉的,如果想要完整返回添加前的状态,需要将这些数据一起传递。
这里的矛盾是其实添加页面根本用不到这些数据,而且地址栏中的过多参数会导致一些url地址过长,很多参数也是暴露出来的,如何解决简单、有效的解决这两个问题?!
解决思路:
1.通过http协议头中的refer字段。
request.MEAT.keys()共有以下字段:
1 dict_keys(['PATH', 'PYTHONPATH', 'SHELL', 'LSCOLORS', 'PYTHONIOENCODING',
'SECURITYSESSIONID', 'CLICOLOR', 'USER', 'TMPDIR', 'SSH_AUTH_SOCK', 'DJANGO_SETTINGS_MODULE',
'XPC_FLAGS', 'PYTHONUNBUFFERED', '__CF_USER_TEXT_ENCODING', 'Apple_PubSub_Socket_Render',
'LS_OPTIONS', 'LOGNAME', 'LC_CTYPE', 'XPC_SERVICE_NAME', 'PWD', 'PYCHARM_HOSTED', 'HOME',
'PYCHARM_MATPLOTLIB_PORT', '__PYVENV_LAUNCHER__', 'TZ', 'RUN_MAIN', 'SERVER_NAME',
'GATEWAY_INTERFACE', 'SERVER_PORT', 'REMOTE_HOST', 'CONTENT_LENGTH', 'SCRIPT_NAME',
'SERVER_PROTOCOL', 'SERVER_SOFTWARE', 'REQUEST_METHOD', 'PATH_INFO', 'QUERY_STRING',
'REMOTE_ADDR', 'CONTENT_TYPE', 'HTTP_HOST', 'HTTP_CONNECTION', 'HTTP_UPGRADE_INSECURE_REQUESTS',
'HTTP_USER_AGENT', 'HTTP_ACCEPT', 'HTTP_REFERER', 'HTTP_ACCEPT_ENCODING', 'HTTP_ACCEPT_LANGUAGE',
'HTTP_COOKIE', 'wsgi.input', 'wsgi.errors', 'wsgi.version', 'wsgi.run_once', 'wsgi.url_scheme',
'wsgi.multithread', 'wsgi.multiprocess', 'wsgi.file_wrapper', 'CSRF_COOKIE'])
很多头部都是http协议头,其中HTTP_REFERER就是我们要的,但是这个字段会带来另外一个问题,当你保存的时候,其实
是以POST方式提交给http://127.0.0.1:8000/kingadmin/CRM/customerinfo/add页面,HTTP_REFERER字段变成了
http://127.0.0.1:8000/kingadmin/CRM/customerinfo/add,而不是http://127.0.0.1:8000/kingadmin/CRM/customerinfo?&o=id&_q=,
而且有时,刷新add页面或者输入的信息有误的时候,都是重复提交到add页面,都会引起HTTP_REFERER值得改变,所以通过这种方法不是明智之举。
需要解决将第一次的HTTP_REFERER字段保存到全局变量中,以区分后面的访问造成的HTTP_REFERER值变动。
2. 将这些特定字段信息埋在前端页面table_list.html中,即“添加”这个超级链接中。
具体做法如下:
埋标签
1 {% extends 'project/head.html' %} 2 {% load tags %} 3 {% block main %} 4 5 <div class="container"> 6 <div class="row"> 7 <div class="panel panel-info"> 8 <!-- Default panel contents --> 9 <div class="panel-heading"> 10 <span>{{ table_name }}</span> 11 <a href="{% ret_add_url request page order_before filter_text search_text %}" class="pull-right">添加</a> 12 </div> 13 <div class="panel-body"> 14 <form class="form-inline" action="{% url 'table_list' app_name table_name %}" 15 method="GET"> 16 {# 检索 #} 17 <div class="form-group col-lg-9"> 18 {% for filter_condition in filter_conditions %} 19 {% field_verbose_name filter_condition admin_class filter_conditions_customer %} 20 {% endfor %} 21 <button type="submit" class="btn-success btn-xs">检索</button> 22 </div> 23 {# 搜索 #} 24 <div class="form-group"> 25 <div class="input-group"> 26 <input type="search" class="form-control" 27 placeholder="{% ret_search_help admin_class %}" name="_q" 28 value="{{ search_text }}" maxlength="100"> 29 <span class="input-group-btn"> 30 <button class="btn-success btn-xs" type="submit">搜索</button> 31 </span> 32 </div> 33 </div> 34 </form> 35 </div> 36 <!-- Table 数据展示 --> 37 <table class="table table-hover"> 38 <thead> 39 <tr> 40 {% create_table_title fields order_after filter_conditions_customer search_text %} 41 </tr> 42 </thead> 43 <tbody> 44 {% for query_set in contacts %} 45 {% ret_field_value request query_set admin_class.list_display page order_before filter_conditions_customer search_text %} 46 {% endfor %} 47 </tbody> 48 </table> 49 {# 分页功能 #} 50 <div class="panel-footer"> 51 <nav aria-label="..."> 52 <ul class="pagination"> 53 {# 上一页 #} 54 {% if contacts.has_previous %} 55 <li> 56 <a href="?page={{ contacts.previous_page_number }}&o={{ order_before }}" 57 aria-label="Previous"> 58 <span aria-hidden="true">上一页</span> 59 </a> 60 </li> 61 {% else %} 62 <li class="disabled"> 63 <a href="?page={{ contacts.number }}&o={{ order_before }}&_q={{ search_text }}&{{ filter_text }}" aria-label="Previous"> 64 <span aria-hidden="true">上一页</span> 65 </a> 66 </li> 67 {% endif %} 68 {# 页码 #} 69 {% create_page_num contacts order_before search_text filter_text %} 70 {# 下一页 #} 71 {% if contacts.has_next %} 72 <li> 73 <a href="?page={{ contacts.next_page_number }}&o={{ order_before }}&_q={{ search_text }}&{{ filter_text }}" 74 aria-label="Next"> 75 <span aria-hidden="true">下一页</span></a> 76 </li> 77 {% else %} 78 <li class="disabled"> 79 <a href="?page={{ contacts.number }}&o={{ order_before }}&_q={{ search_text }}&{{ filter_text }}" aria-label="Next"> 80 <span aria-hidden="true">下一页</span></a> 81 </li> 82 {% endif %} 83 <span id="data_sum"> 84 总计:{{ contacts.paginator.count }} 85 </span> 86 </ul> 87 </nav> 88 </div> 89 </div> 90 </div> 91 </div> 92 {{ error }} 93 {% endblock %}
后端处理
1 from django import template 2 from django.utils.safestring import mark_safe 3 from kingadmin.utils import filters_to_text 4 5 register = template.Library() 6 7 8 @register.simple_tag 9 def table_verbose_name(admin_class): 10 return admin_class.model._meta.verbose_name 11 12 13 @register.simple_tag 14 def create_page_num(contacts, ordering, _q, filter_text): 15 """ 16 返回分页按钮的html方式 17 :param contacts: Paginator.page(num) 18 :return: 19 """ 20 page_num_html = '' 21 dot_sign = False 22 for number in contacts.paginator.page_range: 23 btn_element = """<li class="{0}"><a href="?page={1}&o={2}&_q={3}&{4}">{5}</a></li>""" 24 li_class = '' 25 if number < 3 \ 26 or number > contacts.paginator.num_pages - 2 \ 27 or abs(number - contacts.number) <= 2: # 前三页,后2页,当前页的前后2页 28 if number == contacts.number: # 页码等于当前页 29 li_class = "active" 30 dot_sign = False 31 page_num_html += btn_element.format(li_class, number, ordering, _q, filter_text, number) 32 else: 33 if not dot_sign: 34 page_num_html += '<li><a>...</a></li>' 35 dot_sign = True 36 return mark_safe(page_num_html) 37 # for number in contacts.paginator.page_range: 38 # if number < 3 or number > contacts.paginator.num_pages - 2 or abs(contacts.number - number) <= 2: # 前两页或最后两页 #} 39 # if number == contacts.number: 40 # page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, number) 41 # dot_sign = False 42 # else: 43 # dot_sign = False 44 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 45 # elif contacts.paginator.num_pages < 7: # 总页数为6,直接显示页码 46 # dot_sign = False 47 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 48 # elif contacts.paginator.num_pages >= 7: # 7页以上 49 # temp = contacts.paginator.num_pages / 2 50 # if type(temp) is int: # 能整除,偶数页,显示中间四页 51 # if temp - 1 <= number <= temp + 2: # 中间四页 52 # if number == contacts.number: # 判断当前页 53 # page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, 54 # number) 55 # dot_sign = False 56 # else: 57 # dot_sign = False 58 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 59 # else: # 非中间四页 60 # page_num_html += """<li><a href="#">...</a></li>""" 61 # else: # 不能整除,奇数页,显示中间三页 62 # if int(temp) <= number <= temp + 2: # 中间三页 63 # if number == contacts.number: 64 # page_num_html += """<li class ="active"><a href="?page={0}">{1}</a></li>""".format(number, 65 # number) 66 # dot_sign = False 67 # else: 68 # dot_sign = False 69 # page_num_html += """<li><a href="?page={0}">{1}</a></li>""".format(number, number) 70 # else: # 非中间三页 71 # if not dot_sign: 72 # page_num_html += """<li><a href="#">...</a></li>""" 73 # dot_sign = True 74 # return mark_safe(page_num_html) 75 76 77 @register.simple_tag 78 def field_verbose_name(filter_condition, admin_class, filter_conditions_customer): 79 """ 80 返回表中的字段的verbose_name,取代英文 81 :param filter_condition: string 82 :param admin_class: class 83 :return: 84 """ 85 if hasattr(admin_class.model, filter_condition): 86 field_class = admin_class.model._meta.get_field(filter_condition) 87 name = field_class.verbose_name 88 choices = field_class.choices 89 selected_value = '' 90 label_html = """<label for={0}>{1}</label>""".format(field_class.name, name) # label content 91 select_html = """<select class="form-control" id="{0}" name="{1}">""".format(field_class.name, field_class.name) 92 # '<option>1</option></select>' # select content 93 94 # selected 95 if field_class.name in filter_conditions_customer: 96 selected_value = filter_conditions_customer[field_class.name] 97 98 if choices or type(field_class).__name__ == 'ForeignKey': # 外键 99 for item in field_class.get_choices(): 100 if str(item[0]) == selected_value: 101 select_html += """<option value={0} selected>{1}</option>""".format(item[0], item[1]) 102 else: 103 select_html += """<option value={0}>{1}</option>""".format(item[0], item[1]) 104 select_html += '</select>' 105 group_html = label_html + select_html 106 107 return mark_safe(group_html) 108 else: 109 return 'there is no %s' % filter_condition 110 111 112 @register.simple_tag 113 def ret_field_value(request, query_set, fields_name, page, order, filter_conditions_customer, search_text): 114 """ 115 返回admin_class中list_display包含字段对应的一行数据,并组装成html格式 116 :param request: 117 :param query_set: class instanceme 118 :param fields_name: 119 :param page: 120 :param order: 121 :param filter_conditions_customer: 122 :param search_text: 123 :return: 124 """ 125 row_data = '' 126 filter_text = filters_to_text(filter_conditions_customer) 127 for k, field_name in enumerate(fields_name): 128 # options的数据类型如下: 129 # ((0, '转介绍'), 130 # (1, 'QQ群'), 131 # (2, '官网'), 132 # (3, '百度推广'), 133 # (4, '51CTO'), 134 # (5, '知乎'), 135 # (6, '市场部推广')) 136 # """<th><span><input type="checkbox"></span></th>""" 137 field_type = query_set._meta.get_field(field_name) 138 options = field_type.choices 139 option_value = getattr(query_set, field_name) 140 if options: # 处理多选字段,即choices属性不为空 141 option_means = [item for item in options if item[0] == option_value][0][1] 142 unit_data = '<td>{0}</td>'.format(option_means) 143 elif type(option_value).__name__ == 'datetime': # 处理时间格式 144 option_value = option_value.strftime("%Y-%m-%d %H:%M:%S") 145 unit_data = '<td>{0}</td>'.format(option_value) 146 elif k == 0: 147 unit_data = '<td><a href="{0}/{1}/edit?page={2}&o={3}&_q={4}&{5}">{6}</a></td>'.format( 148 request.path, 149 query_set.id, 150 page, 151 order, 152 search_text, 153 filter_text, 154 option_value, 155 ) 156 elif type(field_type).__name__ == 'ManyToManyField': # 处理多对多字段 157 field_values = getattr(query_set, field_name).all() 158 temp = '' 159 for k, v in enumerate(field_values): 160 temp += v.name + ',' 161 temp = temp.rstrip(',') 162 unit_data = '<td>{0}</td>'.format(temp) 163 else: 164 unit_data = '<td>{0}</td>'.format(option_value) 165 row_data += unit_data 166 row_data = '<tr><td><span><input type="checkbox" tag="object_checkbox" value="{0}"></span></td>{1}</tr>'.format( 167 query_set.id, 168 row_data 169 ) 170 return mark_safe(row_data) 171 172 173 @register.simple_tag 174 def ret_getattr(query_set, field_name): 175 return hasattr(query_set, field_name) 176 177 178 @register.simple_tag 179 def create_row(query_set_obj, admin_class): 180 element = '' 181 for row in admin_class.list_display: 182 183 field_obj = admin_class.model._meta.get_field(row) 184 if field_obj.choices: 185 row_data = getattr(query_set_obj, 'get_{0}_display'.format(row))() 186 else: 187 row_data = getattr(query_set_obj, row) 188 if type(row_data).__name__ == 'datetime': 189 row_data = row_data.strftime('%Y-%m-%d %H:%M:%S') 190 191 element += "<td>{0}</td>".format(row_data) 192 return mark_safe(element) 193 194 195 @register.simple_tag 196 def create_page_element(page, filter_conditions): 197 page_btns = '' 198 filters = '' 199 for k, v in filter_conditions.items(): 200 filters += '&{0}={1}'.format(k, v) 201 add_dot_ele = False # 标志符 202 for page_num in page.paginator.page_range: # query_set.paginator.page_range: range(1,n),分的总页数, 203 # page_num:每页的页码 204 # query_set.paginator.num_pages: 一共分了多少页 205 # query_set.number: 页对应的页码 206 if page_num < 3 or \ 207 page_num > page.paginator.num_pages - 2 or \ 208 abs(page.number - page_num) <= 2: # 代表最前2页或最后2页 #abs判断前后1页 209 element_class = "" 210 if page.number == page_num: 211 add_dot_ele = False 212 element_class = "active" 213 page_btns += '''<li class="%s"><a href="?page=%s%s">%s</a></li>''' % (element_class, 214 page_num, 215 filters, 216 page_num) 217 else: 218 if not add_dot_ele: 219 page_btns += '<li><a href="#">...</a></li>' 220 add_dot_ele = True 221 222 return mark_safe(page_btns) 223 224 225 @register.simple_tag 226 def render_filter_element(condition, admin_class, filter_conditions): 227 ''' 228 229 :param condition: 字符串, list_filter中的一个 230 :param admin_class: 数据库中的数据表类 231 :param filter_conditions: 字典,key=list_filter中的一个, value=前端传回的对应的option的value值 232 :return: 233 ''' 234 # 初始化下拉框 235 select_element = """<select class='form-control' name={0}><option value=''>------ 236 </option>""".format(condition) 237 field_object = admin_class.model._meta.get_field(condition) # 获取字段, admin_class中的字段 238 # 字段处理, 默认不选中 239 selected = '' # choice处理 240 if field_object.choices: # 遍历choices值 241 for choice_item in field_object.get_choices()[1:]: 242 # print(choice_item) 243 # 判断选择条件是否和choice值相等, 244 if filter_conditions.get(condition) == str(choice_item[0]): 245 # 被选中 246 selected = 'selected' 247 select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0], 248 selected, choice_item[1]) 249 selected = '' 250 # 外键处理 251 if type(field_object).__name__ == 'ForeignKey': 252 for choice_item in field_object.get_choices()[1:]: 253 # 判断选择条件是否和choice值相等 254 if filter_conditions.get(condition) == str(choice_item[0]): 255 # 被选中 256 selected = 'selected' 257 select_element += """<option value='{0}' {1}>{2}</option>""".format(choice_item[0], 258 selected, choice_item[1]) 259 selected = '' 260 select_element += '</select>' 261 return mark_safe(select_element) 262 263 264 @register.simple_tag 265 def ret_search_help(admin_class): 266 help_info = '' 267 if admin_class.search_fields: 268 # help_info += '搜索:' 269 for item in admin_class.search_fields: 270 help_info += item + '、' 271 else: 272 help_info += '未定义搜索字段' 273 274 return help_info 275 276 277 @register.simple_tag 278 def create_table_title(fields, order_after, filter_conditions_customer, search_text): 279 """ 280 281 :param fields: 282 :param order_after: 283 :param filter_conditions_customer: 284 :return: 285 """ 286 # """<th><span><input type="checkbox"></span>""" 287 # """<a href="?o={{ field.name }} style="display:block;font-size:14px;">{{ field.verbose_name }}</a>""" 288 # 添加一列checkbox 289 ele_checkbox = """<th><span><input type="checkbox" id="test" οnclick="select_all_checkbox(this);"></span></th>""" 290 # filter_text 291 filter_text = '' 292 for k, v in filter_conditions_customer.items(): 293 temp = k + '=' + v 294 filter_text += temp + '&' 295 filter_text = filter_text.rstrip('&') 296 # 添加title 297 ele_title = '' 298 # 设置标题的href 299 for field in fields: 300 temp = order_after.lstrip('-') 301 if temp == field.name: 302 ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format( 303 filter_text, 304 order_after, 305 search_text, 306 field.verbose_name 307 ) 308 else: 309 ele_title += """<th><a href="?{0}&o={1}&_q={2}">{3}</a></th>""".format( 310 filter_text, 311 field.name, 312 search_text, 313 field.verbose_name 314 ) 315 table_title = ele_checkbox + ele_title 316 return mark_safe(table_title) 317 318 319 @register.simple_tag 320 def get_horizontal_tag_values(field, admin_class, form_object): 321 field_obj = getattr(admin_class.model, field.name) 322 query_sets_all = field_obj.rel.to.objects.all() 323 try: # 在添加页面时,form_object是空实例,获取tags字段数据的时候会报错 324 instance_field = getattr(form_object.instance, field.name) 325 except ValueError as e: 326 print(e) 327 return query_sets_all 328 else: 329 query_sets_select = instance_field.all() 330 diff_query_sets = query_sets_all.difference(query_sets_select) 331 return diff_query_sets 332 333 334 @register.simple_tag 335 def get_horizontal_field_value(field, form_object): 336 try: # 在添加页面时,form_object是空实例,获取tags字段数据的时候会报错 337 field_obj = getattr(form_object.instance, field.name) 338 except ValueError as e: 339 print(e) 340 return None 341 else: 342 selected_list = field_obj.all() 343 return selected_list 344 345 346 @register.simple_tag 347 def ret_add_url(request, page, order_before, filter_text, search_text): 348 """ 349 返回添加页面的href 350 :param request: 351 :param page: 352 :param order: 353 :param filter_conditions_customer: 354 :param search_text: 355 :return: 356 """ 357 add_url = "{0}/add?page={1}&o={2}&_q={3}&{4}".format(request.path, 358 page, 359 order_before, 360 search_text, 361 filter_text, 362 ) 363 return add_url
views.py
1 from django.shortcuts import render, HttpResponse, redirect, HttpResponseRedirect 2 from django.core.paginator import Paginator, PageNotAnInteger, EmptyPage 3 from kingadmin import kingadmin 4 from kingadmin.utils import custom_filter, table_search, table_sort, table_filter, filters_to_text 5 from kingadmin.forms import create_model_form 6 # Create your views here. 7 8 9 def default(request): 10 """展示所有可管理的数据表""" 11 manage_tables = kingadmin.enabled_admins 12 return render(request, 13 'kingadmin/default.html', 14 {'manage_tables': manage_tables, }) 15 16 17 def table_list(request, app_name, table_name): 18 """ 19 列出数据表中的所有数据 20 :param request: 21 :param app_name: app名称 22 :param table_name: 数据表名称 23 :return: 24 """ 25 # app_name & table_name都存在enabled_admins中,取出其中的数据 26 # for item in request.GET.items(): 27 # print(item) 28 if app_name in kingadmin.enabled_admins.keys() and \ 29 table_name in kingadmin.enabled_admins[app_name].keys(): 30 admin_class = kingadmin.enabled_admins[app_name][table_name] 31 32 # 检索过滤数据 33 # query_sets = admin_class.model.objects.all() 34 query_sets, filter_conditions_customer = custom_filter(request, admin_class) 35 # 搜索过滤数据 36 query_sets, search_text = table_search(request, admin_class, query_sets) 37 # query_sets 排序 38 query_sets, order_before, order_after = table_sort(request, admin_class, query_sets) 39 filter_conditions_preset = admin_class.list_filter 40 # list_display中的所有字段对应的verbose_name 41 field_verbose_names = [] 42 field_names = [] 43 fields = [] 44 for field_name in admin_class.list_display: 45 for field in admin_class.model._meta.get_fields(): 46 if field.name == field_name: 47 fields.append(field) 48 # field_names.append(field_name) 49 # field_verbose_names.append(field.verbose_name) 50 51 # 分页 52 page = request.GET.get('page', '') 53 54 paginator = Paginator(query_sets, admin_class.list_per_page) 55 # 检索参数 56 filter_text = filters_to_text(filter_conditions_customer) 57 try: 58 contacts = paginator.page(page) 59 except PageNotAnInteger: 60 # If page is not an integer, deliver first page. 61 contacts = paginator.page(1) 62 except EmptyPage: 63 # If page is out of range (e.g. 9999), deliver last page of results. 64 contacts = paginator.page(paginator.num_pages) 65 contacts_count = len(contacts) 66 return render(request, 'kingadmin/table_list.html', {'app_name': app_name, 67 'table_name': table_name, 68 'query_sets': query_sets, 69 'admin_class': admin_class, 70 # 'field_verbose_names': field_verbose_names, 71 # 'field_names': field_names, 72 'order_before': order_before, 73 'order_after': order_after, 74 'fields': fields, 75 'contacts': contacts, 76 'contacts_count': contacts_count, 77 'filter_conditions': filter_conditions_preset, 78 'filter_conditions_customer': filter_conditions_customer, 79 'search_text': search_text, 80 'page': page, 81 'filter_text': filter_text, 82 }) 83 # app_name | table_name不存在enabled_admin中,就返回错误信息 84 else: 85 error = '应用名称或数据表名称不存在或未注册' 86 return render(request, 87 'kingadmin/table_list.html', 88 {'error': error, 89 'app_name': app_name, 90 'table_name': table_name, 91 }) 92 93 94 def table_object_edit(request, app_name, table_name, object_id): 95 """ 96 编辑表中的一条数据 97 :param request: 98 :param app_name: 99 :param table_name: 100 :param id: 101 :return: 102 """ 103 admin_class = kingadmin.enabled_admins[app_name][table_name] 104 model_form = create_model_form(request, admin_class) 105 object_list = admin_class.model.objects.get(id=object_id) 106 query_sets, filter_conditions = table_filter(request, admin_class) 107 page = request.GET.get('page', default='') 108 order = request.GET.get('o', '') 109 search_text = table_search(request, admin_class, query_sets)[1] 110 filter_conditions = custom_filter(request, admin_class)[1] 111 filter_text = filters_to_text(filter_conditions) 112 if request.method == 'POST': 113 form_object = model_form(request.POST, instance=object_list) 114 if form_object.is_valid(): 115 form_object.save() 116 return redirect('/kingadmin/{0}/{1}?page={2}&o={3}&_q={4}&{5}'.format( 117 app_name, 118 table_name, 119 page, 120 order, 121 search_text, 122 filter_text, 123 )) 124 # else: # 目前可以删除(无论检验成功与否都是要返回table_object_edit.html) 125 # return render(request, 'kingadmin/table_object_edit.html', {'form_object': form_object, 126 # 'admin_class': admin_class, 127 # 'app_name': app_name, 128 # 'table_name': table_name, 129 # }) # 目前可以删除 130 else: 131 form_object = model_form(instance=object_list) 132 return render(request, 'kingadmin/table_object_edit.html', {'form_object': form_object, 133 'admin_class': admin_class, 134 'app_name': app_name, 135 'table_name': table_name, 136 }) 137 138 139 def table_object_add(request, app_name, table_name): 140 """ 141 添加页面 142 :param request: 143 :param app_name: 144 :param table_name: 145 :return: 146 """ 147 admin_class = kingadmin.enabled_admins[app_name][table_name] 148 model_form = create_model_form(request, admin_class) 149 150 query_string = request.META.get('QUERY_STRING', '') 151 redirect_url = '/kingadmin/{0}/{1}?{2}'.format(app_name, table_name, query_string) 152 if request.method == 'POST': 153 form_object = model_form(request.POST) 154 if form_object.is_valid(): 155 form_object.save() 156 return redirect(redirect_url) 157 else: 158 form_object = model_form() 159 return render(request, 'kingadmin/table_object_add.html', {'app_name': app_name, 160 'table_name': table_name, 161 'admin_class': admin_class, 162 'form_object': form_object, 163 })
urls.py
1 from django.conf.urls import url, include 2 from django.contrib import admin 3 from . import views 4 5 urlpatterns = [ 6 url(r'^$', views.default), 7 url(r'^(\w+)/(\w+)$', views.table_list, name='table_list'), 8 url(r'^(\w+)/(\w+)/(\d+)/edit$', views.table_object_edit, name='table_object_edit'), 9 url(r'^(\w+)/(\w+)/add$', views.table_object_add, name='table_object_add'), 10 ]
效果如下:
问题解决。
如果有更好的解决办法,欢迎指教。