Django 사용자 정의 모델 필드 - 양수 소수점 필드
사용자 정의 모델 필드
기사Custom Model Field Validator - Django에서 모델 필드에 대해 사용자 정의 유효성 검사기를 사용할 수 있음을 보았습니다. 그러나 모델의 공통 필드인 경우 사용자 정의 필드를 만드는 것이 좋습니다.
이 기사에서는 양수 값만 허용하는
PositiveDecimalField
를 만들 것입니다.# src/apps/models.py
from django.db.models import DecimalField
from django.core.exceptions import ValidationError
from django.utils.functional import cached_property
from django.utils.translation import gettext_lazy as _
def validate_positive(value):
if value < 0:
raise ValidationError(
_("%(value)s is not positive."),
params={"value": value}
)
class PositiveDecimalField(DecimalField):
description = _("Positive decimal number")
@cached_property
def validators(self):
return super().validators + [validate_positive]
PositiveDecimalField
를 사용하여 DecimalField 클래스를 상속하고 사용자 정의 유효성 검사기를 추가하여 description
속성과 validators
메서드를 덮어씁니다.다음과 같이 Django의 내장MinValueValidator을 사용할 수도 있습니다.
:
super().validators + [MinValueValidator("0.0")]
.그 외에도
__init__
의 DecimalField
메서드를 상속하고 validators
속성에 사용자 지정 유효성 검사기를 추가할 수도 있습니다.# src/apps/models.py
class PositiveDecimalField(DecimalField):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.validators.append(validate_positive)
용법
다음과 같이 사용자 정의 필드를 사용할 수 있습니다.
# src/apps/models.py
from django.db import models
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE)
title = models.CharField(max_length=120)
price = models.PositiveDecimalField()
단위 테스트
코드에
unittest
를 작성하는 것은 매우 중요합니다. 다음은 PositiveDecimalField
에 대한 테스트입니다.# tests/test_models.py
from django.core.exceptions import ValidationError
from django.test import TestCase
from src.apps.models import PositiveDecimalField
class PositiveDecimalFieldTests(TestCase):
def test_negative_value(self):
field = PositiveDecimalField(max_digits=4, decimal_places=2)
msg = "%s is not positive."
tests = [
"-1.3",
"-0.23",
]
for value in tests:
with self.subTest(value):
with self.assertRaisesMessage(ValidationError, msg % (value,)):
field.clean(value, None)
Django에는 이미 기본 테스트
DecimalField
가 있으므로 테스트DecimalField
할 필요가 없지만 전체 테스트 스위트를 만들고 싶다면:# tests/test_models.py
from decimal import Decimal
from django.core.exceptions import ValidationError
from django.test import TestCase
from src.apps.models import PositiveDecimalField
class PositiveDecimalFieldTests(TestCase):
def test_to_python(self):
f = PositiveDecimalField(max_digits=4, decimal_places=2)
self.assertEqual(f.to_python(3), Decimal("3"))
self.assertEqual(f.to_python("3.14"), Decimal("3.14"))
# to_python() converts floats and honors max_digits.
self.assertEqual(f.to_python(3.1415926535897), Decimal("3.142"))
self.assertEqual(f.to_python(2.4), Decimal("2.400"))
# Uses default rounding of ROUND_HALF_EVEN.
self.assertEqual(f.to_python(2.0625), Decimal("2.062"))
self.assertEqual(f.to_python(2.1875), Decimal("2.188"))
def test_invalid_value(self):
field = PositiveDecimalField(max_digits=4, decimal_places=2)
msg = "“%s” value must be a decimal number."
tests = [
(),
[],
{},
set(),
object(),
complex(),
"non-numeric string",
b"non-numeric byte-string",
]
for value in tests:
with self.subTest(value):
with self.assertRaisesMessage(ValidationError, msg % (value,)):
field.clean(value, None)
def test_default(self):
f = PositiveDecimalField(default=Decimal("0.00"))
self.assertEqual(f.get_default(), Decimal("0.00"))
def test_get_prep_value(self):
f = PositiveDecimalField(max_digits=5, decimal_places=1)
self.assertIsNone(f.get_prep_value(None))
self.assertEqual(f.get_prep_value("2.4"), Decimal("2.4"))
def test_negative_value(self):
field = PositiveDecimalField(max_digits=4, decimal_places=2)
msg = "%s is not positive."
tests = [
"-1.3",
"-0.23",
]
for value in tests:
with self.subTest(value):
with self.assertRaisesMessage(ValidationError, msg % (value,)):
field.clean(value, None)
모두 완료되었습니다!
Reference
이 문제에 관하여(Django 사용자 정의 모델 필드 - 양수 소수점 필드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/serhatteker/django-custom-model-field-positive-decimal-field-5c78텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)