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装饰器基础详解
Mar 09 Python
Python中动态创建类实例的方法
Mar 24 Python
Python元组拆包和具名元组解析实例详解
Mar 26 Python
Python实现数据可视化看如何监控你的爬虫状态【推荐】
Aug 10 Python
浅谈python3.x pool.map()方法的实质
Jan 16 Python
python使用mitmproxy抓取浏览器请求的方法
Jul 02 Python
python中将两组数据放在一起按照某一固定顺序shuffle的实例
Jul 15 Python
浅谈pytorch grad_fn以及权重梯度不更新的问题
Aug 20 Python
python Dijkstra算法实现最短路径问题的方法
Sep 19 Python
Python FtpLib模块应用操作详解
Dec 12 Python
python字符串常用方法及文件简单读写的操作方法
Mar 04 Python
Python 输出详细的异常信息(traceback)方式
Apr 08 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
kindeditor 加入七牛云上传的实例讲解
2017/11/12 PHP
php 比较获取两个数组相同和不同元素的例子(交集和差集)
2019/10/18 PHP
共享自己写一个框架DreamScript
2007/01/20 Javascript
使用jQuery同时控制四张图片的伸缩实现代码
2013/04/19 Javascript
JavaScript 中的日期和时间及表示标准介绍
2013/08/21 Javascript
javascript获取设置div的高度和宽度兼容任何浏览器
2013/09/22 Javascript
js 数组操作之pop,push,unshift,splice,shift
2014/01/29 Javascript
Asp.Net alert弹出提示信息的几种方法总结
2014/01/29 Javascript
js调试系列 控制台命令行API使用方法
2014/06/18 Javascript
chrome调试javascript详解
2015/10/21 Javascript
JavaScript截取指定长度字符串点击可以展开全部代码
2015/12/04 Javascript
JS模仿腾讯图片站的图片翻页按钮效果完整实例
2016/06/21 Javascript
AngularJS 单元测试(二)详解
2016/09/21 Javascript
JS 在数组指定位置插入/删除数据的方法
2017/01/12 Javascript
JavaScript数组和对象的复制
2017/03/21 Javascript
angularjs实现猜数字大小功能
2020/05/20 Javascript
Vue2.0仿饿了么webapp单页面应用详细步骤
2018/07/08 Javascript
解决vue的过渡动画无法正常实现问题
2019/10/31 Javascript
[09:22]2014DOTA2西雅图国际邀请赛 主赛事第二日TOPPLAY
2014/07/21 DOTA
python入门之语句(if语句、while语句、for语句)
2015/01/19 Python
Python中计算三角函数之cos()方法的使用简介
2015/05/15 Python
Python实现的Excel文件读写类
2015/07/30 Python
Python基于pygame实现的font游戏字体(附源码)
2015/11/11 Python
Python实现按特定格式对文件进行读写的方法示例
2017/11/30 Python
Python中使用支持向量机(SVM)算法
2017/12/26 Python
python 遍历目录(包括子目录)下所有文件的实例
2018/07/11 Python
Python模拟登录之滑块验证码的破解(实例代码)
2019/11/18 Python
Python selenium自动化测试模型图解
2020/04/15 Python
详解python命令提示符窗口下如何运行python脚本
2020/09/11 Python
input元素的url类型和email类型简介
2012/07/11 HTML / CSS
大堂副理的岗位职责范文
2014/02/17 职场文书
低碳生活倡议书
2014/04/14 职场文书
运动会400米加油稿(8篇)
2014/09/22 职场文书
2016年5月份红领巾广播稿
2015/12/21 职场文书
 python中的元类metaclass详情
2022/05/30 Python
蓝牙耳机怎么连接电脑win11? Win11蓝牙耳机连接电脑的技巧
2023/01/09 数码科技