如何快速的进行数据的添加以及修改呢?modelform来实现是可以达到效果的,在这里就是应用了modelform,每一个表都不同,所以需要创建不同的modelform。

 def get_model_form_class(self, is_add,request,pk, *args,**kwargs):
"""
获取添加、修改功能的modelform
:return:
"""
if self.model_form_class:
return self.model_form_class class AddModelForm(BaseModelForm,forms.ModelForm):
class Meta:
model = self.model_class
fields = '__all__' return AddModelForm

是否注意到创建modelform时继承了BaseModelForm,实际上就是将request对象传入modelform中

class BaseRequestModelForm(object):
def __init__(self, request, *args, **kwargs):
self.request = request
super(BaseRequestModelForm, self).__init__(*args, **kwargs) class BaseModelForm(BaseRequestModelForm,forms.ModelForm): def __init__(self,request,*args,**kwargs):
super().__init__(request,*args,**kwargs)
#####给modelform字段加样式
for name,field in self.fields.items():
attrs_dict={'class':'form-control'}
if 'DateTimeField' in field.__repr__():
attrs_dict = {'class': 'form-control', 'date_time': 'datetimepicker', 'size': ''}
field.widget.attrs.update(attrs_dict)

这就是在之前提到过的在执行视图函数之前装饰器的作用。

    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

那么为什么要这样做呢?给一个场景就是客户付款的订单只是自己所有的订单,并不包括其他客户的订单。

class PaymentRecordModelForm(BaseModelForm):
class Meta:
model=models.PaymentRecord
exclude=['confirm_date','confirm_user'] def __init__(self,request,*args, **kwargs): #form中没有传入request对象
super().__init__(request,*args, **kwargs)
current_user_id = self.request.session['user_info']['id']
customer=models.Customer.objects.filter(name=models.UserInfo.objects.filter(id=current_user_id).first().username).first()
self.fields['order'].queryset = models.Order.objects.filter(customer=customer)

接下来就是添加、修改的视图函数

    def add_view(self,request,*args,**kwargs):
# 处理所有添加功能,使用ModelForm来实现
Add_Model_Form = self.get_model_form_class(True,request,None,*args,**kwargs)
if request.method == 'GET':
form = Add_Model_Form(request=request)
return render(request, 'stark/change.html', {'form': form,'starkclass':self})
form = Add_Model_Form(request=request,data=request.POST)
if form.is_valid():
obj=self.save(request,form,False,*args,**kwargs)
# obj=form.save()
pop_post_id=request.GET.get('pop_id')
if pop_post_id:
res={'pop_post_id':pop_post_id,'pk':obj.pk,'obj':str(obj)}
return render(request,'stark/pop.html',res) return redirect(self.reverse_changelist_url(*args,**kwargs))
return render(request, 'stark/change.html', {'form': form})
    def change_view(self, request,pk,*args,**kwargs):
"""
处理所有修改表单
:param request:
:param pk:
:return:
"""
Edit_Model_Form = self.get_model_form_class(False,request,pk,*args,**kwargs)
obj = self.model_class.objects.filter(pk=pk).first()
if not obj:
return HttpResponse('该用户不存在')
if request.method == 'GET':
form = Edit_Model_Form(request,instance=obj)
return render(request, 'stark/change.html', {'form': form})
form = Edit_Model_Form(request=request,data=request.POST,instance=obj)
if form.is_valid():
self.save(request,form,True,*args,**kwargs)
return redirect(self.reverse_changelist_url(*args,**kwargs))
filter_horizontal=self.get_filter_horizontal()
el=EditList(self,request,pk,filter_horizontal,*args,**kwargs)#修改和添加共用一个页面,所以form没有进行封装
return render(request, 'stark/change.html', {'form': form,'el':el})

注意在保存时并没有直接保存,而是预留了保存的钩子函数,这样在保存前还可以做一些其它动作。

    ####对于一些排除字段,重新此方法进行添加
def save(self,request,form,is_modify,*args,**kwargs): return form.save()

在这里添加和修改共用了一个模板页面,添加中包括了pop功能,和djangoadmin类似,凡是foreignkey字段都可以进行点击添加。修改页面中有filter_horizontal功能,主要就是针对ManyToMany字段。

  <form class="change" method="post" novalidate>
{% csrf_token %}
{% for filed in form %}
<div class="form-group" style="position: relative">
{% if field.name in el.filter_horizontal %}
<label>{{ filed.label }}</label>
{% m2m_all_data form field el.stark_class %}
<span class="errors pull-right" style="color: red">{{ filed.errors.0 }}</span>
{% else %} <label>{{ filed.label }}</label>
{% gen_is_pop filed starkclass %}
<span class="errors pull-right" style="color: red">{{ filed.errors.0 }}</span>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-primary">保存</button> </form>

