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 相关文章推荐
跟老齐学Python之print详解
Sep 28 Python
python实现八大排序算法(1)
Sep 14 Python
django2 快速安装指南分享
Jan 05 Python
pandas按若干个列的组合条件筛选数据的方法
Apr 11 Python
Python 利用切片从列表中取出一部分使用的方法
Feb 01 Python
详解python数据结构和算法
Apr 18 Python
python+openCV利用摄像头实现人员活动检测
Jun 22 Python
python支付宝支付示例详解
Aug 22 Python
在pycharm中显示python画的图方法
Aug 31 Python
python numpy存取文件的方式
Apr 01 Python
python 多进程队列数据处理详解
Dec 23 Python
浅谈python opencv对图像颜色通道进行加减操作溢出
Jun 03 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
PHP数据库操作面向对象的优点
2006/10/09 PHP
php strlen mb_strlen计算中英文混排字符串长度
2009/07/10 PHP
PHP-Fcgi下PHP的执行时间设置方法
2013/08/02 PHP
PHP格式化MYSQL返回float类型的方法
2016/03/30 PHP
Yii2基于Ajax自动获取表单数据的方法
2016/08/10 PHP
PHP数组编码gbk与utf8互相转换的两种方法
2016/09/01 PHP
如何使用php等比例缩放图片
2016/10/12 PHP
Git命令之分支详解
2021/03/02 PHP
jQuery 事件的命名空间简单了解
2013/11/22 Javascript
JavaScript将数据转换成整数的方法
2014/01/04 Javascript
jquery模拟alert的弹窗插件
2015/07/31 Javascript
JS+CSS实现电子商务网站导航模板效果代码
2015/09/10 Javascript
基于Turn.js 实现翻书效果实例解析
2016/06/20 Javascript
第一次接触神奇的Bootstrap
2016/10/14 Javascript
JS仿JQuery选择器功能
2017/03/08 Javascript
详解a++和++a的区别
2017/08/30 Javascript
jQuery中.attr()和.data()的区别分析
2017/09/03 jQuery
跨域解决之JSONP和CORS的详细介绍
2018/11/21 Javascript
原生js实现获取form表单数据代码实例
2019/03/27 Javascript
Vue实现表格批量审核功能实例代码
2019/05/28 Javascript
浅谈监听单选框radio改变事件(和layui中单选按钮改变事件)
2019/09/10 Javascript
在Vue里如何把网页的数据导出到Excel的方法
2020/09/30 Javascript
python获取代码运行时间的实例代码
2018/06/11 Python
python 用 xlwings 库 生成图表的操作方法
2019/12/22 Python
Python使用OpenPyXL处理Excel表格
2020/07/02 Python
html5 touch事件实现触屏页面上下滑动(一)
2016/03/10 HTML / CSS
德国的大型美妆个护电商:Flaconi
2020/06/26 全球购物
电子专业毕业生自我鉴定
2014/01/22 职场文书
制药工程专业个人求职自荐信
2014/01/25 职场文书
白酒市场营销方案
2014/02/25 职场文书
社区学习雷锋活动总结
2014/04/25 职场文书
美丽家庭事迹材料
2014/05/03 职场文书
房产授权委托书范本
2014/09/22 职场文书
导游词范文之颐和园/重庆/云台山
2019/09/10 职场文书
js中Map和Set的用法及区别实例详解
2022/02/15 Javascript
Java工作中实用的代码优化技巧分享
2022/04/21 Java/Android