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中不同进制互相转换(二进制、八进制、十进制和十六进制)
Apr 05 Python
解决python大批量读写.doc文件的问题
May 08 Python
详解Python做一个名片管理系统
Mar 14 Python
Python实现的删除重复文件或图片功能示例【去重】
Apr 23 Python
Python List列表对象内置方法实例详解
Oct 22 Python
Python使用贪婪算法解决问题
Oct 22 Python
在flask中使用python-dotenv+flask-cli自定义命令(推荐)
Jan 05 Python
Python 解析pymysql模块操作数据库的方法
Feb 18 Python
python + selenium 刷B站播放量的实例代码
Jun 12 Python
Python爬取12306车次信息代码详解
Aug 12 Python
Python面试不修改数组找出重复的数字
May 20 Python
pandas中pd.groupby()的用法详解
Jun 16 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
动态网站web开发 PHP、ASP还是ASP.NET
2006/10/09 PHP
PHP集成百度Ueditor 1.4.3
2014/11/23 PHP
利用PHP将部分内容用星号替换
2020/04/21 PHP
php使用GD2绘制几何图形示例
2017/02/15 PHP
Laravel框架中Blade模板的用法示例
2017/08/30 PHP
PHP7使用ODBC连接SQL Server2008 R2数据库示例【基于thinkPHP5.1框架】
2019/05/06 PHP
js下将阿拉伯数字每三位一逗号分隔(如:15000000转化为15,000,000)
2014/06/02 Javascript
原生js和jQuery随意改变div属性style的名称和值
2014/10/22 Javascript
jQuery实现购物车计算价格功能的方法
2015/03/25 Javascript
jQuery 中ajax异步调用的四种方式
2016/06/28 Javascript
移动端js触摸事件详解
2016/09/18 Javascript
JavaScript实现垂直向上无缝滚动特效代码
2016/11/23 Javascript
详解Angular4中路由Router类的跳转navigate
2017/06/09 Javascript
ComboBox(下拉列表框)通过url加载调用远程数据的方法
2017/08/06 Javascript
angular4模块中给标签添加背景图的实现方法
2017/09/15 Javascript
Vue.js 表单控件操作小结
2018/03/29 Javascript
JavaScript 下载svg图片为png格式
2018/06/21 Javascript
小程序自定义弹框效果
2020/11/16 Javascript
Python中的装饰器用法详解
2015/01/14 Python
Python爬虫的两套解析方法和四种爬虫实现过程
2018/07/20 Python
Python如何发布程序的详细教程
2018/10/09 Python
python批量赋值操作实例
2018/10/22 Python
python 执行文件时额外参数获取的实例
2018/12/18 Python
python tkinter实现屏保程序
2019/07/30 Python
Virtualenv 搭建 Py项目运行环境的教程详解
2020/06/22 Python
css3圆角边框和边框阴影示例
2014/05/05 HTML / CSS
详解html5 canvas常用api总结(二)--绘图API
2016/12/14 HTML / CSS
德国奢侈品网上商城:Mytheresa
2016/08/24 全球购物
英国领先的狗和宠物美容专家:Christies Direct
2017/04/03 全球购物
Booking.com英国官网:全球酒店在线预订网站
2018/04/21 全球购物
实体的生命周期
2013/08/31 面试题
中式结婚主持词
2014/03/14 职场文书
公司放假通知怎么写
2015/04/15 职场文书
2016暑期社会实践心得体会范文
2016/01/14 职场文书
英镑符号 £
2022/02/17 杂记