stark组件之添加、修改页面内容搭建(七)

如何快速的进行数据的添加以及修改呢?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': '16'}
            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 οnclick="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)
}

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

 

转载于:https://www.cnblogs.com/shenjianping/p/10911605.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值