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的Flask框架开发环境的一些技巧总结
Jul 12 Python
Python实现使用卷积提取图片轮廓功能示例
May 12 Python
如何利用Anaconda配置简单的Python环境
Jun 24 Python
python把转列表为集合的方法
Jun 28 Python
详解Python对JSON中的特殊类型进行Encoder
Jul 15 Python
TensorFlow——Checkpoint为模型添加检查点的实例
Jan 21 Python
基于Pytorch SSD模型分析
Feb 18 Python
Django单元测试中Fixtures用法详解
Feb 25 Python
python求前n个阶乘的和实例
Apr 02 Python
使用Python三角函数公式计算三角形的夹角案例
Apr 15 Python
python+adb+monkey实现Rom稳定性测试详解
Apr 23 Python
python3中的logging记录日志实现过程及封装成类的操作
May 12 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
造势之举?韩国总统候选人发布《星际争霸》地图
2017/04/22 星际争霸
php对数组排序代码分享
2014/02/24 PHP
php实现读取手机客户端浏览器的类
2015/01/09 PHP
PHP实现简单的新闻发布系统实例
2015/07/28 PHP
PHP实现在数据库百万条数据中随机获取20条记录的方法
2017/04/19 PHP
php实现数字补零的方法总结
2018/09/12 PHP
[原创]PHP global全局变量经典应用与注意事项分析【附$GLOBALS用法对比】
2019/07/12 PHP
PHP页面静态化――纯静态与伪静态用法详解
2020/06/05 PHP
接收键盘指令的脚本
2006/06/26 Javascript
JavaScript中Array 对象相关的几个方法
2006/12/22 Javascript
jQuery lazyload 的重复加载错误以及修复方法
2010/11/19 Javascript
js弹出层(jQuery插件形式附带reLoad功能)
2013/04/12 Javascript
JS获取图片lowsrc属性的方法
2015/04/01 Javascript
将JavaScript的jQuery库中表单转化为JSON对象的方法
2015/11/17 Javascript
jQuery模拟360浏览器切屏效果幻灯片(附demo源码下载)
2016/01/29 Javascript
Bootstrap 折叠(Collapse)插件用法实例详解
2016/06/01 Javascript
vue-cli中打包图片路径错误的解决方法
2017/10/26 Javascript
详解超简单的react服务器渲染(ssr)入坑指南
2019/02/28 Javascript
js判断在哪个浏览器打开项目的方法
2020/01/21 Javascript
Vue解析剪切板图片并实现发送功能
2020/02/04 Javascript
原生JS实现记忆翻牌游戏
2020/07/31 Javascript
Vue中component标签解决项目组件化操作
2020/09/04 Javascript
在项目vue中使用echarts的操作步骤
2020/09/07 Javascript
[04:44]DOTA2西游记战队视频彩蛋流出 师徒开黑巧遇林书豪
2016/08/03 DOTA
使用Python中PDB模块中的命令来调试Python代码的教程
2015/03/30 Python
python3+PyQt5实现自定义分数滑块部件
2018/04/24 Python
Django使用详解:ORM 的反向查找(related_name)
2018/05/30 Python
python使用turtle库绘制时钟
2020/03/25 Python
Django教程笔记之中间件middleware详解
2018/08/01 Python
Python numpy.zero() 初始化矩阵实例
2019/11/27 Python
带你认识HTML5中的WebSocket
2015/05/22 HTML / CSS
We Fashion荷兰:一家国际时装公司
2018/04/18 全球购物
依法行政工作汇报
2014/10/28 职场文书
毕业论文答辩演讲稿
2015/06/23 职场文书
python使用PySimpleGUI设置进度条及控件使用
2021/06/10 Python
撤回我也能看到!教你用Python制作微信防撤回脚本
2021/06/11 Python