Как ограничить максимальное значение числового поля в модели Django?
Django имеет различные числовые поля, доступные для использования в моделях, например DecimalField и PositiveIntegerField. Хотя первый может быть ограничен количеством сохраненных десятичных знаков и общим количеством сохраненных символов, есть ли способ ограничить его сохранением только чисел в определенном диапазоне, например, 0.0-5.0 ?
в противном случае, есть ли способ ограничить PositiveIntegerField только для хранения, например, цифры до 50?
обновление: теперь эта ошибка 6845 был закрыт, этот вопрос StackOverflow может быть спорным. - sampablokuper
6 ответов
вы также можете создать пользовательский тип поля модели-см. http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields
в этом случае вы можете "наследовать" от встроенного IntegerField и переопределить его логику проверки.
чем больше я думаю об этом, я понимаю, насколько это было бы полезно для многих приложений Django. Возможно, тип IntegerRangeField может быть представлен как патч для разработчиков Django, чтобы рассмотреть возможность добавления ствол.
это работает для меня:
from django.db import models
class IntegerRangeField(models.IntegerField):
def __init__(self, verbose_name=None, name=None, min_value=None, max_value=None, **kwargs):
self.min_value, self.max_value = min_value, max_value
models.IntegerField.__init__(self, verbose_name, name, **kwargs)
def formfield(self, **kwargs):
defaults = {'min_value': self.min_value, 'max_value':self.max_value}
defaults.update(kwargs)
return super(IntegerRangeField, self).formfield(**defaults)
тогда в вашем классе модели вы будете использовать его следующим образом (поле-это модуль, в который вы помещаете приведенный выше код):
size = fields.IntegerRangeField(min_value=1, max_value=50)
или для ряда отрицательного и положительного (как ряд генератора):
size = fields.IntegerRangeField(min_value=-100, max_value=100)
что было бы действительно круто, если бы его можно было вызвать с помощью оператора диапазона следующим образом:
size = fields.IntegerRangeField(range(1, 50))
но для этого потребуется намного больше кода, так как вы можете указать "пропустить" параметр-диапазон(1, 50, 2) - Интересная идея...
можно использовать встроенные валидаторы Django-
from django.db.models import IntegerField, Model
from django.core.validators import MaxValueValidator, MinValueValidator
class CoolModelBro(Model):
limited_integer_field = IntegerField(
default=1,
validators=[
MaxValueValidator(100),
MinValueValidator(1)
]
)
редактировать: хотя эти работает только при использовании модели в ModelForm, Если вы используете модель "по себе", вздыхают.
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator
size = models.IntegerField(validators=[MinValueValidator(0),
MaxValueValidator(5)])
У меня была эта же проблема, вот мое решение:
SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)
есть два способа сделать это. Один из них-использовать проверку формы, чтобы пользователь никогда не вводил число более 50. форма проверки документов.
Если в процессе нет пользователя или вы не используете форму для ввода данных, вам придется переопределитьsave
метод для создания исключения или ограничения данных, поступающих в поле.
здесь самое лучшее решение если вы хотите некоторую дополнительную гибкость и не хотите изменять ваше модельное поле. Просто добавьте этот пользовательский валидатор:
#Imports
from django.core.exceptions import ValidationError
class validate_range_or_null(object):
compare = lambda self, a, b, c: a > c or a < b
clean = lambda self, x: x
message = ('Ensure this value is between %(limit_min)s and %(limit_max)s (it is %(show_value)s).')
code = 'limit_value'
def __init__(self, limit_min, limit_max):
self.limit_min = limit_min
self.limit_max = limit_max
def __call__(self, value):
cleaned = self.clean(value)
params = {'limit_min': self.limit_min, 'limit_max': self.limit_max, 'show_value': cleaned}
if value: # make it optional, remove it to make required, or make required on the model
if self.compare(cleaned, self.limit_min, self.limit_max):
raise ValidationError(self.message, code=self.code, params=params)
и его можно использовать как таковой:
class YourModel(models.Model):
....
no_dependents = models.PositiveSmallIntegerField("How many dependants?", blank=True, null=True, default=0, validators=[validate_range_or_null(1,100)])
эти два параметра-max и min, и это позволяет nulls. Вы можете настроить валидатор, если хотите, избавившись от отмеченного оператора if или изменив поле на пустое=False, null=False в модели. Это, конечно, потребует миграция.
Примечание: мне пришлось добавить валидатор, потому что Django не проверяет диапазон на PositiveSmallIntegerField, вместо этого он создает smallint (в postgres) для этого поля, и вы получаете ошибку DB, если указанное число находится вне диапазона.
надеюсь, это поможет :) Подробнее валидаторы в Django.
PS. Я основал свой ответ на BaseValidator в django.ядро.валидаторы, но все по-другому, кроме кода.