在添加页面中对后台传递的form字段进行判断,如果是ManyToMany就执行m2m_all_data 标签方法。

@register.inclusion_tag('stark/m2m.html')
def m2m_all_data(form,field,stark_class):
return {'m2m_data':m2m_data(form,field,stark_class),'m2m_un_data':m2m_un_data(form,field,stark_class),'field':field}
@register.simple_tag()
def m2m_data(form,field,stark_class):
"""
出项在左侧的可选项
:param form:
:param field:
:param stark_class:
:return:
"""
field_name=field.name
field_obj=stark_class.model_class._meta.get_field(field_name)
if isinstance(field_obj,ManyToManyField):
data_set = set(field_obj.remote_field.model.objects.all())
if form.instance.id:
selected_data_set=set(getattr(form.instance,field_obj.name).all())
queryset=data_set-selected_data_set
return queryset
return data_set @register.simple_tag()
def m2m_un_data(form,field,stark_class):
"""
出项在右侧已选项
:param form:
:param field:
:return:
"""
field_name = field.name
field_obj=stark_class.model_class._meta.get_field(field_name)
if isinstance(field_obj,ManyToManyField):
if form.instance.id:
selected_data_set = getattr(form.instance, field_obj.name).all()
return selected_data_set
else:
return []

这里利用了inclusion_tag方法

{% load stark %}
<div class="row">
<div class="col-lg-6">
<input type="search" oninput="M2mSearch(this)" class="form-control">
<select id="id_{{ field.name }}_from" multiple class="multiselect" class="form-control">
{% for row in m2m_data %}
<option ondblclick="MoveElement(this,'id_{{ field.name }}_to')" value="{{ row.id }}">{{ row }}</option>
{% endfor %}
</select>
<p><a onclick="MoveAllElements('id_{{ field.name }}_from','id_{{ field.name }}_to')">全选</a></p>
</div> <div class="col-lg-6">
<input type="search" oninput="M2mSearch(this)" class="form-control">
<select id="id_{{ field.name }}_to" selected_data="selected_m2m" multiple class="multiselect" name="{{ field.name }}" class="form-control">
{% for row in m2m_un_data %}
<option ondblclick="MoveElement(this,'id_{{ field.name }}_from')"
value="{{ row.id }}">{{ row }}</option>
{% endfor %}
</select>
<p><a onclick="MoveAllElements('id_{{ field.name }}_to','id_{{ field.name }}_from')">移除</a></p>
</div>
</div>

需要用到的script代码

        function readysubmit() {

            $('select[selected_data] option').prop('selected', true);
} function MoveElement(ths, target_id) {
var $target_from_id = $(ths).parent().attr('id');
var op = $('<option></option>');
op.attr('ondblclick', 'MoveElement(this,"' + $target_from_id + '")');
op[0].value = $(ths).val();
op[0].text = $(ths).text();
$('#' + target_id).append(op);
$(ths).remove()
} function MoveAllElements(from_id, target_id) {
$('#' + from_id).children().each(function () {
MoveElement($(this), target_id)
})
} function M2mSearch(ths) {
var $searchText = $(ths).val().toUpperCase();
$(ths).next().children().each(function () {
var $matchText = $(this).text().toUpperCase().search($searchText);
if ($matchText != -1) {
$(this).show()
} else {
$(this).hide()
}
}) }

另外一个就是pop功能了,主要解决Foreignkey的问题

@register.simple_tag()
def gen_is_pop(bfield,starkclass):
if isinstance(bfield.field,ModelChoiceField):
namespace=starkclass.site.namespace
related_app_lebel=bfield.field.queryset.model._meta.app_label
related_model_name=bfield.field.queryset.model._meta.model_name
url_name='%s:%s_%s_add'%(namespace,related_app_lebel,related_model_name)
add_url=reverse(url_name)
add_url=add_url+'?pop_id=id_%s'%bfield.name
return mark_safe("""<a onclick="pop('%s')" style="position: absolute;right: -30px;top: 20px"><span style="font-size: 28px">+</span></a>"""%add_url)
return bfield

后台返回的数据先返回给另一个html页面,在这个页面中执行父窗口中的js代码

{% extends 'layout.html' %}

{% block js %}
<script>
(function () {
opener.get_data('{{ pop_post_id }}','{{ pk }}','{{ obj }}');
window.close()
})() </script> {% endblock %}

