Python中Django 后台自定义表单控件


Posted in Python onMarch 28, 2017

在 django 中我们可以在 admin.py 中添加 ModelAdmin,这样就能很方便地在后台进行增删改查的操作。然而,对应 Model 生成的表单,并不友好,我们希望能像前端开发一样做出各种类型的控件,这就得对其后台的表单进行自定义。

其实 django 已经为我们提供了一些可用的表单控件,比如:多选框、单选按钮等,下面就以单选按钮为例:

# forms.py
from django import forms
from .models import MyModel

class MyForm(forms.ModelForm):
  xxx = forms.ChoiceField(choices=[...], widget=forms.RadioSelect())

  class Meta:
    model = MyModel
    fields = ['id', 'xxx']


# admin.py
from django.contrib import admin
from .models import MyModel
from .forms import MyForm

class MyAdmin(admin.ModelAdmin):
  form = MyForm
  # ...省略若干代码

admin.site.register(MyModel, MyAdmin)

先自定义一个 MyForm,在里面为字段添加控件,widget 用来指定控件的类型,choices 指定可选列表,再在 MyAdmin 中的 form 指定为自定义表单即可。

在 django 中已经提供了很多 widget(控件),然而这些还远远满足不了我们的需求,这就需要我们去自定义,下面就以一个 ACE 插件 (ACE 是一个独立的 JavaScript 编写的基于 Web 的代码编辑器)为例,说说怎么自定义 widget:

#coding: utf-8
from django import forms
from django.utils.html import format_html
from django.forms.utils import flatatt
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe


ACE_RENDER = '''
<script src="/static/js/jquery-1.11.2.min.js"></script>
<script src="/static/js/ace/ace.js"></script>
<script>
  $(function () {
    var textarea = $('textarea');
    var editDiv = $('<div>', {
      position: 'absolute',
      width: textarea.width(),
      height: textarea.height(),
      'class': textarea.attr('class')
    }).insertBefore(textarea);

    textarea.css('display', 'none');

    var editor = ace.edit(editDiv[0]);
    editor.getSession().setValue(textarea.val());
    editor.getSession().setMode("ace/mode/%s");
    editor.setTheme("ace/theme/%s");

    textarea.closest('form').submit(function () {
      textarea.val(editor.getSession().getValue());
    });
  });
</script>
'''

class AceWidget(forms.Textarea):
  def __init__(self, mode="", theme="", attrs=None):
    '''
    为了能在调用的时候自定义代码类型和样式
    :param mode:
    :param theme:
    :param attrs:
    :return:
    '''
    super(AceWidget, self).__init__(attrs)
    self.mode = mode
    self.theme = theme

  def render(self, name, value, attrs=None):
    '''
    关键方法
    :param name:
    :param value:
    :param attrs:
    :return:
    '''
    if value is None:
      value = ''
    final_attrs = self.build_attrs(attrs, name=name)
    output = [format_html('<textarea{}>\r\n{}</textarea>', flatatt(final_attrs), force_text(value))]
    current_ace_render = ACE_RENDER %(self.mode, self.theme)
    output.append(current_ace_render)
    return mark_safe('\n'.join(output))

主要就是自定义的 widget 要继承自 django 的 widget,然后重写 render 方法,在这个方法中,对新的控件进行包装。

forms.py 中将自定义的控件 AceWidget 引入:

#coding: utf-8
from django import forms
from .models import Code
from widgets import AceWidget


class CodeForm(forms.ModelForm):
  code = forms.CharField(label='源码', widget=AceWidget(attrs={'cols': '100', 'rows': '20'}, mode="python", theme="monokai"))

  class Meta:
    model = Code
    fields = ['title', 'code']

需要注意的是:在这里使用的 mode="python", theme="monokai" 对应的文件 mode-python.js theme-monokai.js 一定要在 /static/js/ace 目录下。

效果图

Python中Django 后台自定义表单控件

附录:

models.py:

#coding:utf-8
from django.db import models


class Code(models.Model):
  title = models.CharField('标题', max_length=50, unique=True)
  code = models.TextField('源码')

  class Meta:
    db_table = 'code'
    verbose_name = verbose_name_plural = '代码'

  def __unicode__(self):
    return self.title

admin.py:

