django groupcheckbox element vs 原生

================

背景:用原生和用element plus处理checkbox group

提交全部用原生view

=============

============用django 原生,解决数据回显时候页面数据checked状态=======================

django 若在model定义,只有 models.ManyToManyField(Category) # Default: SelectMultiple  才默认多选,

还有一个方案是:

model定义

multisel1=models.CharField(max_length=100,null=True,blank=True)#elementui
multisel2=models.CharField(max_length=100,null=True,blank=True)#django

form定义

class Item1Form(forms.ModelForm):
multisel2 = forms.MultipleChoiceField(
choices=[
(1, '教育'),
(2, '企业管理'),
(3, '人工智能'),
],
widget=forms.CheckboxSelectMultiple, # 可选,用于 Django 原生渲染
label='技术栈2', required=False,
)

django原生CheckboxSelectMultiple,往数据库保存是 string ['1', '2']。 注意db中的['1', '2']是charfeild

而CheckboxSelectMultiple要正确回显,接受的value必须是list

所以在modelform要处理数据

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        #为了和element的定制widget混合着用,label和input在一行
        self.helper = FormHelper()
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-lg-2'  # 左側 label 寬度
        self.helper.field_class = 'col-lg-10'  # 右側 input 寬度
        if self.instance and self.instance.multisel2:
                try:
                    # If stored as stringified list, e.g., "['1', '2']"
                    self.initial['multisel2'] = ast.literal_eval(self.instance.multisel2)
                except Exception:
                    self.initial['multisel2'] = []

 

在form.html中,multisel2 的value必须是python的list

{{ form.multisel2 | as_crispy_field }}

 

 

 

============用element plus 有2种类用法=======================

方法一

image

 为了普通 post提交而隐藏的 input 如下

image

所以, modelform的widget不必特殊定制,就是默认charfield,则数据库里面保存的是 1,3

image

 

 但 group checkbox回显,checked的状态的value 必须是 js 的数字 [1,3]才可以 , 所以,要在modelform设置初始值

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        #为了和element的定制widget混合着用,label和input在一行
        self.helper = FormHelper()
        self.helper.form_class = 'form-horizontal'
        self.helper.label_class = 'col-lg-2'  # 左側 label 寬度
        self.helper.field_class = 'col-lg-10'  # 右側 input 寬度
        if self.instance and self.instance.multisel2:
                try:
                    # If stored as stringified list, e.g., "['1', '2']"
                    self.initial['multisel2'] = ast.literal_eval(self.instance.multisel2)
                except Exception:
                    self.initial['multisel2'] = []
        if self.instance and self.instance.multisel1:
                try:
                    # 数据库存的 1,2变成 ['1', '2']
                    self.initial['multisel1'] = self.instance.multisel1.split(',')
                except Exception:
                    self.initial['multisel1'] = []

然后,form.html的vue data的 js中,为vue 准备页面初始值

multisel1: {{ form.multisel1.value|default:"[]"|safe }}, //不可使用引号,否则是string

 方法二

还有一种方法,就是modelform的widget特殊定制:

class Item1Form(forms.ModelForm):
    multisel1 = forms.MultipleChoiceField(
        choices=[
            (1, '教育'),
            (2, '企业管理'),
            (3, '人工智能'),
        ],
        widget=forms.CheckboxSelectMultiple,  # 可选,用于element plus
        label='技术栈1', required=False,
    )

 

这样,django的post data 进行valid时候,有效数据是 [1,3] 列表, 数据库保存的也是 [1,3] 

但是hidden 提交的value是 1,3

image

 

所以,必须修改post的数据, 把 '1,2' 转成 ['1', '2']

def Item1_update(request, pk):
    template_name = f'{APPNAME}/{MODELNAME}/form.html'
    obj = get_object_or_404(Item1, pk=pk)
    if request.method == 'POST':
        multisel1_data = request.POST.get('multisel1', '')
        if isinstance(multisel1_data, str) and ',' in multisel1_data:
            # 把 '1,2' 转成 ['1', '2']
            multisel1_list = [c.strip() for c in multisel1_data.split(',') if c.strip()]
            # 创建一个新的 QueryDict 来模拟 POST 数据
            mutable_post = request.POST.copy()
            mutable_post.setlist('multisel1', multisel1_list)
            request.POST = mutable_post

        form = Item1Form(request.POST, instance=obj)

        if form.is_valid():
            form.save()
            return redirect('app3:Item1_list')

 

 

<el-checkbox-group v-model="form.{{ name }}">      //v-model这里,必须是 javascript的数组,才能回显checked状态,通过vue里面 multisel1: {{ form.multisel1.value|default:"[]"|safe }}, 获得

{% for value, label in options %}
<el-checkbox :label="'{{ value }}'">{{ label }}</el-checkbox>
{% endfor %}
</el-checkbox-group>


 

然后,modelform的

数据库存的 1,2变成 ['1', '2']这一步就免了。

综合来说,方法一比较好

 ==========================================================================================

最终, sel1 用的element plus 方法二,  sel2是原生multicheckbox

image

 

image

 

image

 

posted @ 2025-10-11 10:36  花生与酒  阅读(4)  评论(0)    收藏  举报