三十一、动态Form
1.一、计算机初识2.二、数据概述3.六、ip地址与子网划分4.五、网络通信实现5.四、字符编码6.三、网络基础7.十四、MySQL与Django之Model基础8.十三、Django Admin9.十二、Django视图函数和模版相关10.十一、Django url控制系统11.十、Django静态文件12.九、Django环境搭建(基于anaconda环境)13.八、Python开发环境管理14.七、ip地址配置15.二十五、JSON跨域16.二十四、文件上传17.二十三、Django Serializes18.二十二、Django之Form组件19.二十一、分页20.JS笔记21.二十、基于Bootstrap和FontAwesome制作页面22.十九、Ajax和iFrame23.十八、Django之Http24.十七、Cookie和Session25.十六、Django的ORM(二)26.十五、Django的ORM27.实践中前端的一些笔记28.二十六、登录相关29.二十九、RBAC+动态菜单30.二十八、XSS31.JS第三方插件32.二十七、简单的验证码实现33.三十二、Django实践的笔记
34.三十一、动态Form
35.三十、Kingadmin1、动态Form
form_handle.py
from django.forms import ModelForm
def create_dynamic_model_form(admin_class,form_add=False):
"""动态的生成modelform
form_add: False 默认是修改的表单,True时为添加
"""
class Meta:
model = admin_class.model
# fields = ['name','consultant','status']
fields = "__all__"
if not form_add:#change
exclude = admin_class.readonly_fields
admin_class.form_add = False #这是因为自始至终admin_class实例都是同一个,
# 这里修改属性为True是为了避免上一次添加调用将其改为了True
else: #add
admin_class.form_add = True
def __new__(cls, *args, **kwargs):
print("__new__",cls,args,kwargs)
for field_name in cls.base_fields:
filed_obj = cls.base_fields[field_name]
filed_obj.widget.attrs.update({'class':'form-control'})
# if field_name in admin_class.readonly_fields:
# filed_obj.widget.attrs.update({'disabled': 'true'})
# print("--new meta:",cls.Meta)
#print(cls.Meta.exclude)
return ModelForm.__new__(cls)
dynamic_form = type("DynamicModelForm" ,(ModelForm,) ,{'Meta' :Meta,'__new__':__new__})
print(dynamic_form)
return dynamic_form
2、动态Form的使用(views)
@login_required
def table_obj_delete(request, app_name, model_name, obj_id):
admin_class = site.enabled_admins[app_name][model_name]
obj = admin_class.model.objects.get(id=obj_id)
if request.method == "POST":
obj.delete()
return redirect("/kingadmin/{app_name}/{model_name}/".format(app_name=app_name, model_name=model_name))
return render(request, 'kingadmin/table_obj_delete.html', locals())
def table_obj_change(request, app_name, model_name, obj_id):
admin_class = site.enabled_admins[app_name][model_name]
obj = admin_class.model.objects.get(id=obj_id)
form = form_handle.create_dynamic_model_form(admin_class) #创建动态model form
if request.method == "GET":
form_obj = form(instance=obj)
elif request.method == "POST":
form_obj = form(instance=obj,data=request.POST)
if form_obj.is_valid():
form_obj.save() #直接save就可以保存request.POST的修改信息
return redirect("/kingadmin/%s/%s/" %(app_name,model_name))
# from crm.forms import CustomerForm
# form_obj = CustomerForm()
return render(request, 'kingadmin/table_obj_change.html', locals())
def table_obj_add(request,app_name,model_name):
admin_class = site.enabled_admins[app_name][model_name]
model_form = form_handle.create_dynamic_model_form(admin_class,form_add=True)
if request.method == "GET":
form_obj = model_form()
elif request.method == "POST":
form_obj = model_form(data=request.POST)
if form_obj.is_valid():
form_obj.save()
return redirect("/kingadmin/%s/%s/" % (app_name, model_name))
return render(request,'kingadmin/table_obj_add.html',locals())
def get_filter_result(request,querysets):
filter_conditions = {}
for key,val in request.GET.items():
if key in ('_page', '_o', '_q'): continue # 分页、排序、搜索参数,非过滤参数
if val:
filter_conditions[key] = val #key:input元素的name val:select的值
return querysets.filter(**filter_conditions),filter_conditions
def get_orderby_result(request,querysets,admin_class):
"""排序"""
current_ordered_column = {}
orderby_index = request.GET.get('_o')
if orderby_index: # 如果本来已经在排序
orderby_key = admin_class.list_display[ abs(int(orderby_index)) ] # 字段名
current_ordered_column[orderby_key] = orderby_index #为了让前端知道当前排序的列
if orderby_index.startswith('-'):
orderby_key = '-'+ orderby_key
return querysets.order_by(orderby_key),current_ordered_column
else:
return querysets,current_ordered_column
def get_serached_result(request,querysets,admin_class):
search_key = request.GET.get('_q')
if search_key :
q = Q() # Q查询
q.connector = 'OR' # 多条件OR
for search_field in admin_class.search_fields:
q.children.append(("%s__contains"% search_field,search_key))
return querysets.filter(q)
return querysets
@login_required
def table_obj_list(request, app_name, model_name):
admin_class = site.enabled_admins[app_name][model_name]
if request.method == "POST":
selected_action = request.POST.get('action')
selected_ids = json.loads(request.POST.get('selected_ids') )
selected_objs = admin_class.model.objects.filter(id__in=selected_ids)
admin_action_func = getattr(admin_class,selected_action)
admin_action_func(request,selected_objs)
querysets = admin_class.model.objects.all()
querysets, filter_condtions = get_filter_result(request, querysets)
admin_class.filter_condtions = filter_condtions
# searched queryset result
querysets = get_serached_result(request, querysets, admin_class)
admin_class.search_key = request.GET.get('_q', '')
# sorted querysets
querysets, sorted_column = get_orderby_result(request, querysets, admin_class)
paginator = Paginator(querysets, admin_class.list_per_page) # Show 25 contacts per page
page = request.GET.get('_page')
try:
querysets = paginator.page(page) #可以拿到指定页的querysets
except PageNotAnInteger:
# If page is not an integer, deliver first page.
querysets = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
querysets = paginator.page(paginator.num_pages)
print(request.GET) #
print(querysets.object_list)
return render(request, 'kingadmin/table_obj_list.html', {'querysets': querysets,
'admin_class': admin_class,
'sorted_column':sorted_column})
3、model新建、修改页面(Form html中)
table_obj_add.html
{% extends 'kingadmin/index.html' %}
{% load kingadmin_tags %}
{% block right-content-container %}
<h2 class="page-header">{% get_model_name admin_class %}</h2>
<h4 class="page-header">添加{% get_model_name admin_class %}数据</h4>
<div>
{% include 'kingadmin/table_obj_change_component.html' %}
</div>
{% endblock %}
table_obj_change.html
{% extends 'kingadmin/index.html' %}
{% load kingadmin_tags %}
{% block right-content-container %}
<h2 class="page-header">{% get_model_name admin_class %}</h2>
<h4 class="page-header">修改{{ form_obj.instance }}</h4>
<div>
{% include 'kingadmin/table_obj_change_component.html' %}
</div>
{% endblock %}
table_obj_change_component.html
{% load kingadmin_tags %}
<form class="form-horizontal" method="post" onsubmit="VerificationBeforeFormSubmit()"> {% csrf_token %}
{{ form_obj.errors }}
{% for field in form_obj %} # 这样就遍历form的所有字段
<div class="form-group">
<label class="col-sm-2 control-label">{{ field.label }}</label>
<div class="col-sm-10">
{% if field.name in admin_class.filter_horizontal %} #若filter_horizontal中有这个字段
<div class="col-lg-5"> # oninput:搜索框只要输入就触发
<input type="search" class="form-control" oninput="FuzzSearch(this)">
<select id="id_{{ field.name }}_from" multiple class="form-control">
{% get_available_m2m_data field.name form_obj admin_class as available_m2m_data %}
{% for obj in available_m2m_data %}
<option ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_to')" value="{{ obj.id }}">{{ obj }}</option>
{% endfor %} #ondblclick 双击事件
</select>
<p><a onclick="MoveAllElements('id_{{ field.name }}_from','id_{{ field.name }}_to')">Choose All</a></p>
</div>
<div class="col-lg-5">
<select tag="selected_m2m" id="id_{{ field.name }}_to" multiple class="form-control" name="{{ field.name }}">
{% get_selected_m2m_data field.name form_obj admin_class as selected_m2m_data %}
{% for obj in selected_m2m_data %}
<option value="{{ obj.id }}" ondblclick="MoveSelectedOption(this,'id_{{ field.name }}_from')">{{ obj }}</option>
{% endfor %}
</select>
<p><a onclick="MoveAllElements('id_{{ field.name }}_to','id_{{ field.name }}_from')">Remove All</a></p>
</div>
{% else %}
{{ field }}
{% endif %}
<span style="color: red">{{ field.errors.0 }} </span>
</div>
</div>
{% endfor %}
{% if not admin_class.form_add %} <!--如果这是修改表单-->
{% for field in admin_class.readonly_fields %}
<div class="form-group">
<label class="col-sm-2 control-label">{{ field }}</label>
<div class="col-sm-10">
<p>{% get_obj_field_val form_obj field %}</p>
</div>
</div>
{% endfor %}
{% endif %}
<div class="form-group">
<div class=" col-sm-2">
<a class="btn btn-danger" href="{% url 'obj_delete' app_name model_name form_obj.instance.id %}">Delete</a>
</div>
<div class="col-sm-offset-11 col-sm-2">
<button type="submit" class="btn btn-info">Save</button>
</div>
</div>
</form>
<script>
function MoveSelectedOption(ele,target_id) {
var new_target_id = $(ele).parent().attr('id');
var option = "<option value='" + $(ele).val() +"'ondblclick=MoveSelectedOption(this,'"+ new_target_id +"') >" + $(ele).text() +"</option>";
$("#"+ target_id).append(option);
$(ele).remove();
}
function MoveAllElements(from_id,to_id) {
console.log( $("#"+from_id).children());
$("#"+from_id).children().each(function () {
MoveSelectedOption(this,to_id);
})
}
function FuzzSearch(ele){
console.log($(ele).val());
var search_text = $(ele).val().toUpperCase();
$(ele).next().children().each(function () { #js字符串search方法
if ( $(this).text().toUpperCase().search(search_text) != -1){
$(this).show(); #jQuery的使元素显示的方法
}else {
$(this).hide(); #jQuery的使元素隐藏的方法
}
})
}
function VerificationBeforeFormSubmit() {
$("select[tag] option").prop('selected',true);
}
</script>
4、相关simple_tag
创建templatetags包,然后创建kingadmin_tags.py模块
from django.template import Library
from django.utils.safestring import mark_safe
import datetime ,time
register = Library()
@register.simple_tag
def build_filter_ele(filter_column,admin_class):
column_obj = admin_class.model._meta.get_field(filter_column)
try:
filter_ele = "<div class='col-md-2'>%s<select class='form-control' name='%s'>" % (filter_column,filter_column)
for choice in column_obj.get_choices(): # get_choices()可以拿到对应字段的choices
selected = '' # 若是外键,get_choices()可以拿到关联的外键model数据[(id, model.__str__),]
if filter_column in admin_class.filter_condtions:#当前字段被过滤了
# print("filter_column", choice,
# type(admin_class.filter_condtions.get(filter_column)),
# admin_class.filter_condtions.get(filter_column))
if str(choice[0]) == admin_class.filter_condtions.get(filter_column):#当前值被选中了
selected = 'selected'
print('selected......')
option = "<option value='%s' %s>%s</option>" % (choice[0],selected,choice[1])
filter_ele += option
except AttributeError as e:
print("err",e)
filter_ele = "<div class='col-md-2'>%s<select class='form-control' name='%s__gte'>" % (filter_column,filter_column)
if column_obj.get_internal_type() in ('DateField','DateTimeField'):
time_obj = datetime.datetime.now()
time_list = [
['','------'],
[time_obj,'Today'],
[time_obj - datetime.timedelta(7),'七天内'], #日期的计算
[time_obj.replace(day=1),'本月'], # 日期的直接修改
[time_obj - datetime.timedelta(90),'三个月内'],
[time_obj.replace(month=1,day=1),'YearToDay(YTD)'],
['','ALL'],
]
for i in time_list:
selected = ''
time_to_str = ''if not i[0] else "%s-%s-%s"%(i[0].year,i[0].month,i[0].day)
if "%s__gte"% filter_column in admin_class.filter_condtions: # 当前字段被过滤了
print('-------------gte')
if time_to_str == admin_class.filter_condtions.get("%s__gte"% filter_column): # 当前值被选中了
selected = 'selected'
option = "<option value='%s' %s>%s</option>" % \
(time_to_str ,selected,i[1])
filter_ele += option
filter_ele += "</select></div>"
return mark_safe(filter_ele)
@register.simple_tag
def build_table_row(obj,admin_class):
"""生成一条记录的html element"""
ele = ""
if admin_class.list_display:
for index, column_name in enumerate(admin_class.list_display):
column_obj = admin_class.model._meta.get_field(column_name)
if column_obj.choices: #get_xxx_display
column_data = getattr(obj,'get_%s_display'% column_name)()
else:
column_data = getattr(obj,column_name) #通过反射获取属性值
td_ele = "<td>%s</td>"% column_data
if index == 0:
td_ele = "<td><a href='%s/change/'>%s</a></td>"% (obj.id,column_data)
ele += td_ele
else:
td_ele = "<td><a href='%s/change/'>%s</a></td>" % (obj.id, obj)
ele += td_ele
return mark_safe(ele)
@register.simple_tag
def get_model_name(admin_class):
return admin_class.model._meta.model_name.upper()
@register.simple_tag
def get_sorted_column(column,sorted_column,forloop):
#sorted_column = {'name': '-0'}
if column in sorted_column:#这一列被排序了,
#你要判断上一次排序是什么顺序,本次取反
last_sort_index = sorted_column[column]
if last_sort_index.startswith('-'):
this_time_sort_index = last_sort_index.strip('-')
else:
this_time_sort_index = '-%s'%last_sort_index
return this_time_sort_index
else:
return forloop
@register.simple_tag
def render_sorted_arrow(column,sorted_column):
if column in sorted_column: # 这一列被排序了,
last_sort_index = sorted_column[column]
if last_sort_index.startswith('-'):
arrow_direction = 'bottom'
else:
arrow_direction = 'top'
ele = '''<span class="glyphicon glyphicon-triangle-%s" aria-hidden="true"></span>''' % arrow_direction
return mark_safe(ele)
return ''
@register.simple_tag
def render_filtered_args(admin_class,render_html=True):
'''拼接筛选的字段'''
if admin_class.filter_condtions:
ele = ''
for k,v in admin_class.filter_condtions.items():
ele += '&%s=%s' %(k,v)
if render_html:
return mark_safe(ele)
else:
return ele
else:
return ''
@register.simple_tag
def render_paginator(querysets,admin_class,sorted_column):
ele = '''
<ul class="pagination">
'''
for i in querysets.paginator.page_range:
if abs(querysets.number - i) < 2 :#display btn
active = ''
if querysets.number == i : #current page
active = 'active'
filter_ele = render_filtered_args(admin_class)
sorted_ele = ''
if sorted_column:
sorted_ele = '&_o=%s' % list(sorted_column.values())[0]
p_ele = '''<li class="%s"><a href="?_page=%s%s%s">%s</a></li>''' % (active,i,filter_ele,sorted_ele,i)
ele += p_ele
ele += "</ul>"
return mark_safe(ele)
@register.simple_tag
def get_current_sorted_column_index(sorted_column):
# .values() 拿到字典值的列表 但类型是dict_values
return list(sorted_column.values())[0] if sorted_column else ''
@register.simple_tag
def get_available_m2m_data(field_name,form_obj,admin_class):
"""返回的是m2m字段关联表的所有数据"""
field_obj = admin_class.model._meta.get_field(field_name)
obj_list = set(field_obj.related_model.objects.all()) #字典.related_model
try:
selected_data = set(getattr(form_obj.instance, field_name).all())
except TypeError as e:
print(e)
return obj_list
else:
return obj_list - selected_data
@register.simple_tag
def get_selected_m2m_data(field_name,form_obj,admin_class):
"""返回已选的m2m数据"""
# selected_data = getattr(form_obj.instance ,field_name).all() if form_obj.instance else ()
#
# return selected_data
# print(type(form_obj.instance), id(form_obj.instance))
# if form_obj.instance:
# print(1111111111)
# print(field_name)
# print(getattr(form_obj.instance, field_name))
try:
#新建model时,getattr(form_obj.instance, field_name)会出错。
# 通过if判断instance是否有来区分是修改还是新建行不通,不知道为什么新建时,
# 这里instance已经有值,有id。但获取字段就报错:TypeError: __str__ returned non-string (type NoneType)
selected_data = getattr(form_obj.instance, field_name).all()
except TypeError as e:
return ()
else:
return selected_data #教程源码:用 if form_obj.instance.id:
@register.simple_tag
def get_obj_field_val(form_obj,field):
'''返回model obj具体字段的值'''
return getattr(form_obj.instance,field)
合集:
Python全栈(Django)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库