Во-первых, я использую Python 3.7 в Windows и Django 2.1.3.
Я пытаюсь сохранить диапазон чисел в CharField в таблице django. Я также хочу, чтобы сайт администратора отображал два числовых текстовых поля рядом, чтобы обозначить нижний предел значения и верхний предел значения соответственно. У меня есть следующие файлы и код Django:
автомобиль / 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)
машина / 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 не уважает и не использует валидаторы, которые я добавил в эти поля? Единственная проверка, которая ДЕЛАЕТ работу, - это проверка, которую я провел в методе обычного clean (), где я проверяю, чтобы нижний предел не превышал верхнего.