Django 表单模型选择框如何使用分组


Posted in Python onMay 16, 2019

起步

Django 表单中有两种字段类型可以使用选择框: ChoiceFieldModelChoiceField

对于 ChoiceField 的基本使用是:

class ExpenseForm(forms.Form):
  CHOICES = (
    (11, 'Credit Card'),
    (12, 'Student Loans'),
    (13, 'Taxes'),
    (21, 'Books'),
    (22, 'Games'),
    (31, 'Groceries'),
    (32, 'Restaurants'),
  )
  date = forms.DateField()
  category = forms.ChoiceField(choices=CHOICES)

它能渲染出:

Django 表单模型选择框如何使用分组

使用分组下拉框

还可以使用如下方式生成 <optgourp> 标签:

class ExpenseForm(forms.Form):
  CHOICES = (
    ('Debt', (
      (11, 'Credit Card'),
      (12, 'Student Loans'),
      (13, 'Taxes'),
    )),
    ('Entertainment', (
      (21, 'Books'),
      (22, 'Games'),
    )),
    ('Everyday', (
      (31, 'Groceries'),
      (32, 'Restaurants'),
    )),
  )
  date = forms.DateField()
  category = forms.ChoiceField(choices=CHOICES)

能够渲染为:

Django 表单模型选择框如何使用分组

分组模型下拉框

如果使用的是 ModelChoiceField ,那抱歉,Django本身没有提供解决方案。

在 https://code.djangoproject.com/ticket/27331 中提供了一个很好的解决方案。

首先为需要分类的类型创建模型,在另一个模型中用外键关联它:

from django.db import models

class Category(models.Model):
  name = models.CharField(max_length=30)
  parent = models.ForeignKey('Category', on_delete=models.CASCADE, null=True)

  def __str__(self):
    return self.name

class Expense(models.Model):
  amount = models.DecimalField(max_digits=10, decimal_places=2)
  date = models.DateField()
  category = models.ForeignKey(Category, on_delete=models.CASCADE)

  def __str__(self):
    return self.amount

其次,创建一个新的表单 Field 类型:

from functools import partial
from itertools import groupby
from operator import attrgetter

from django.forms.models import ModelChoiceIterator, ModelChoiceField

class GroupedModelChoiceIterator(ModelChoiceIterator):
  def __init__(self, field, groupby):
    self.groupby = groupby
    super().__init__(field)

  def __iter__(self):
    if self.field.empty_label is not None:
      yield ("", self.field.empty_label)
    queryset = self.queryset
    # Can't use iterator() when queryset uses prefetch_related()
    if not queryset._prefetch_related_lookups:
      queryset = queryset.iterator()
    for group, objs in groupby(queryset, self.groupby):
      yield (group, [self.choice(obj) for obj in objs])

class GroupedModelChoiceField(ModelChoiceField):
  def __init__(self, *args, choices_groupby, **kwargs):
    if isinstance(choices_groupby, str):
      choices_groupby = attrgetter(choices_groupby)
    elif not callable(choices_groupby):
      raise TypeError('choices_groupby must either be a str or a callable accepting a single argument')
    self.iterator = partial(GroupedModelChoiceIterator, groupby=choices_groupby)
    super().__init__(*args, **kwargs)

最后,在表单中可以如下进行使用:

from django import forms
from .fields import GroupedModelChoiceField
from .models import Category, Expense

