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实现字典(dict)的迭代操作示例
Jun 05 Python
pandas.DataFrame选取/排除特定行的方法
Jul 03 Python
Linux下python3.7.0安装教程
Jul 30 Python
10个Python小技巧你值得拥有
Sep 29 Python
利用Pycharm断点调试Python程序的方法
Nov 29 Python
Python中出现IndentationError:unindent does not match any outer indentation level错误的解决方法
Apr 18 Python
Python类的继承、多态及获取对象信息操作详解
Feb 28 Python
详解pandas DataFrame的查询方法(loc,iloc,at,iat,ix的用法和区别)
Aug 02 Python
python处理excel绘制雷达图
Oct 18 Python
python配置文件写入过程详解
Oct 19 Python
opencv3/C++图像像素操作详解
Dec 10 Python
Python爬虫+tkinter界面实现历史天气查询的思路详解
Feb 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
4月1日重磅发布!《星际争霸II》6.0.0版本更新
2020/04/09 星际争霸
在PHP中实现Javascript的escape()函数代码
2010/08/08 PHP
使用ltrace工具跟踪PHP库函数调用的方法
2016/04/25 PHP
LaravelS通过Swoole加速Laravel/Lumen详解
2018/03/02 PHP
PHP编程实现的TCP服务端和客户端功能示例
2018/04/13 PHP
Laravel框架定时任务2种实现方式示例
2018/12/08 PHP
PHP实现二维数组按照指定的字段进行排序算法示例
2019/04/23 PHP
javascript window对象属性整理
2009/10/24 Javascript
使用Plupload实现直接上传附件至七牛云存储
2014/12/26 Javascript
JS中的THIS和WINDOW.EVENT.SRCELEMENT详解
2015/05/25 Javascript
jQuery Easyui 下拉树组件combotree
2016/12/16 Javascript
AngularJs篇:使用AngularJs打造一个简易权限系统的实现代码
2016/12/26 Javascript
Vue computed计算属性的使用方法
2017/07/14 Javascript
利用require.js与angular搭建spa应用的方法实例
2017/07/19 Javascript
浅谈angular.copy() 深拷贝
2017/09/14 Javascript
Bootstrap 3多级下拉菜单实例
2017/11/23 Javascript
详解VUE2.X过滤器的使用方法
2018/01/11 Javascript
20行JS代码实现粘贴板复制功能
2018/02/06 Javascript
JavaScript(js)处理的HTML事件、键盘事件、鼠标事件简单示例
2019/11/19 Javascript
JavaScript实现PC端横向轮播图
2020/02/07 Javascript
[01:29]2017 DOTA2国际邀请赛官方英雄手办展示
2017/03/18 DOTA
python 输出一个两行字符的变量
2009/02/05 Python
10款最好的Web开发的 Python 框架
2015/03/18 Python
在Python中操作文件之truncate()方法的使用教程
2015/05/25 Python
Python 利用flask搭建一个共享服务器的步骤
2020/12/05 Python
python中Mako库实例用法
2020/12/31 Python
史上最详细的Python打包成exe文件教程
2021/01/17 Python
CSS3教程(5):网页背景图片
2009/04/02 HTML / CSS
企业精神口号
2014/06/11 职场文书
幼儿园健康教育方案
2014/06/14 职场文书
自愿离婚协议书范本
2014/09/13 职场文书
2014年销售工作总结
2014/12/01 职场文书
导师工作推荐信
2015/03/27 职场文书
golang 生成对应的数据表struct定义操作
2021/04/28 Golang
Python如何配置环境变量详解
2021/05/18 Python
Python基础之函数嵌套知识总结
2021/05/23 Python