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之Python文档
Oct 10 Python
python搜索指定目录的方法
Apr 29 Python
Python使用CMD模块更优雅的运行脚本
May 11 Python
Django框架视图介绍与使用详解
Jul 18 Python
Python解压 rar、zip、tar文件的方法
Nov 19 Python
python中提高pip install速度
Feb 14 Python
解决jupyter notebook 前面书写后面内容消失的问题
Apr 13 Python
python3通过udp实现组播数据的发送和接收操作
May 05 Python
浅谈pytorch中torch.max和F.softmax函数的维度解释
Jun 28 Python
Python 通过爬虫实现GitHub网页的模拟登录的示例代码
Aug 17 Python
python中remove函数的踩坑记录
Jan 04 Python
python某漫画app逆向
Mar 31 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
PHP5/ZendEngine2的改进
2006/10/09 PHP
PHP 采集心得技巧
2009/05/15 PHP
php面向对象全攻略 (十七) 自动加载类
2009/09/30 PHP
PHP中UNIX时间戳和日期间的转换与计算实例
2014/11/19 PHP
Laravel如何友好的修改.env配置文件详解
2017/06/07 PHP
PHP定义字符串的四种方式详解
2018/02/06 PHP
优化Jquery,提升网页加载速度
2013/11/14 Javascript
JS控制图片翻转示例代码(兼容firefox,ie,chrome)
2013/12/19 Javascript
详解Node.js:events事件模块
2016/11/24 Javascript
vue.js获取数据库数据实例代码
2017/05/26 Javascript
js禁止表单重复提交
2017/08/29 Javascript
解决vue无法设置滚动位置的问题
2018/10/07 Javascript
vue自定义指令用法经典实例小结
2019/03/16 Javascript
Angular中innerHTML标签的样式不起作用的原因解析
2019/06/18 Javascript
vue实现简易图片左右旋转,上一张,下一张组件案例
2020/07/31 Javascript
vue单元格多列合并的实现
2020/11/26 Vue.js
[46:27]DOTA2上海特级锦标赛主赛事日 - 1 胜者组第一轮#2LGD VS MVP.Phx第一局
2016/03/02 DOTA
[01:20:06]TNC vs VG 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
python中的多线程实例教程
2014/08/27 Python
Python与Java间Socket通信实例代码
2017/03/06 Python
pygame库实现移动底座弹球小游戏
2020/04/14 Python
Abbacino官网:包、钱包和女士配饰
2019/04/15 全球购物
高中考试作弊检讨书
2014/01/14 职场文书
工会主席事迹材料
2014/06/03 职场文书
2014年创先争优工作总结
2014/12/11 职场文书
2015学习委员工作总结范文
2015/04/03 职场文书
小学生勤俭节约倡议书
2015/04/29 职场文书
2015年节能减排工作总结
2015/05/14 职场文书
怒海潜将观后感
2015/06/11 职场文书
办公室日常管理制度
2015/08/04 职场文书
2015中秋祝酒词
2015/08/12 职场文书
详解MySQL 联合查询优化机制
2021/05/10 MySQL
SpringBoot中获取profile的方法详解
2022/04/08 Java/Android
PostgreSQL数据库去除重复数据和运算符的基本查询操作
2022/04/12 PostgreSQL
使用Redis实现分布式锁的方法
2022/06/16 Redis