美文网首页
Django自定义小部件(widget)

Django自定义小部件(widget)

作者: 黑色汪汪汪 | 来源:发表于2018-09-04 10:21 被阅读0次

    在啃了官网文档之后依旧不明白的同学,应该都知道,官网的文档对这方面写的挺笼统的,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}}
    
    
    
    
    
    

    相关文章

      网友评论

          本文标题:Django自定义小部件(widget)

          本文链接:https://www.haomeiwen.com/subject/hbzwwftx.html