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找出9个连续的空闲端口
Feb 01 Python
Python实现多线程抓取网页功能实例详解
Jun 08 Python
Python爬虫通过替换http request header来欺骗浏览器实现登录功能
Jan 07 Python
对pandas中iloc,loc取数据差别及按条件取值的方法详解
Nov 06 Python
Django组件content-type使用方法详解
Jul 19 Python
Django 开发环境与生产环境的区分详解
Jul 26 Python
python爬虫 模拟登录人人网过程解析
Jul 31 Python
python实现超市商品销售管理系统
Oct 25 Python
Django中的session用法详解
Mar 09 Python
Django框架实现在线考试系统的示例代码
Nov 30 Python
python爬虫如何解决图片验证码
Feb 14 Python
用python自动生成日历
Apr 24 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
WordPress中is_singular()函数简介
2015/02/05 PHP
php实现通用的信用卡验证类
2015/03/24 PHP
CI框架入门之MVC简单示例
2016/11/21 PHP
PHP微信公众号开发之微信红包实现方法分析
2017/07/14 PHP
PHP命令Command模式用法实例分析
2018/08/08 PHP
Tab页界面 用jQuery及Ajax技术实现(php后台)
2011/10/12 Javascript
NodeJs中的VM模块详解
2015/05/06 NodeJs
详解JavaScript中jQuery和Ajax以及JSONP的联合使用
2015/08/13 Javascript
异步JS框架的作用以及实现方法
2015/10/29 Javascript
jQuery实现的简单分页示例
2016/06/01 Javascript
利用Angularjs实现幻灯片效果
2016/09/07 Javascript
JavaScript重定向URL参数的两种方法小结
2016/10/19 Javascript
JavaScript屏蔽Backspace键的实现代码
2017/11/02 Javascript
AngularJS双向数据绑定原理之$watch、$apply和$digest的应用
2018/01/30 Javascript
开发用到的js封装方法(20种)
2018/10/12 Javascript
Egg Vue SSR 服务端渲染数据请求与asyncData
2019/11/24 Javascript
vue 需求 data中的数据之间的调用操作
2020/08/05 Javascript
[49:21]TNC vs VG 2019DOTA2国际邀请赛淘汰赛 胜者组赛BO3 第三场 8.20.mp4
2019/08/22 DOTA
Python中使用glob和rmtree删除目录子目录及所有文件的例子
2014/11/21 Python
使用Python构建Hopfield网络的教程
2015/04/14 Python
扩展Django admin的list_filter()可使用范围方法
2019/08/21 Python
PyQt5 如何让界面和逻辑分离的方法
2020/03/24 Python
浅析HTML5中header标签的用法
2016/06/24 HTML / CSS
Shopee越南:东南亚与台湾电商平台
2019/02/03 全球购物
英国发展最快的在线超市之一:Click Marketplace
2021/02/15 全球购物
网上书店创业计划书
2014/01/12 职场文书
工作个人的自我评价
2014/01/14 职场文书
新闻编辑求职信
2014/04/09 职场文书
餐饮商业计划书范文
2014/04/29 职场文书
单位委托书怎么写
2014/09/21 职场文书
关于运动会广播稿50字
2014/10/18 职场文书
小学感恩主题班会
2015/08/12 职场文书
golang正则之命名分组方式
2021/04/25 Golang
Vue操作Storage本地化存储
2022/04/29 Vue.js
2022微信温控新功能上线
2022/05/09 数码科技
centos环境下nginx高可用集群的搭建指南
2022/07/23 Servers