from django.contrib import admin
from .models import Code
from .forms import CodeForm


class CodeAdmin(admin.ModelAdmin):
  form = CodeForm
  list_display = ['id', 'title']

admin.site.register(Code, CodeAdmin)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python的类实例属性访问规则探讨
Jan 30 Python
python 实现一个贴吧图片爬虫的示例
Oct 12 Python
Python3.6简单反射操作示例
Jun 14 Python
Python3中在Anaconda环境下安装basemap包
Oct 21 Python
python+os根据文件名自动生成文本
Mar 21 Python
Python实现FM算法解析
Jun 18 Python
Python实现简单的列表冒泡排序和反转列表操作示例
Jul 10 Python
Python在OpenCV里实现极坐标变换功能
Sep 02 Python
python代码打印100-999之间的回文数示例
Nov 24 Python
python连接PostgreSQL过程解析
Feb 09 Python
python中zip()函数遍历多个列表方法
Feb 18 Python
windows上安装Anaconda和python的教程详解
Mar 28 #Python
利用python爬取软考试题之ip自动代理
Mar 28 #Python
详解python调度框架APScheduler使用
Mar 28 #Python
Python中is与==判断的区别
Mar 28 #Python
Python利用Beautiful Soup模块创建对象详解
Mar 27 #Python
Python利用Beautiful Soup模块修改内容方法示例
Mar 27 #Python
python递归查询菜单并转换成json实例
Mar 27 #Python
You might like
PHP 将逗号、空格、回车分隔的字符串转换为数组的函数
2012/06/07 PHP
PHP轻量级数据库操作类Medoo增加、删除、修改、查询例子
2014/07/04 PHP
PHP 获取ip地址代码汇总
2015/07/05 PHP
详解PHP中foreach的用法和实例
2016/10/25 PHP
php将print_r处理后的数据还原为原始数组的解决方法
2016/11/02 PHP
jQuery源码分析-03构造jQuery对象-源码结构和核心函数
2011/11/14 Javascript
js 判断js函数、变量是否存在的简单示例代码
2014/03/04 Javascript
jQueryMobile之Helloworld与页面切换的方法
2015/02/04 Javascript
JS组件系列之Bootstrap table表格组件神器【二、父子表和行列调序】
2016/05/10 Javascript
JCrop+ajaxUpload 图像切割上传的实例代码
2016/07/20 Javascript
jQuery设置聚焦并使光标位置在文字最后的实现方法
2016/08/02 Javascript
Javascript 事件冒泡机制详细介绍
2016/10/10 Javascript
jQuery轮播图实例详解
2018/08/15 jQuery
优雅的在React项目中使用Redux的方法
2018/11/10 Javascript
PostgreSQL Node.js实现函数计算方法示例
2019/02/12 Javascript
微信小程序实现点击空白隐藏的方法示例
2019/08/13 Javascript
layui动态渲染生成select的option值方法
2019/09/23 Javascript
JS面向对象之多选框实现
2020/01/17 Javascript
微信小程序实现上拉加载功能示例【加载更多数据/触底加载/点击加载更多数据】
2020/05/29 Javascript
vue Treeselect 树形下拉框:获取选中节点的ids和lables操作
2020/08/15 Javascript
vue 根据选择的月份动态展示日期对应的星期几
2021/02/06 Vue.js
Python中for循环控制语句用法实例
2015/06/02 Python
python实现支持目录FTP上传下载文件的方法
2015/06/03 Python
全面解析Python的While循环语句的使用方法
2015/10/13 Python
用python写的一个wordpress的采集程序
2016/02/27 Python
python访问抓取网页常用命令总结
2017/04/11 Python
python3实现多线程聊天室
2018/12/12 Python
Django之提交表单与前后端交互的方法
2019/07/19 Python
python爬虫 execjs安装配置及使用
2019/07/30 Python
css3制作彩色边线3d立体按钮的示例(css3按钮)
2014/05/06 HTML / CSS
介绍Java的内部类
2012/10/27 面试题
公司承诺书怎么写
2014/05/24 职场文书
应聘会计求职信
2014/06/11 职场文书
2015年教师新年寄语
2014/12/08 职场文书
英文感谢信范文
2015/01/21 职场文书
物业工程部岗位职责
2015/02/11 职场文书