Como limitar o valor máximo de um campo numérico em um modelo de Django?

votos
112

Django tem vários campos numéricos disponíveis para uso em modelos, por exemplo DecimalField e PositiveIntegerField . Embora o primeiro pode ser restringido com o número de casas decimais armazenada e o número total de caracteres armazenado, não há qualquer maneira de restringi-la para armazenar apenas os números dentro de uma determinada gama, por exemplo, 0,0-5,0?

Falhando isso, há alguma maneira de restringir um PositiveIntegerField a única loja, por exemplo, os números de até 50?

Update: agora que Bug 6845 foi fechada , esta pergunta StackOverflow pode ser discutível. - sampablokuper

Publicado 11/05/2009 em 18:29
fonte usuário
Em outras línguas...                            


6 respostas

votos
219

Você pode usar validadores internos do 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)
        ]
     )

Editar : Embora estes só funcionam quando você estiver usando o modelo em um ModelForm , não se você estiver usando o modelo "por conta própria", suspiro.

Respondeu 19/08/2012 em 14:32
fonte usuário

votos
113

Você também pode criar um tipo de campo modelo personalizado - veja http://docs.djangoproject.com/en/dev/howto/custom-model-fields/#howto-custom-model-fields

Neste caso, você pode 'herdar' a partir da sua lógica de validação embutida IntegerField e substituir.

Quanto mais eu penso sobre isso, eu percebo o quão útil esta seria para muitos aplicativos Django. Talvez um tipo IntegerRangeField poderia ser enviado como um patch para os devs Django considerar adicionar ao tronco.

Isso está funcionando para mim:

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)

Então, em sua classe de modelo, você iria utilizá-lo como este (campo sendo o módulo onde você colocar o código acima):

size = fields.IntegerRangeField(min_value=1, max_value=50)

Ou para uma gama de negativo e positivo (como uma gama oscilador):

size = fields.IntegerRangeField(min_value=-100, max_value=100)

O que seria muito legal é se ele poderia ser chamado com o operador de intervalo como este:

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

Mas, isso exigiria um código muito mais uma vez, pois você pode especificar um parâmetro de 'pular' - gama (1, 50, 2) - Idéia interessante embora ...

Respondeu 11/05/2009 em 19:31
fonte usuário

votos
62
from django.db import models
from django.core.validators import MinValueValidator, MaxValueValidator

size = models.IntegerField(validators=[MinValueValidator(0),
                                       MaxValueValidator(5)])
Respondeu 19/08/2012 em 14:54
fonte usuário

votos
48

Eu tive esse mesmo problema; aqui foi a minha solução:

SCORE_CHOICES = zip( range(1,n), range(1,n) )
score = models.IntegerField(choices=SCORE_CHOICES, blank=True)
Respondeu 28/10/2010 em 22:38
fonte usuário

votos
10

Há duas maneiras de fazer isso. Uma é usar validação de formulário para nunca deixar qualquer número acima de 50 ser inserido por um usuário. Docs de validação de formulário .

Se não houver nenhum usuário envolvido no processo, ou você não está usando um formulário para inserir dados, então você vai ter que substituir o modelo de savemétodo para lançar uma exceção ou limitar os dados que vão para o campo.

Respondeu 11/05/2009 em 18:39
fonte usuário

votos
4

Aqui é a melhor solução se você quiser alguma flexibilidade extra e não quer mudar seu campo de modelo. Basta adicionar este validador personalizado:

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

E ele pode ser usado como tal:

class YourModel(models.Model):

    ....
    no_dependents = models.PositiveSmallIntegerField("How many dependants?", blank=True, null=True, default=0, validators=[validate_range_or_null(1,100)])

Os dois parâmetros são máximo e mínimo, e que permite que os nulos. Você pode personalizar o validador se você gosta de se livrar do marcada if ou alterar o campo para ser em branco = False, null = False no modelo. Que necessitarão de uma migração.

Nota: eu tive que adicionar o validador porque Django não valida o intervalo em PositiveSmallIntegerField, em vez disso, cria um smallint (no postgres) para este campo e você recebe um erro de DB se o numérico especificado está fora do intervalo.

Espero que isso ajude :) Mais sobre Validators em Django .

PS. Baseei minha resposta no BaseValidator em django.core.validators, mas tudo é diferente, exceto para o código.

Respondeu 17/09/2014 em 21:45
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more