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 httplib模块使用实例
Apr 11 Python
Django 导出 Excel 代码的实例详解
Aug 11 Python
python多进程实现进程间通信实例
Nov 24 Python
python thrift搭建服务端和客户端测试程序
Jan 17 Python
Python读取properties配置文件操作示例
Mar 29 Python
Python调用服务接口的实例
Jan 03 Python
Python子类继承父类构造函数详解
Feb 19 Python
wxPython之wx.DC绘制形状
Nov 19 Python
Python递归求出列表(包括列表中的子列表)的最大值实例
Feb 27 Python
Django之腾讯云短信的实现
Jun 12 Python
详解pandas获取Dataframe元素值的几种方法
Jun 14 Python
Python colormap库的安装和使用详情
Oct 06 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
一个连接两个不同MYSQL数据库的PHP程序
2006/10/09 PHP
COM in PHP (winows only)
2006/10/09 PHP
Thinkphp实现自动验证和自动完成
2015/12/19 PHP
php变量与JS变量实现不通过跳转直接交互的方法
2017/08/25 PHP
基于laravel belongsTo使用详解
2019/10/18 PHP
JavaScript类和继承 constructor属性
2010/03/04 Javascript
Node.js:Windows7下搭建的Node.js服务(来玩玩服务器端的javascript吧,这可不是前端js插件)
2011/06/27 Javascript
fancybox modal的完美解决(右上的X)
2012/10/30 Javascript
js怎么终止程序return不行换jfslk
2013/05/30 Javascript
利用js实现遮罩以及弹出可移动登录窗口
2013/07/08 Javascript
jquery移除、绑定、触发元素事件使用示例详解
2014/04/10 Javascript
jQuery filter函数使用方法
2014/05/19 Javascript
zepto.js中tap事件阻止冒泡的实现方法
2015/02/12 Javascript
jquery Validation表单验证使用详解
2020/09/12 Javascript
jQuery实现发送验证码并60秒倒计时功能
2016/11/25 Javascript
js自制图片放大镜功能
2017/01/24 Javascript
React手稿之 React-Saga的详解
2018/11/12 Javascript
mpvue微信小程序开发之实现一个弹幕评论
2019/11/24 Javascript
python嵌套字典比较值与取值的实现示例
2017/11/03 Python
Python实现屏幕截图的两种方式
2018/02/05 Python
详解python OpenCV学习笔记之直方图均衡化
2018/02/08 Python
Python检查ping终端的方法
2019/01/26 Python
Python类中方法getitem和getattr详解
2019/08/30 Python
Django实现文件上传下载
2019/10/06 Python
Pytorch自己加载单通道图片用作数据集训练的实例
2020/01/18 Python
Python3读写Excel文件(使用xlrd,xlsxwriter,openpyxl3种方式读写实例与优劣)
2020/02/13 Python
Java如何基于wsimport调用wcf接口
2020/06/17 Python
CSS3提交意见输入框样式代码
2014/10/30 HTML / CSS
html5应用缓存_动力节点Java学院整理
2017/07/13 HTML / CSS
HTML5头部标签的一些常用信息小结
2016/10/23 HTML / CSS
ASOS西班牙官网:英国在线时尚和美容零售商
2020/01/10 全球购物
婚纱摄影师求职信
2014/03/07 职场文书
经典英文广告词
2014/03/18 职场文书
小学综合实践活动总结
2014/07/07 职场文书
运动会新闻报道稿
2015/07/22 职场文书
python面向对象版学生信息管理系统
2021/06/24 Python