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 03 Python
python实现协同过滤推荐算法完整代码示例
Dec 15 Python
Python如何抓取天猫商品详细信息及交易记录
Feb 23 Python
Python Learning 列表的更多操作及示例代码
Aug 22 Python
Python实现查询某个目录下修改时间最新的文件示例
Aug 29 Python
谈谈Python中的while循环语句
Mar 10 Python
浅析Python 中几种字符串格式化方法及其比较
Jul 02 Python
Python如何实现后端自定义认证并实现多条件登陆
Jun 22 Python
Python之字典添加元素的几种方法
Sep 30 Python
python 通过 pybind11 使用Eigen加速代码的步骤
Dec 07 Python
用Python实现职工信息管理系统
Dec 30 Python
python爬虫如何解决图片验证码
Feb 14 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
php 日期和时间的处理-郑阿奇(续)
2011/07/04 PHP
apache配置虚拟主机的方法详解
2013/06/17 PHP
php object转数组示例
2014/01/15 PHP
Thinkphp中的curd应用实用要点
2015/01/04 PHP
PHP+Javascript实现在线拍照功能实例
2015/07/18 PHP
Yii2框架数据库简单的增删改查语法小结
2016/08/31 PHP
详解Yii2 之 生成 URL 的方法
2017/06/16 PHP
PHP CURL中传递cookie的方法步骤
2019/05/09 PHP
laravel框架 laravel-admin上传图片到oss的方法
2019/10/13 PHP
对 lightbox JS 图片控件进行了一下改造, 使其他支持复杂的图片说明
2010/03/20 Javascript
jquery下div 的resize事件示例代码
2014/03/09 Javascript
让你一句话理解闭包(简单易懂)
2016/06/03 Javascript
基于js实现二级下拉联动
2016/12/17 Javascript
详解javascript获取url信息的常见方法
2016/12/19 Javascript
微信小程序 数组中的push与concat的区别
2017/01/05 Javascript
BootStrap实现带关闭按钮功能
2017/02/15 Javascript
Node.js文件编码格式的转换的方法
2018/04/27 Javascript
详解JavaScript中关于this指向的4种情况
2019/04/18 Javascript
JS数组方法shift()、unshift()用法实例分析
2020/01/18 Javascript
vue常用高阶函数及综合实例
2021/02/25 Vue.js
Python实现抓取网页生成Excel文件的方法示例
2017/08/05 Python
Python使用cx_Oracle调用Oracle存储过程的方法示例
2017/10/07 Python
对pytorch中的梯度更新方法详解
2019/08/20 Python
django框架auth模块用法实例详解
2019/12/10 Python
Python进程间通信multiprocess代码实例
2020/03/18 Python
VICHY薇姿英国官网:全球专业敏感肌护肤领先品牌
2017/07/04 全球购物
捷克体育用品购物网站:D-sport
2017/12/28 全球购物
金属材料工程毕业生个人的自我评价
2013/11/28 职场文书
团队精神演讲稿
2013/12/31 职场文书
网上开店必备创业计划书
2014/01/26 职场文书
副董事长岗位职责
2014/04/02 职场文书
经济类毕业生求职信
2014/06/26 职场文书
法定代表人资格证明书
2015/06/18 职场文书
创业计划书之酒店
2019/08/30 职场文书
OpenCV-Python实现轮廓的特征值
2021/06/09 Python
Python+Selenium实现抖音、快手、B站、小红书、微视、百度好看视频、西瓜视频、微信视频号、搜狐视频、一点号、大风号、趣头条等短视频自动发布
2022/04/13 Python