父窗口中的js代码实际就是get_data()函数了

 function pop(url) {
window.open(url,'PopName',"width=600,height=400,top=100,left=100")
} function get_data(pop_post_id,pk,obj) {
var $option=$('<option>');
$option.html(obj);
$option.val(pk);
$option.attr('selected','selected');
$('#'+pop_post_id).append($option)
}

这就是添加、修改页面的主要功能了。

stark组件之添加、修改页面内容搭建(七)的更多相关文章

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

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

  2. phpcms v9 后台添加修改页面空白页问题解决方法

    phpcms v9 添加修改页面空白页的解决方法 找一个正常运行的phpcms 将caches\caches_model\caches_data 目录下的 content_form.class.php ...

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

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

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

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

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

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

  6. JQuery DataTables Editor---只修改页面内容

    近来在工作中需要对JQuery DataTables进行增,删,改的操作,在网上找了一些资料,感觉比较的好的就是(http://editor.datatables.net/)文章中所展示的操作方法(如 ...

  7. stark组件开发之列表页面自定义函数扩展

    对于展示页面, 可能需要显示一些. 数据库中,没有的字段. 比如, 删除按钮, 编辑按钮.  这个数据库,是没有的. 所以,可能就需要, 添加一个这个东西.  比如我在渲染的时候, 给他添加两个函数进 ...

  8. stark组件开发之列表页面预留钩子方法。 可根据用户的不同,显示不同的列

    要实现,这个方法.子类中 list_diplay 这个列表, 就不能够写死.他应该是 可以根据.用户的不同,返回不同的值. 所以 就需要一个函数, 可以进行判断当前用户是谁. 并且往这个列表中添加,他 ...

  9. Python-S9-Day88——stark组件之设计urls

    03 stark组件之设计urls 04 stark组件之设计urls2 05 stark组件之设计list_display 06 stark组件之z查看页面的数据展示 03 stark组件之设计ur ...

随机推荐

  1. bzoj 4823: [Cqoi2017]老C的方块【最大权闭合子图】

    参考:https://www.cnblogs.com/neighthorn/p/6705785.html 并不是黑白染色而是三色染色(还有四色的,不过是一个意思 仔细观察一下不合法情况,可以发现都是特 ...

  2. poj 3130 How I Mathematician Wonder What You Are! 【半平面交】

    求多边形的核,直接把所有边求半平面交判断有无即可 #include<iostream> #include<cstdio> #include<algorithm> # ...

  3. 洛谷P3287 [SCOI2014]方伯伯的玉米田(树状数组)

    传送门 首先要发现,每一次选择拔高的区间都必须包含最右边的端点 为什么呢?因为如果拔高了一段区间,那么这段区间对于它的左边是更优的,对它的右边会更劣,所以我们每一次选的区间都得包含最右边的端点 我们枚 ...

  4. Windows下安装Ubuntu16.04双系统

    ROS需要在Ubuntu系统上开发,虚拟机跑Ubuntu开发ROS容易出现各种各样的问题,所以需要安装Ubuntu16.04双系统.笔者也是一步步按着网上的帖子来,由于网上的教程都不是最新的而且有的也 ...

  5. C++中的四种强制类型转换符详解

    阅读目录 C++即支持C风格的类型转换,又有自己风格的类型转换.C风格的转换格式很简单,但是有不少缺点的: 转换太过随意,可以在任意类型之间转换.你可以把一个指向const对象的指针转换成指向非con ...

  6. 暴力(判凸四边形) FZOJ 2148 Moon Game

    题目传送门 题意:给了n个点的坐标,问能有几个凸四边形 分析:数据规模小,直接暴力枚举,每次四个点判断是否会是凹四边形,条件是有一个点在另外三个点的内部,那么问题转换成判断一个点d是否在三角形abc内 ...

  7. 题解报告:hdu 1203 I NEED A OFFER!(01背包)

    Problem Description Speakless很早就想出国,现在他已经考完了所有需要的考试,准备了所有要准备的材料,于是,便需要去申请学校了.要申请国外的任何大学,你都要交纳一定的申请费用 ...

  8. 题解报告:hdu 2062 Subset sequence

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2062 Problem Description 考虑集合An = {1,2,...,n}. 例如,A1 ...

  9. 题解报告:hdu 2093 考试排名

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2093 Problem Description C++编程考试使用的实时提交系统,具有即时获得成绩排名的 ...

  10. windows系统下在忘记安装make的Cygwin中如何正确安装make(图文详解)

    由于我在安装cygwin时忘了包含make包,所以安装后发现我在bash中无法使用make命令.但是一般在cygwin下面的软件都是要用make来实现编译和安装的.没有make,又如何编译生成make ...