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 执行字符串表达式函数(eval exec execfile)
Aug 11 Python
给Python初学者的一些编程技巧
Apr 03 Python
Python pickle模块用法实例
Apr 14 Python
python实现读Excel写入.txt的方法
Apr 29 Python
Python 爬虫之Beautiful Soup模块使用指南
Jul 05 Python
django 邮件发送模块smtp使用详解
Jul 22 Python
文件上传服务器-jupyter 中python解压及压缩方式
Apr 22 Python
Django实现内容缓存实例方法
Jun 30 Python
Python获取浏览器窗口句柄过程解析
Jul 25 Python
基于Python正确读取资源文件
Sep 14 Python
详解解Django 多对多表关系的三种创建方式
Aug 23 Python
python+pytest接口自动化之token关联登录的实现
Apr 06 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
如何删除多级目录
2006/10/09 PHP
php数组的概述及分类与声明代码演示
2013/02/26 PHP
php防注入,表单提交值转义的实现详解
2013/06/10 PHP
PHP安全上传图片的方法
2015/03/21 PHP
Yii2验证器(Validator)用法分析
2016/07/23 PHP
一些常用的JS功能函数代码
2009/06/23 Javascript
JS date对象的减法处理实现代码
2010/12/28 Javascript
JS获得URL超链接的参数值实例代码
2013/06/21 Javascript
JQuery的Ajax请求实现局部刷新的简单实例
2014/02/11 Javascript
jquery自定义表格样式
2015/11/23 Javascript
DWR中各种java方法的调用
2016/05/04 Javascript
JS中对Cookie的操作详解
2016/08/05 Javascript
利用jquery实现验证输入的是否是数字、小数,包含保留几位小数
2016/12/07 Javascript
vue2滚动条加载更多数据实现代码
2017/01/10 Javascript
nodeJs实现基于连接池连接mysql的方法示例
2018/02/10 NodeJs
nodejs爬虫初试superagent和cheerio
2018/03/05 NodeJs
详解Vue的常用指令v-if, v-for, v-show,v-else, v-bind, v-on
2018/10/12 Javascript
如何在JavaScript中优雅的提取循环内数据详解
2019/03/04 Javascript
vue前端框架—Mint UI详解(更适用于移动端)
2019/04/30 Javascript
JavaScript中的垃圾回收与内存泄漏示例详解
2019/05/02 Javascript
浅谈python 四种数值类型(int,long,float,complex)
2016/06/08 Python
python数据清洗系列之字符串处理详解
2017/02/12 Python
Python基于Matplotlib库简单绘制折线图的方法示例
2017/08/14 Python
解决pyqt5中QToolButton无法使用的问题
2019/06/21 Python
python递归函数用法详解
2020/10/26 Python
使用HTML5 Canvas API中的clip()方法裁剪区域图像
2016/03/25 HTML / CSS
瀑布模型都有哪些优缺点
2014/06/23 面试题
英文简历中的自我评价
2013/10/06 职场文书
服装设计专业毕业生推荐信
2013/11/09 职场文书
《记承天寺夜游》教学反思
2014/02/16 职场文书
毕业生实习证明
2014/09/19 职场文书
代领学位证书毕业证书委托书
2014/09/30 职场文书
优秀党务工作者先进事迹材料
2014/12/25 职场文书
珍惜时间的诗歌赏析
2019/08/23 职场文书
React Native项目框架搭建的一些心得体会
2021/05/28 Javascript
python自动化八大定位元素讲解
2021/07/09 Python