如何快速的进行数据的添加以及修改呢?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. K - KazaQ’s Socks

    Bryce1010模板 #include <bits/stdc++.h> using namespace std; #define LL long long int main() { LL ...

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

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

  3. Windows10系统切换JDK版本(前提是装了多个版本的JDK)

    由于是直接截屏,等我回过头来整理的时候忘记了文章原来的出处, 如作者本人看到,如有侵权,请联系删除!

  4. AJPFX区分this和super

    this和super的区别No.区别thissuper1操作属性this.属性:表示调用本类中的属性,如果本类中的属性不存在,则从父类查找super.属性:表示调用父类中的属性2操作方法this.方法 ...

  5. AJPFX: Java基础多线程(一)

    多线程是Java学习的非常重要的方面,是每个Java程序员必须掌握的基本技能.本文只是多线程细节.本质的总结,并无代码例子入门,不适合初学者理解.初学者学习多线程,建议一边看书.看博文,以便写代码尝试 ...

  6. AJPFX总结在循环中break与continue的区别

    相信刚学编程的人很容易被break,continue这两个关键词搞混淆了,两者都有跳出循环的意思,但是他们到底有什么区别呢?其实很简单,break是结束整个循环体,continue是结束当前这一单次循 ...

  7. 微信小程序之多行文本省略号

    最近在捣鼓小程序,期间遇到的问题,踩过的坑,也是在网上各种搜.这里也说下我解决的问题,方便大家. 在小程序首页显示文本列表的时候,为了美观,不希望把所有的文本都显示出来,希望是显示前几行(比如前3行, ...

  8. iOS之NSAttributedString-------字符属性

    NSAttributedString 字符属性 字符属性可以应用于 attributed string 的文本中. NSString *const NSFontAttributeName;(字体) N ...

  9. Asp.Net 设计模式 之 “简单工厂”模式

    主要思想: public static Operation CreateFactory(string ope)        {            //实例化空父类,让父类指向子类         ...

  10. 在 Windows Server 上搭建 *** 服务端(转载加亲测)

    转载自:https://diveng.io/build-shadowsocks-server-on-windows-server.html 下面的教程建议大家使用第一种方法安装,说是比较简单.我则使用 ...