Django 모델에서 숫자 필드의 최대 값을 제한하는 방법은 무엇입니까?


169

장고에는 모델에 사용할 수있는 다양한 숫자 필드 (예 : DecimalFieldPositiveIntegerField)가 있습니다. 전자는 저장된 소수점 이하 자릿수 및 저장된 전체 문자 수로 제한 될 수 있지만 특정 범위 (예 : 0.0-5.0) 내의 숫자 저장하도록 제한 할 수있는 방법이 있습니까?

실패하면 PositiveIntegerField를 제한하여 예를 들어 최대 50까지의 숫자 만 저장하도록 할 수 있습니까?

업데이트 : 이제 버그 6845 가 닫 혔기 때문에이 StackOverflow 질문에 문제가있을 수 있습니다. -Sampablokuper



Django의 관리자에게 제한을 적용하고 싶다고 언급 했어야합니다. 그것을 얻기 위해서는 최소한 다음과 같은 문서가 있어야합니다. docs.djangoproject.com/en/dev/ref/contrib/admin/…
sampablokuper

실제로 1.0 이전 버전의 Django는 cotellese.net/2007/12/11/…과 같은 매우 우아한 솔루션을 가지고있는 것 같습니다 . Django의 svn 릴리스 에서이 작업을 수행하는 똑같이 우아한 방법이 있는지 궁금합니다.
sampablokuper

나는이 것을 배울 실망 하지 않는 현재의 장고 SVN으로이 작업을 수행하는 우아한 방법이 될 것으로 보인다. 자세한 내용은이 토론 스레드를 참조하십시오 : groups.google.com/group/django-users/browse_thread/thread/…
sampablokuper

모델에서 유효성 검사기를 사용하면 유효성 검사가 관리자 인터페이스 및 ModelForms에서 작동합니다. docs.djangoproject.com/en/dev/ref/validators/…
guettli

답변:


133

사용자 정의 모델 필드 유형을 만들 수도 있습니다. http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields를 참조 하십시오.

이 경우 내장 IntegerField에서 '상속'하고 유효성 검사 논리를 무시할 수 있습니다.

이것에 대해 더 많이 생각할수록 많은 Django 앱에 이것이 얼마나 유용한 지 알았습니다. 아마도 장고 개발자가 트렁크에 추가하는 것을 고려하기 위해 IntegerRangeField 유형을 패치로 제출할 수 있습니다.

이것은 나를 위해 일하고 있습니다 :

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)

정말 멋진 것은 다음과 같이 range 연산자로 호출 할 수 있다는 것입니다.

size = fields.IntegerRangeField(range(1, 50))

그러나 'skip'매개 변수-range (1, 50, 2)를 지정할 수 있기 때문에 훨씬 더 많은 코드가 필요합니다.


이것은 작동하지만 모델의 clean 메소드에서 정수 값은 항상 None이므로 추가 청소를 제공 할 수 없습니다. 이것이 왜 있고 어떻게 고칠 수 있는지 아십니까?
KrisF

2
MinValueValidator(min_value) and MaxValueValidator(max_value)전화하기 전에 추가하여 사용자 정의 필드를 향상시킬 수 있습니다 super().__init__ ...(스 니펫 : gist.github.com/madneon/147159f46ed478c71d5ee4950a9d697d )
madneon

349

당신은 사용할 수 있습니다 장고가 내장되어있어 유효성 검사기 -

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)
        ]
     )

편집 : 모델로 직접 작업 하는 경우 유효성 검사기를 트리거하기 위해 모델을 저장하기 전에 모델 full_clean 메서드 를 호출해야합니다 . ModelForm양식은 자동으로 수행되므로 사용시에는 필요하지 않습니다 .


4
limited_integer_field를 옵션으로 사용하려면 자체 유효성 검사기를 작성해야한다고 생각합니까? (공백이 아닌 경우 유효 범위 만) null = 참, 공란 = 참이하지 않았습니다.
radtek

