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求解水仙花数的方法
May 11 Python
python实现比较两段文本不同之处的方法
May 30 Python
python开发中module模块用法实例分析
Nov 12 Python
Python学习教程之常用的内置函数大全
Jul 14 Python
Python使用遗传算法解决最大流问题
Jan 29 Python
python list元素为tuple时的排序方法
Apr 18 Python
Django中日期处理注意事项与自定义时间格式转换详解
Aug 06 Python
解决Django no such table: django_session的问题
Apr 07 Python
Python新手学习raise用法
Jun 03 Python
python函数超时自动退出的实操方法
Dec 28 Python
python基础之文件操作
Oct 24 Python
python游戏开发之pygame实现接球小游戏
Apr 22 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
Linux中为php配置伪静态
2014/12/17 PHP
Ajax PHP JavaScript MySQL实现简易无刷新在线聊天室
2016/08/17 PHP
setAttribute 与 class冲突解决
2008/02/17 Javascript
网页禁用右键实现代码(JavaScript代码)
2009/10/29 Javascript
使用Microsoft Ajax Minifier减小JavaScript文件大小的方法
2010/04/01 Javascript
js的压缩及jquery压缩探讨(提高页面加载性能/保护劳动成果)
2013/01/29 Javascript
jquery ajax同步异步的执行最终解决方案
2013/04/26 Javascript
js/jQuery简单实现选项卡功能
2014/01/02 Javascript
Jquery下EasyUI组件中的DataGrid结果集清空方法
2014/01/06 Javascript
javaScript 页面自动加载事件详解
2014/02/10 Javascript
按Enter键触发事件的jquery方法实现代码
2014/02/17 Javascript
js中将String转换为number以便比较
2014/07/08 Javascript
JS 日期与时间戮相互转化的简单实例
2016/06/22 Javascript
js实现无缝滚动图
2017/02/22 Javascript
jQuery滚动插件scrollable.js用法分析
2017/05/25 jQuery
微信小程序使用Promise简化回调
2018/02/06 Javascript
解决Vue打包之后文件路径出错的问题
2018/03/06 Javascript
vue后台管理之动态加载路由的方法
2018/08/13 Javascript
如何测量vue应用运行时的性能
2019/06/21 Javascript
微信小程序npm引入vant-weapp的踩坑记录
2019/08/01 Javascript
[01:00:35]2018DOTA2亚洲邀请赛3月30日B组 EffcetVSMineski
2018/03/31 DOTA
[36:22]VP vs Serenity 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
使用PDB模式调试Python程序介绍
2015/04/05 Python
对python 命令的-u参数详解
2018/12/03 Python
Python字典遍历操作实例小结
2019/03/05 Python
PyTorch搭建多项式回归模型(三)
2019/05/22 Python
python实现五子棋人机对战游戏
2020/03/25 Python
Python列表原理与用法详解【创建、元素增加、删除、访问、计数、切片、遍历等】
2019/10/30 Python
pycharm的python_stubs问题
2020/04/08 Python
python爬虫scrapy图书分类实例讲解
2020/11/23 Python
SmartBuyGlasses英国:购买太阳镜和眼镜
2018/01/29 全球购物
.NET笔试题(20个问题)
2016/02/02 面试题
应届生程序员求职信
2013/11/05 职场文书
进步之星获奖感言
2014/02/22 职场文书
《在大海中永生》教学反思
2014/02/24 职场文书
python使用pymysql模块操作MySQL
2021/06/16 Python