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数据处理实战(必看篇)
Jun 11 Python
matplotlib设置legend图例代码示例
Dec 19 Python
1分钟快速生成用于网页内容提取的xslt
Feb 23 Python
Python RabbitMQ消息队列实现rpc
May 30 Python
Numpy截取指定范围内的数据方法
Nov 14 Python
在Pycharm中调试Django项目程序的操作方法
Jul 17 Python
在pandas中遍历DataFrame行的实现方法
Oct 23 Python
Pycharm小白级简单使用教程
Jan 08 Python
Python descriptor(描述符)的实现
Nov 15 Python
matplotlib之pyplot模块之标题(title()和suptitle())
Feb 22 Python
据Python爬虫不靠谱预测可知今年双十一销售额将超过6000亿元
Nov 11 Python
pd.DataFrame中的几种索引变换的实现
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
《魔兽争霸3:重制版》翻车了?你想要的我们都没有
2019/11/07 魔兽争霸
Notice: Undefined index: page in E:\PHP\test.php on line 14
2010/11/02 PHP
PHP中通过加号合并数组的一个简单方法分享
2011/01/27 PHP
php入门学习知识点八 PHP中for循环基本应用之九九乘法口绝表
2011/07/14 PHP
php对称加密算法示例
2014/05/07 PHP
php使用gettimeofday函数返回当前时间并存放在关联数组里
2015/03/19 PHP
php使用文本统计访问量的方法
2016/05/12 PHP
微信支付PHP SDK ―― 公众号支付代码详解
2016/09/13 PHP
PHP实现的MD5结合RSA签名算法实例
2017/10/07 PHP
PHP中非常有用却鲜有人知的函数集锦
2019/08/17 PHP
js 颜色选择器(兼容firefox)
2009/03/05 Javascript
jQuery对象和DOM对象使用说明
2010/06/25 Javascript
JS 实现完美include载入实现代码
2010/08/05 Javascript
nodejs事件的监听与触发的理解分析
2015/02/12 NodeJs
Javascript动画效果(1)
2016/10/11 Javascript
vue.js表格分页示例
2016/10/18 Javascript
BootStrap 下拉菜单点击之后不会出现下拉菜单(下拉菜单不弹出)的解决方案
2016/12/14 Javascript
手机端js和html5刮刮卡效果
2020/09/29 Javascript
ES6新特性一: let和const命令详解
2017/04/20 Javascript
HTML5+Canvas调用手机拍照功能实现图片上传(下)
2017/04/21 Javascript
Python解决鸡兔同笼问题的方法
2014/12/20 Python
Django后台获取前端post上传的文件方法
2018/05/28 Python
浅析python的Lambda表达式
2019/02/27 Python
python绘制已知点的坐标的直线实例
2019/07/04 Python
Django 路由控制的实现
2019/07/17 Python
详解Django中异步任务之django-celery
2020/11/05 Python
解决pytorch下出现multi-target not supported at的一种可能原因
2021/02/06 Python
纯HTML5+CSS3制作生日蛋糕代码
2016/11/16 HTML / CSS
html2canvas截图空白问题的解决
2020/03/24 HTML / CSS
英国创新设计文具、卡片和礼品包装网站:Paperchase
2018/07/14 全球购物
Ajax的优点和缺点
2014/11/21 面试题
招聘专员岗位职责
2014/03/07 职场文书
全国文明单位申报材料
2014/05/31 职场文书
全国爱眼日活动总结
2015/02/27 职场文书
千手观音观后感
2015/06/03 职场文书
Win11怎么跳过联网验机 ?Win11跳过联网验机激活教程
2022/04/05 数码科技