我准备了WeekdayField
,这似乎按预期工作。
from django.db.models import PositiveSmallIntegerField
from django.core import validators
_ = lambda x: x
class WeekdayField(PositiveSmallIntegerField):
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
SUNDAY = 7
DAY_OF_THE_WEEK = (
(MONDAY, _('Monday')),
(TUESDAY, _('Tuesday')),
(WEDNESDAY, _('Wednesday')),
(THURSDAY, _('Thursday')),
(FRIDAY, _('Friday')),
(SATURDAY, _('Saturday')),
(SUNDAY, _('Sunday')),
)
default_validators = [
validators.MinValueValidator(MONDAY),
validators.MaxValueValidator(SUNDAY)
]
def __init__(self, *args, **kwargs):
kwargs['choices'] = WeekdayField.DAY_OF_THE_WEEK
super(WeekdayField, self).__init__(*args, **kwargs)
当我开始为这个自定义字段编写单元测试时,我发现了问题。
我很惊讶,验证器只能通过django形式调用。
from django.contrib.humanize.templatetags.humanize import ordinal
from django.db import models
from django.forms.models import ModelForm
from django.test import TestCase
from services.fields import WeekdayField
class DayOfTheWeek(models.Model):
day = WeekdayField()
class DayOfTheWeekForm(ModelForm):
class Meta:
model = DayOfTheWeek
fields = ['day']
class WeekdayFieldTests(TestCase):
def _check_day(self, day, expected):
form = DayOfTheWeekForm({'day': day})
self.assertEqual(
form.is_valid(),
expected,
'There is no %s day of the week' % ordinal(day)
)
def test_7_days(self):
days = range(WeekdayField.MONDAY, len(WeekdayField.DAY_OF_THE_WEEK)+1)
for day in days:
self._check_day(day, True)
def test_no_0th_day_in_the_week(self):
self._check_day(0, False)
def test_no_13th_day_in_the_week(self):
self._check_day(13, False)
有没有更好的方法来写这个?
答案 0 :(得分:0)
重构后,我有类似的东西:
# -*- coding: utf-8 -*-
"""
This file contains custom definition of Django Model Fields
"""
from django.core.exceptions import ValidationError
from django.db.models import PositiveSmallIntegerField
_ = lambda x: x
class RangeValidator(object):
"""
Validates whether proper value belongs to specified range
"""
def __init__(self, bottom_limit, top_limit, message, code):
self.bottom_limit = bottom_limit
self.top_limit = top_limit
self.message = message
self.code = code
def __call__(self, value):
if not self.bottom_limit <= value <= self.top_limit:
raise ValidationError(self.message, code=self.code)
class WeekdayField(PositiveSmallIntegerField):
"""
Weekday field - simple Integer based field, to store number of the week.
First day of the week is Monday, which is represented by number 1.
"""
MONDAY = 1
TUESDAY = 2
WEDNESDAY = 3
THURSDAY = 4
FRIDAY = 5
SATURDAY = 6
SUNDAY = 7
DAY_OF_THE_WEEK = (
(MONDAY, _('Monday')),
(TUESDAY, _('Tuesday')),
(WEDNESDAY, _('Wednesday')),
(THURSDAY, _('Thursday')),
(FRIDAY, _('Friday')),
(SATURDAY, _('Saturday')),
(SUNDAY, _('Sunday')),
)
default_validators = [
RangeValidator(
bottom_limit=MONDAY,
top_limit=SUNDAY,
message=_(
'Day number should be between {} and {}'.format(MONDAY, SUNDAY)
),
code=_('wrong day number')
)
]
我决定不使用validators.MinValueValidator
和validators.MaxValueValidator
,因为它们没有返回最佳错误消息。
好消息是,测试该字段不需要测试文件中的新Form:)
并测试:
# -*- coding: utf-8 -*-
from django.core.exceptions import ValidationError
from django.test import TestCase
from services.fields import WeekdayField
class WeekdayFieldTests(TestCase):
def test_7_days(self):
days = range(WeekdayField.MONDAY, len(WeekdayField.DAY_OF_THE_WEEK)+1)
for day in days:
field = WeekdayField()
self.assertEqual(field.clean(day, None), day)
def test_no_0th_day_in_the_week(self):
field = WeekdayField()
with self.assertRaisesMessage(
ValidationError,
expected_message=(
u"Day number should be between 1 and 7"
)
):
field.clean(0, None)
def test_no_13th_day_in_the_week(self):
field = WeekdayField()
with self.assertRaisesMessage(
ValidationError,
expected_message=(
u"Day number should be between 1 and 7"
)
):
field.clean(13, None)