脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Python - Django 表单模型选择框如何使用分组

Django 表单模型选择框如何使用分组

2021-06-27 00:06栖迟於一丘 Python

这篇文章主要介绍了Django 表单模型选择框如何使用分组,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

起步

django 表单中有两种字段类型可以使用选择框: choicefieldmodelchoicefield

对于 choicefield 的基本使用是:

?
1
2
3
4
5
6
7
8
9
10
11
12
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> 标签:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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 中提供了一个很好的解决方案。

首先为需要分类的类型创建模型,在另一个模型中用外键关联它:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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 类型:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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)

最后,在表单中可以如下进行使用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
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')

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:http://www.hongweipeng.com/index.php/archives/1790/

延伸 · 阅读

精彩推荐