首先,我在Windows和Django 2.1.3上使用Python 3.7。
我正在尝试在Django表的CharField中存储一系列数字。我还希望管理站点并排显示两个数字文本框,分别表示下限值和上限值。我有以下文件和Django代码:
car / models.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)
car / admin.py
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为什么不尊重或运行我添加到这些字段中的验证器?可以执行的一项验证是我在custome clean()方法中所做的验证,在该方法中,我确定下限不大于上限。
答案 0 :(得分:0)
将msrp = RangeField()
添加到CarChangeForm解决了该问题。 Django不会自动为您的列初始化字段。您必须自己填写表格。