2
장고 1.7에서 설정 null=True하고 blank=True예상대로 작동합니다. 이 필드는 선택 사항이며 비워두면 null로 저장됩니다.
Tim Tisdall

77
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator

size = models.IntegerField(validators=[MinValueValidator(0),
                                       MaxValueValidator(5)])

52

나는이 같은 문제가 있었다; 여기 내 해결책이있었습니다.

SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)

10
목록 이해하기 :models.IntegerField(choices=[(i, i) for i in range(1, n)], blank=True)
Razzi Abuissa

10

이를 수행하는 두 가지 방법이 있습니다. 하나는 사용자가 50을 초과하는 숫자를 입력하지 않도록 양식 유효성 검사를 사용하는 것입니다. 검증 문서 양식 .

프로세스에 관련된 사용자가 없거나 데이터를 입력하기 위해 양식을 사용하지 않는 save경우 예외를 발생 시키거나 필드로 들어가는 데이터를 제한하기 위해 모델의 메소드를 재정의 해야합니다.


2
사람이 아닌 입력을 확인하는 양식도 사용할 수 있습니다. 폼을 만능 유효성 검사 기술로 채우는 것이 좋습니다.
S.Lott

1
이것에 대해 생각한 후에, 나는 유효성 검사를 양식에 넣고 싶지 않다고 확신합니다. 어떤 숫자의 범위가 수용 가능한지에 대한 질문은 어떤 종류의 숫자가 수용 가능한가에 대한 질문만큼 모델의 일부입니다. 모델을 편집 할 수있는 모든 양식, 수용 할 수있는 숫자 범위를 말하고 싶지 않습니다. 이것은 DRY를 위반할뿐 아니라 그다지 부적절합니다. 내가 모델을 대체 해 보길거야 그래서 방법 저장, 또는 아마도 사용자 정의 모델 필드 유형 만들기 - 내가 찾을 수없는 경우에도 더 좋은 방법 :
sampablokuper

tghw, 당신은 "예외를 던지거나 현장에 들어가는 데이터를 제한하기 위해 모델의 save 메소드를 무시할 수있다"고 말했다. 모델 정의의 재정의 save () 메서드 내에서 입력 한 숫자가 지정된 범위를 벗어나면 문자 필드에 숫자 필드에 입력 한 것처럼 유효성 검사 오류가 발생하도록하려면 어떻게해야합니까? 즉, 사용자가 관리자 또는 다른 양식을 통해 편집하는지 여부에 관계없이 작동 할 수있는 방법이 있습니까? 나는 사용자에게 무슨 일이 일어나고 있는지 알려주지 않고 현장에 들어가는 데이터를 제한하고 싶지 않습니다. :) 감사합니다!
sampablokuper

"save"메소드를 사용하더라도 MyModel.object.filter (blabla) .update (blabla)와 같이 QuerySet을 통해 테이블을 업데이트 할 때는 작동하지 않으므로 save가 호출되지 않으므로 점검이 수행되지 않습니다.
Olivier Pons

5

추가 유연성을 원하고 모델 필드를 변경하지 않으려는 경우 최상의 솔루션이 있습니다. 이 사용자 정의 유효성 검사기를 추가하십시오.

#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이며 널을 허용합니다. 표시된 if 문을 제거하거나 모델에서 필드를 blank = False, null = False로 변경하여 원하는 경우 유효성 검사기를 사용자 정의 할 수 있습니다. 물론 마이그레이션이 필요합니다.

참고 : Django는 PositiveSmallIntegerField에서 범위의 유효성을 검사하지 않기 때문에 유효성 검사기를 추가해야했습니다. 대신이 필드에 대해 smallint (postgres)를 생성하고 지정된 숫자가 범위를 벗어나면 DB 오류가 발생합니다.

이것이 도움이되기를 바랍니다 :) Django의 Validator에 대한 추가 정보 .

추신. django.core.validators의 BaseValidator를 기반으로 대답했지만 코드를 제외하고는 모두 다릅니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.