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种类用法=======================
方法一
为了普通 post提交而隐藏的 input 如下
所以, modelform的widget不必特殊定制,就是默认charfield,则数据库里面保存的是 1,3
但 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
所以,必须修改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