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 Celery定时任务的示例
Mar 13 Python
pyhton列表转换为数组的实例
Apr 04 Python
解决python3 json数据包含中文的读写问题
May 10 Python
python将字母转化为数字实例方法
Oct 04 Python
你可能不知道的Python 技巧小结
Jan 29 Python
Python多线程threading join和守护线程setDeamon原理详解
Mar 18 Python
在python里创建一个任务(Task)实例
Apr 25 Python
如何理解Python中的变量
Jun 01 Python
Python fileinput模块如何逐行读取多个文件
Oct 05 Python
Python+OpenCV图像处理—— 色彩空间转换
Oct 22 Python
Django实现WebSocket在线聊天室功能(channels库)
Sep 25 Python
4种方法python批量修改替换列表中元素
Apr 07 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代码(一个表一个文件)
2010/05/28 PHP
使用PHP把HTML生成PDF文件的几个开源项目介绍
2014/11/17 PHP
PHP+Mysql基于事务处理实现转账功能的方法
2015/07/08 PHP
使用URL传输SESSION信息
2015/07/14 PHP
Js 获取HTML DOM节点元素的方法小结
2009/04/24 Javascript
jquery中get,post和ajax方法的使用小结
2014/02/04 Javascript
jQuery中toggleClass()方法用法实例
2015/01/05 Javascript
Redis基本知识、安装、部署、配置笔记
2015/03/05 Javascript
JS输出空格的简单实现方法
2016/09/08 Javascript
JS添加或修改控件的样式(Class)实现方法
2016/10/15 Javascript
详解ES6中的let命令
2020/04/05 Javascript
详解JS异步加载的三种方式
2017/03/07 Javascript
详解vue-resource promise兼容性问题
2017/06/20 Javascript
快速解决brew安装特定版本flow的问题
2018/05/17 Javascript
ajaxfileupload.js实现上传文件功能
2019/04/19 Javascript
解决vue语法会有延迟加载显现{{xxx}}的问题
2019/11/14 Javascript
webpack 动态批量加载文件的实现方法
2020/03/19 Javascript
[02:42]2014DOTA2国际邀请赛 三冰专访:我会打到Ti20
2014/07/13 DOTA
[01:08:29]DOTA2-DPC中国联赛定级赛 RNG vs Aster BO3第一场 1月9日
2021/03/11 DOTA
通过Python爬虫代理IP快速增加博客阅读量
2016/12/14 Python
django ajax json的实例代码
2018/05/29 Python
对python中的try、except、finally 执行顺序详解
2019/02/18 Python
Python+OpenCV 实现图片无损旋转90°且无黑边
2019/12/12 Python
HTML5 微格式和相关的属性名称
2010/02/10 HTML / CSS
使用jquery实现HTML5响应式导航菜单教程
2014/04/02 HTML / CSS
StubHub澳大利亚:购买或出售您的门票
2019/08/01 全球购物
SQL Server的固定数据库角色都有哪些?对应的服务器权限有哪些?
2013/05/18 面试题
通信工程专业个人找工作求职信范文
2013/09/21 职场文书
法学专业个人求职信
2013/09/26 职场文书
高中运动会广播稿
2014/01/21 职场文书
体育教学随笔感言
2014/02/24 职场文书
物业管理专业自荐信
2014/07/01 职场文书
小班教师个人总结
2015/02/05 职场文书
出国留学自荐信模板
2015/03/06 职场文书
爱国主义教育主题班会
2015/08/13 职场文书
小学英语教学经验交流材料
2015/11/02 职场文书