class ExpenseForm(forms.ModelForm):
  category = GroupedModelChoiceField(
    queryset=Category.objects.exclude(parent=None), 
    choices_groupby='parent'
  )

  class Meta:
    model = Expense
    fields = ('amount', 'date', 'category')

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Django中使用group_by的方法
May 26 Python
浅谈插入排序算法在Python程序中的实现及简单改进
May 04 Python
一道python走迷宫算法题
Jan 22 Python
Python 使用PIL中的resize进行缩放的实例讲解
Aug 03 Python
详解Numpy中的广播原则/机制
Sep 20 Python
CentOS6.9 Python环境配置(python2.7、pip、virtualenv)
May 06 Python
Pandas_cum累积计算和rolling滚动计算的用法详解
Jul 04 Python
python实现简易学生信息管理系统
Apr 05 Python
TFRecord格式存储数据与队列读取实例
Jan 21 Python
Pycharm激活码激活两种快速方式(附最新激活码和插件)
Mar 12 Python
解决pycharm编辑区显示yaml文件层级结构遇中文乱码问题
Apr 27 Python
linux centos 7.x 安装 python3.x 替换 python2.x的过程解析
Dec 14 Python
详解pandas如何去掉、过滤数据集中的某些值或者某些行?
May 15 #Python
详解Python列表赋值复制深拷贝及5种浅拷贝
May 15 #Python
Python 20行简单实现有道在线翻译的详解
May 15 #Python
Python中的字符串切片(截取字符串)的详解
May 15 #Python
python3 property装饰器实现原理与用法示例
May 15 #Python
详解Python下载图片并保存本地的两种方式
May 15 #Python
Python常用模块之requests模块用法分析
May 15 #Python
You might like
攻克CakePHP系列二 表单数据显示
2008/10/22 PHP
php不写闭合标签的好处
2014/03/04 PHP
PHP计算数组中值的和与乘积的方法(array_sum与array_product函数)
2016/04/01 PHP
PHP模板引擎Smarty中的保留变量用法分析
2016/04/11 PHP
js监听表单value的修改同步问题,跨浏览器支持
2009/12/31 Javascript
javascript 事件查询综合 推荐收藏
2010/03/10 Javascript
js DOM 元素ID就是全局变量
2012/09/20 Javascript
JS实现可直接显示网页代码运行效果的HTML代码预览功能实例
2015/08/06 Javascript
JavaScript实现的简单烟花特效代码
2015/10/20 Javascript
解决angular的$http.post()提交数据时后台接收不到参数值问题的方法
2015/12/10 Javascript
详解AngularJS跨页面传值(ui-router)
2017/08/23 Javascript
vue+socket.io+express+mongodb 实现简易多房间在线群聊示例
2017/10/21 Javascript
JavaScript闭包与作用域链实例分析
2019/01/21 Javascript
Weex开发之地图篇的具体使用
2019/10/16 Javascript
基于JavaScript实现留言板功能
2020/03/16 Javascript
Python递归遍历列表及输出的实现方法
2015/05/19 Python
python实现网站的模拟登录
2016/01/04 Python
Python中asyncore异步模块的用法及实现httpclient的实例
2016/06/28 Python
Python中属性和描述符的正确使用
2016/08/23 Python
深入理解NumPy简明教程---数组1
2016/12/17 Python
Python机器学习之K-Means聚类实现详解
2018/02/22 Python
Python将list中的string批量转化成int/float的方法
2018/06/26 Python
python查找指定文件夹下所有文件并按修改时间倒序排列的方法
2018/10/21 Python
python程序快速缩进多行代码方法总结
2019/06/23 Python
python2 中 unicode 和 str 之间的转换及与python3 str 的区别
2019/07/25 Python
django多文件上传,form提交,多对多外键保存的实例
2019/08/06 Python
python中实现词云图的示例
2020/12/19 Python
基于html和CSS3制作酷炫的导航栏
2015/09/23 HTML / CSS
css3实现可拖动的魔方3d效果
2019/05/07 HTML / CSS
德国运动鞋网上商店:Afew Store
2018/01/05 全球购物
英国时尚和家居用品零售商:Matalan
2021/02/28 全球购物
党员廉洁自律承诺书
2014/05/26 职场文书
学生会竞选演讲稿怎么写
2014/08/26 职场文书
员工教育培训协议书
2014/09/27 职场文书
村官2015年度工作总结
2015/10/14 职场文书
CSS Transition通过改变Height实现展开收起元素
2021/08/07 HTML / CSS