Q: 如何自定义字段在页面上的显示效果. 比如使用自己特定的js控件
A:
- 可以自定义widgets
- 自定义form将widgets设置到form的对应的field上
- 在OptionClass里设置form
- 将OptionClass设置到xadmin上
举例:
在页面上显示tags字段时候想使用select2.js这个模板来实现这样的效果. 也就是多选的select框, 选中的放在上面作为标签, 可以叉掉.
models.py
首先models.py里面tags字段使用了postgres才有的ArrayField来存储多个选项
from django.contrib.postgres.fields import ArrayField
from django.db import models
class Case(models.Model):
tags = ArrayField(models.CharField(max_length=200), null=True, blank=True)
widgets.py
要将前端接收到的tags[]字段修改成tag才能保存
import os
import pandas as pd
from django import forms
from django.utils.safestring import mark_safe
pwd = os.path.abspath(os.path.dirname(__file__))
# 加载tag标签的所有值
df = pd.read_csv(os.path.join(pwd, "hunting_rules_db.tags_list.csv"))
tags_list = list(df["name"].values)
# 要注入到页面上的js
JS = '''
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/css/select2.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/js/select2.min.js"></script>
<script>
$(function () {
$('.js-example-basic-multiple').select2();
});
</script>
'''
class Select2Widget(forms.SelectMultiple):
# 要处理多选的字段
array_field_list = ['tags']
def value_from_datadict(self, data, files, name):
"""
处理前端是tags[]后端tag
:param data:
:param files:
:param name:
:return:
"""
if name in self.array_field_list:
name += '[]'
try:
getter = data.getlist
except AttributeError:
getter = data.get
return getter(name)
def render(self, name, value, attrs=None, renderer=None):
'''
关键方法
:param name:
:param value:
:param attrs:
:return:
'''
output = [JS]
output.append('<select class="js-example-basic-multiple" name="tags[]" multiple="multiple">')
tags_list = self.get_tags_list()
if value is None:
value = []
for tag in tags_list:
if tag in value:
selected = ' selected="selected"'
else:
selected = ''
output.append(f'<option value="{tag}" {selected}>{tag}</option>')
output.append('</select>')
return mark_safe('\n'.join(output))
def get_tags_list(self):
return tags_list
adminx.py
from django.contrib.postgres.forms import SimpleArrayField
from django.forms import ModelForm, CharField
import xadmin
from xadmin import views
from .models import Case, Ioc, FileAttachment
from .widgets import Select2Widget
#自定义的widget注册到form中
class CaseForm(ModelForm):
tags = SimpleArrayField(CharField(), widget=Select2Widget, required=False)
# 自定义的form注册到OptionClass中
class BaseAdmin:
list_display = ["name", "happen_datetime", "TLP", "tags", "len_ioc", "len_file", "update_user", "update_time"]
form = CaseForm