Py学习  »  Django

使用django-admin表单中的多值字段和多小部件

boymeetscode • 4 年前 • 345 次点击  

首先,我在Windows和Django2.1.3上使用了python 3.7。

我正试图在django表的charfield中存储一系列数字。我还希望管理站点并排显示两个数字文本框,分别表示下限值和上限值。我有以下文件和Django代码:

轿车/车型.py

from django.db import models
from django.utils.translation import gettext_lazy as _

# Create your models here.


class Car(models.Model):

    class Meta:
        verbose_name = 'car'
        db_table = 'cars'
        verbose_name_plural = 'cars'

    make = models.CharField(_('manufacturer'), max_length=32)
    model = models.CharField(_('model'), max_length=24)
    msrp = models.CharField(_('suggested price'), max_length=11)

汽车/行政人员

from django.contrib import admin
from django.forms import ModelForm, MultiWidget, MultiValueField, NumberInput, IntegerField
from django.core.validators import MinValueValidator, MaxValueValidator, ValidationError

# Register your models here.
from .models import Car


class RangeWidget(MultiWidget):
    def __init__(self, *args, **kwargs):
        self.widgets = [NumberInput(), NumberInput()]
        super().__init__(self.widgets, *args, **kwargs)

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

    def value_from_datadict(self, data, files, name):
        datalist = [
            widget.value_from_datadict(
                data, files, '{name}_{i}'.format(name=name, i=i)
            ) for i, widget in enumerate(self.widgets)
        ]
        try:
            v = '/'.join(datalist)
        except ValueError:
            return ''
        else:
            return v


class RangeField(MultiValueField):
    widget = RangeWidget

    def __init__(self, *args, **kwargs):
        error_messages = {
            'incomplete': 'Enter two numbers',
        }
        fields = (
            IntegerField(
                error_messages={
                    'incomplete': 'Enter a number between 1 and 99999.'
                },
                validators=[
                    MinValueValidator(limit_value=1, message='Field cannot be less than 1'),
                    MaxValueValidator(limit_value=999999, message='Field cannot be greater than 99999')
                ],
                required=True
            ),
            IntegerField(
                error_messages={
                    'incomplete': 'Enter a number between 1 and 99999 that is equal or greater than the lower limit.'
                },
                validators=[
                    MinValueValidator(limit_value=1, message='Field cannot be less than 1'),
                    MaxValueValidator(limit_value=999999, message='Field cannot be greater than 99999')
                ],
                required=True
            )
        )

        super().__init__(
            error_messages=error_messages,
            fields=fields,
            require_all_fields=True,
            **kwargs
        )

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


class CarChangeForm(ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['msrp'].widget.attrs.update({'class': 'range', 'min': 1, 'max': 99999})

    class Meta:
        model = Car
        fields = ['make', 'model']
        exclude = []
        widgets = {
            'msrp': RangeWidget
        }

    def clean(self):
        cleaned_data = super().clean()
        try:
            lower, higher = cleaned_data.get('msrp').split('-')
        except (AttributeError, KeyError):
            raise ValidationError(message='Provide both msrp values')

        if lower.isdigit() and higher.isdigit() and int(lower) > int(higher):
            self.add_error(
                'msrp',
                'The lower MSRP cannot be more than higher MSRP.'
            )
        else:
            cleaned_data['msrp_lower'] = lower
            cleaned_data['msrp_higher'] = higher
            return cleaned_data


class CarAdmin(admin.ModelAdmin):
    fields = [
        ('make', 'model',),
        'msrp',
    ]

    form = CarChangeForm

    list_display = ('make', 'model', 'msrp')


admin.site.register(Car, CarAdmin)

除了我在rangefield.fields下指定的验证器不验证表单,并且允许我输入负数并将字段保留为空之外,似乎一切工作正常。为什么Django不尊重或运行我添加到这些字段中的验证程序?唯一有效的验证是我在custom clean()方法中所做的验证,在该方法中,我确保下限不大于上限。

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/38678
 
345 次点击  
文章 [ 1 ]  |  最新文章 4 年前
boymeetscode
Reply   •   1 楼
boymeetscode    5 年前

添加 msrp = RangeField() 到换车台解决了这个问题。Django不会自动初始化列的字段。你必须在表格中自己做。