Django: 多值字段和多组件

7 投票
1 回答
8775 浏览
提问于 2025-04-16 17:59

Django的文档在解释如何使用MultiValueField和MultiWidget方面并不是特别详细。我尝试过分析其中一个实现,但结果并不理想。有没有人能给我一个简单的指引,让我朝正确的方向前进?

我的例子:

widgets.py

from django import forms

class TestMultiWidget(forms.MultiWidget):

    def __init__(self, attrs=None):
        widgets = (
            forms.TextInput(attrs=attrs),
            forms.TextInput(attrs=attrs),
        )
        super(TestMultiWidget, self).__init__(widgets, attrs)

    def decompress(self, value):
        if value:
            return value.split(':::')[0:2]
        return ['', '']

fields.py

from django import forms
from widgets import TestMultiWidget

class TestMultiField(forms.MultiValueField):
    widget = TestMultiWidget

    def __init__(self, *args, **kwargs):
        fields = (
            forms.CharField(),
            forms.CharField(),
        )
        super(TestMultiField, self).__init__(fields, *args, **kwargs)

    def compress(self, data_list):
        if data_list:
            return ':::'.join(data_list)
        return ''

models.py

from django.db import models
from util.fields import TestMultiField

class Test(models.Model):
    a = models.CharField(max_length=128)
    b = TestMultiField()
    c = models.CharField(max_length=128)

admin.py

from django.contrib import admin
from models import Test
admin.site.register(Test)

还有生成的管理界面

有没有人知道这里发生了什么?我猜可能是有一些意外的异常被隐藏了,但我找不到具体的原因。

谢谢!

1 个回答

16

请注意,django.forms.MultiValueField 是一个 表单 字段,而不是 模型 字段(像 django.db.models.CharField)。所以,它在你的测试模型中并不被当作模型字段处理,也没有在你的数据库中创建。(你可以通过 ./manage.py sqlall myapp 来检查。)

把你的 models.py 改成:

from django.db import models
from fields import TestMultiField

class TestMultiModelField(models.Field):

    def formfield(self, **kwargs):
        defaults = {'form_class': TestMultiField}
        defaults.update(kwargs)
        return super(TestMultiModelField, self).formfield(**defaults)

    def get_internal_type(self):
        return 'TextField'        

class Test(models.Model):
    a = models.CharField(max_length=128)
    b = TestMultiModelField()
    c = models.CharField(max_length=128)      

删除你的表(在 linux/mac 上可以用 ./manage.py sqlclear myapp | ./manage.py dbshell),然后用 syncdb 创建你的表,这次要包含 b 列。现在检查一下你的管理后台。

解释一下:要创建一个自定义的模型字段,可以参考这个链接: https://docs.djangoproject.com/en/dev/howto/custom-model-fields/

为了设置 模型 字段对应的 表单 字段,使用了 formfield 方法。

(顺便说一下,设计模型字段的“正确”方式可能稍有不同,涉及到 to_python 和 get_prep_value 的使用。)

撰写回答