在啃了官网文档之后依旧不明白的同学,应该都知道,官网的文档对这方面写的挺笼统的,https://docs.djangoproject.com/zh-hans/2.1/ref/forms/widgets/#styling-widget-instances
这是官网的文档,在后面的“MultiWidget”里,有个demo
from datetime import date
from django.forms import widgets
class DateSelectorWidget(widgets.MultiWidget):
def __init__(self, attrs=None):
# create choices for days, months, years
# example below, the rest snipped for brevity.
years = [(year, year) for year in (2011, 2012, 2013)]
_widgets = (
widgets.Select(attrs=attrs, choices=days),
widgets.Select(attrs=attrs, choices=months),
widgets.Select(attrs=attrs, choices=years),
)
super().__init__(_widgets, attrs)
def decompress(self, value):
if value:
return [value.day, value.month, value.year]
return [None, None, None]
def value_from_datadict(self, data, files, name):
datelist = [
widget.value_from_datadict(data, files, name + '_%s' % i)
for i, widget in enumerate(self.widgets)]
try:
D = date(
day=int(datelist[0]),
month=int(datelist[1]),
year=int(datelist[2]),
)
except ValueError:
return ''
else:
return str(D)
先把这个demo跑起来吧
在app项目目录下,新建一个widgets.py,文件名自己起,自己觉得好就行。把上面的代码复制进去,你会发现缺少months、days数组。
在方法体中,有个decompress,就是处理这些数据的,具体怎么写,大家随便吧。我是直接弄了两个数组上去:
days = [1,2,3,4,5,6,7,8.9]
months = [1,2,3,4,5,6]
init()大家都知道是构造函数,用于初始化一些实例,变量等等。
后面的 “def value_from_datadict()"这个方法就是最后的返回数据。返回给谁呢?返回给调用它的对象啊。
在哪调用呢?
在models.py里面,先在app里建立一个forms.py文件。
#forms.py
from django import forms
from widgets import DateSelectorWidget
class testFeild(forms.CharField):
widget = DateSelectorWidget
然后再models.py里调用:
from django.db import models
from .forms import testFeild
# Create your models here.
class test(models.Model):
name = models.CharField(max_length=100)
input = testFeild()
def __str__(self):
return self.name
这样,一个多选widget就被使用上了。但是,这不是本文的重点。
像省市区、多级多选如何实现?
网上90%是同一篇文章被爬虫、人为各种转载,恶心至极。
网上都是单选,相对简单些,因为单选的话,可以直接用Django自带的select widget,像上面例子里拿样,再构造函数里直接初始化现成的对象。如果Django没有的对象怎么办?
首先,自己写一个html模板,用于自定义用户输入界面,包括通过js获取输入的结果,保证js能拿到这个结果。
然后,在刚才新建的widgets.py文件里,新建一个类:
class SelectAreaFeild(widgets.Widget):
template_name='home.html'
def get_context(self, name, value, attrs=None):
return {
'widget':{
'name':name,
'value':value,
}
}
#发送自定义模板
def render(self, name, value, attrs=None, renderer=None):
context = self.get_context(name,value,attrs)
output = loader.render_to_string(self.template_name,
{'widget_name': name, })
return mark_safe(output)
#格式化value
def format_value(self, value):
print(value)
def value_from_datadict(self, data, files, name):
return data.get(name, None)
把你的html文件放到app/templates目录下,用template_name='home.html' 这句引用。
def render() 这个方法的作用就是渲染模板,可以直接输出html语句。
get_context()获取上下文参数,这里把name,传递到html中,命名为:widget_name
在html中,你的自定义的表单,可以花里胡哨,但是要传值给Django,必须定义一个隐藏的input控件:
<input type="hidden" name={{ widget_name }} v-model="mod_o">
v-model="mod_o" 这句的意思是赋值,把js获取到的值赋值给input,这样就可以使用了。
注意:
上述的方法,在models.py中是无法直接调用的,在models.py中定义成textFeild或者CharFeild,然后在admin.py
把字段指定widget。
from django.contrib import admin
from django.db import models as md
@admin.register(models.test)
class testAdmin(admin.ModelAdmin):
list_display = ('name','input')
formfield_overrides = {md.TextField:{'widget':SelectAreaFeild}}
网友评论