fields.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790
  1. # -*- coding: utf-8 -*-
  2. from __future__ import unicode_literals
  3. import six
  4. import random
  5. import string
  6. import sys
  7. import uuid
  8. import re
  9. import copy
  10. import datetime
  11. from six.moves import urllib_parse as urlparse, range
  12. from IPy import IP, MAX_IPV4_ADDRESS, MAX_IPV6_ADDRESS
  13. from library.validator import exceptions
  14. from library.validator.utils import force_text
  15. from library.validator.translation import gettext as _
  16. FIELDS_NAME_MAP = {
  17. # Don't need to add field to here by hand,
  18. # BaseFieldMetaClass will auto add field to here.
  19. }
  20. def create_field(field_info):
  21. """
  22. Create a field by field info dict.
  23. """
  24. field_type = field_info.get('type')
  25. if field_type not in FIELDS_NAME_MAP:
  26. raise ValueError(_('not support this field: {}').format(field_type))
  27. field_class = FIELDS_NAME_MAP.get(field_type)
  28. params = dict(field_info)
  29. params.pop('type')
  30. return field_class.from_dict(params)
  31. class EmptyValue(object):
  32. """
  33. a data type replace None
  34. """
  35. def __init__(self):
  36. pass
  37. def __str__(self):
  38. return '__empty_value__'
  39. def __repr__(self):
  40. return '<{}>'.format(self.__class__.__name__)
  41. EMPTY_VALUE = EmptyValue()
  42. class BaseFieldMetaClass(type):
  43. def __new__(cls, name, bases, attrs):
  44. clazz = super(BaseFieldMetaClass, cls).__new__(cls, name, bases, attrs)
  45. field_name = attrs.get('FIELD_TYPE_NAME')
  46. if field_name is not None and field_name != 'object':
  47. FIELDS_NAME_MAP[field_name] = clazz
  48. return clazz
  49. @six.add_metaclass(BaseFieldMetaClass)
  50. class BaseField(object):
  51. """
  52. BaseField
  53. """
  54. """
  55. INTERNAL_TYPE is the type of the field in python internal, like str, int, list, dict
  56. INTERNAL_TYPE can be a type list, such as [int, long]
  57. INTERNAL_TYPE used to validate field's type by isinstance(value, INTERNAL_TYPE)
  58. """
  59. INTERNAL_TYPE = object
  60. FIELD_TYPE_NAME = 'object'
  61. PARAMS = [
  62. 'strict', 'default', 'validators', 'required'
  63. ]
  64. def __init__(self, strict=True, default=EMPTY_VALUE, validators=None, required=False, **kwargs):
  65. """
  66. :param strict: bool, if strict is True, value must be an instance of INTERVAL_TYPE,
  67. otherwise, value should be convert to INTERNAL_TYPE
  68. :param default: default value, defaults to EMPTY_VALUE
  69. :param validators: a validator list, validator can be function, other callable object or object that have method named validate
  70. :param required: bool, indicate that this field is whether required
  71. """
  72. self.strict = strict
  73. self.default = default
  74. if validators is None:
  75. validators = []
  76. elif not isinstance(validators, (tuple, list)):
  77. validators = [validators]
  78. self.validators = validators
  79. self.required = required
  80. if "requiredError" in kwargs:
  81. self._requiredError = kwargs["requiredError"]
  82. else:
  83. self._requiredError = None
  84. if "unicodeName" in kwargs:
  85. self._unicodeName = kwargs["unicodeName"]
  86. else:
  87. self._unicodeName = None
  88. def __str__(self):
  89. return self.__class__.__name__
  90. @classmethod
  91. def _check_value_range(cls, min_value, max_value):
  92. if max_value is not None and max_value < min_value:
  93. raise ValueError(_('the max value must greater than or equals the min value, got min value={min}, max value={max}').format(
  94. min=min_value, max=max_value))
  95. def _convert_type(self, value):
  96. if isinstance(self.INTERNAL_TYPE, (tuple, list)):
  97. for t in self.INTERNAL_TYPE:
  98. try:
  99. value = t(value)
  100. break
  101. except TypeError as e:
  102. pass
  103. else:
  104. raise ValueError()
  105. else:
  106. value = self.INTERNAL_TYPE(value)
  107. return value
  108. @classmethod
  109. def _get_all_params(cls):
  110. """
  111. Collect all PARAMS from this class and its parent class.
  112. """
  113. params = list(cls.PARAMS)
  114. bases = cls.__bases__
  115. for base in bases:
  116. if issubclass(base, BaseField):
  117. params.extend(base._get_all_params())
  118. return params
  119. def validate(self, value):
  120. """
  121. return validated value or raise FieldValidationError.
  122. """
  123. value = self._validate(value)
  124. for v in self.validators:
  125. v(value)
  126. return value
  127. def _validate(self, value):
  128. """
  129. return validated value or raise FieldValidationError.
  130. sub-class should override this method.
  131. """
  132. return self._validate_type(value)
  133. def _validate_type(self, value):
  134. """
  135. validate the type of value
  136. """
  137. if not isinstance(value, self.INTERNAL_TYPE):
  138. if self.strict:
  139. raise exceptions.FieldValidationError(
  140. _('got a wrong type: {0}, expect {1}').format(type(value).__name__, self.FIELD_TYPE_NAME))
  141. else:
  142. try:
  143. value = self._convert_type(value)
  144. except (ValueError, TypeError) as e:
  145. raise exceptions.FieldValidationError(
  146. _('type convertion({0} -> {1}) is failed: {2}').format(type(value).__name__, self.FIELD_TYPE_NAME, str(e)))
  147. return value
  148. def is_required(self):
  149. return self.required
  150. def requiredError(self):
  151. return self._requiredError or exceptions.FieldRequiredError()
  152. def unicodeName(self):
  153. return self._unicodeName
  154. def get_default(self):
  155. """
  156. return default value
  157. """
  158. if callable(self.default):
  159. return self.default()
  160. else:
  161. return self.default
  162. def to_presentation(self, value):
  163. """
  164. value: must be a internal value
  165. """
  166. return value
  167. def to_internal(self, value):
  168. """
  169. value: must be a validated value
  170. """
  171. return value
  172. def to_dict(self):
  173. """
  174. to dict presentation
  175. """
  176. d = {
  177. 'type': self.FIELD_TYPE_NAME,
  178. }
  179. params = self._get_all_params()
  180. for name in params:
  181. if hasattr(self, name):
  182. value = getattr(self, name)
  183. # 处理特殊值
  184. if value is EMPTY_VALUE:
  185. value = '__empty__'
  186. d[name] = value
  187. return d
  188. @classmethod
  189. def from_dict(cls, params):
  190. """
  191. Create a field from params.
  192. sub-class can override this method.
  193. """
  194. if params.get('default') == '__empty__':
  195. params['default'] = EMPTY_VALUE
  196. return cls(**params)
  197. def mock_data(self):
  198. """
  199. reutrn mocking data
  200. sub-class should override this method
  201. """
  202. return 'this field doesnt implement mock_data method'
  203. class StringField(BaseField):
  204. """
  205. StringField
  206. internal: six.string_types
  207. presentation: string
  208. """
  209. if six.PY2:
  210. INTERNAL_TYPE = (unicode, str)
  211. else:
  212. INTERNAL_TYPE = str
  213. FIELD_TYPE_NAME = 'string'
  214. PARAMS = ['min_length', 'max_length', 'regex']
  215. def __init__(self, min_length=0, max_length=None, regex=None, **kwargs):
  216. if min_length < 0:
  217. min_length = 0
  218. self._check_value_range(min_length, max_length)
  219. self.min_length = min_length
  220. self.max_length = max_length
  221. if isinstance(regex, six.string_types):
  222. regex = re.compile(regex)
  223. self.regex = regex
  224. super(StringField, self).__init__(**kwargs)
  225. def _validate(self, value):
  226. value = self._validate_type(value)
  227. if len(value) < self.min_length:
  228. raise exceptions.FieldValidationError(
  229. _('string is too short, min-lenght is {}').format(self.min_length))
  230. if self.max_length and len(value) > self.max_length:
  231. raise exceptions.FieldValidationError(
  232. _('string is too long, max-lenght is {}').format(self.max_length))
  233. if not self._match(value):
  234. raise exceptions.FieldValidationError(
  235. _('{0} not match {1}').format(self.regex.pattern, value))
  236. return value
  237. def _match(self, value):
  238. if self.regex is None:
  239. return True
  240. else:
  241. return self.regex.match(value) is not None
  242. def to_internal(self, value):
  243. return six.text_type(value)
  244. def mock_data(self):
  245. min_ = self.min_length
  246. max_ = self.max_length
  247. if max_ is None:
  248. max_ = min_ + 100
  249. size = random.randint(min_, max_)
  250. random_str = ''.join(
  251. [random.choice(string.ascii_letters + string.digits) for _ in range(size)])
  252. random_str = self.to_internal(random_str)
  253. return random_str
  254. class NumberField(BaseField):
  255. if six.PY2:
  256. INTERNAL_TYPE = (int, long, float)
  257. else:
  258. INTERNAL_TYPE = (int, float)
  259. FIELD_TYPE_NAME = 'number'
  260. PARAMS = ['min_value', 'max_value']
  261. def __init__(self, min_value=None, max_value=None, **kwargs):
  262. self._check_value_range(min_value, max_value)
  263. self.min_value = min_value
  264. self.max_value = max_value
  265. super(NumberField, self).__init__(**kwargs)
  266. def _validate(self, value):
  267. value = self._validate_type(value)
  268. if self.min_value is not None and value < self.min_value:
  269. raise exceptions.FieldValidationError(
  270. _('value is too small, min-value is {}').format(self.min_value))
  271. if self.max_value is not None and value > self.max_value:
  272. raise exceptions.FieldValidationError(
  273. _('value is too big, max-value is {}').format(self.max_value))
  274. return value
  275. def mock_data(self):
  276. min_ = self.min_value
  277. if min_ is None:
  278. min_ = 0
  279. max_ = self.max_value
  280. if max_ is None:
  281. max_ = min_ + 1000
  282. return random.uniform(min_, max_)
  283. class IntegerField(NumberField):
  284. INTERNAL_TYPE = int
  285. FIELD_TYPE_NAME = 'integer'
  286. PARAMS = []
  287. def mock_data(self):
  288. d = super(IntegerField, self).mock_data()
  289. return int(d)
  290. class FloatField(NumberField):
  291. INTERNAL_TYPE = float
  292. FIELD_TYPE_NAME = 'float'
  293. PARAMS = []
  294. class BoolField(BaseField):
  295. INTERNAL_TYPE = bool
  296. FIELD_TYPE_NAME = 'bool'
  297. PARAMS = []
  298. def mock_data(self):
  299. return random.choice([True, False])
  300. class UUIDField(BaseField):
  301. INTERNAL_TYPE = uuid.UUID
  302. FIELD_TYPE_NAME = 'UUID'
  303. PARAMS = ['format']
  304. SUPPORT_FORMATS = {
  305. 'hex': 'hex',
  306. 'str': '__str__',
  307. 'int': 'int',
  308. 'bytes': 'bytes',
  309. 'bytes_le': 'bytes_le'
  310. }
  311. def __init__(self, format='hex', **kwargs):
  312. """
  313. format: what format used when to_presentation, supports 'hex', 'str', 'int', 'bytes', 'bytes_le'
  314. """
  315. if format not in self.SUPPORT_FORMATS:
  316. raise ValueError(_('not supports format: {}').format(format))
  317. self.format = format
  318. kwargs.setdefault('strict', False)
  319. super(UUIDField, self).__init__(**kwargs)
  320. def _validate(self, value):
  321. value = self._validate_type(value)
  322. return value
  323. def to_presentation(self, value):
  324. assert isinstance(value, self.INTERNAL_TYPE)
  325. attr = getattr(value, self.SUPPORT_FORMATS[self.format])
  326. if callable(attr):
  327. return attr()
  328. return attr
  329. def mock_data(self):
  330. return uuid.uuid4()
  331. class MD5Field(StringField):
  332. FIELD_TYPE_NAME = 'md5'
  333. PARAMS = []
  334. REGEX = r'[\da-fA-F]{32}'
  335. def __init__(self, **kwargs):
  336. kwargs['strict'] = True
  337. super(MD5Field, self).__init__(min_length=32,
  338. max_length=32,
  339. regex=self.REGEX,
  340. **kwargs)
  341. def _validate(self, value):
  342. try:
  343. return super(MD5Field, self)._validate(value)
  344. except exceptions.FieldValidationError as e:
  345. raise exceptions.FieldValidationError(
  346. _('Got wrong md5 value: {}').format(value))
  347. def mock_data(self):
  348. return ''.join([random.choice(string.hexdigits) for i in range(32)])
  349. class SHAField(StringField):
  350. FIELD_TYPE_NAME = 'sha'
  351. SUPPORT_VERSION = [1, 224, 256, 384, 512]
  352. PARAMS = ['version']
  353. def __init__(self, version=256, **kwargs):
  354. if version not in self.SUPPORT_VERSION:
  355. raise ValueError(_('{0} not support, support versions are: {1}').format(
  356. version, self.SUPPORT_VERSION))
  357. if version == 1:
  358. length = 40
  359. else:
  360. length = int(version / 8 * 2)
  361. self.version = version
  362. self.length = length
  363. kwargs['strict'] = True
  364. super(SHAField, self).__init__(min_length=length,
  365. max_length=length,
  366. regex=r'[\da-fA-F]{' +
  367. str(length) + '}',
  368. **kwargs)
  369. def _validate(self, value):
  370. try:
  371. return super(SHAField, self)._validate(value)
  372. except exceptions.FieldValidationError as e:
  373. raise exceptions.FieldValidationError(
  374. _('Got wrong sha{0} value: {1}').format(self.version, value))
  375. def mock_data(self):
  376. return ''.join([random.choice(string.hexdigits) for i in range(self.length)])
  377. class EmailField(StringField):
  378. FIELD_TYPE_NAME = 'email'
  379. REGEX = r'^[a-zA-Z0-9.!#$%&\'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$'
  380. PARAMS = []
  381. def __init__(self, **kwargs):
  382. kwargs['strict'] = True
  383. super(EmailField, self).__init__(regex=self.REGEX, **kwargs)
  384. def _validate(self, value):
  385. try:
  386. return super(EmailField, self)._validate(value)
  387. except exceptions.FieldValidationError as e:
  388. raise exceptions.FieldValidationError(
  389. _('Got wrong email value: {}').format(value))
  390. def mock_data(self):
  391. name = ''.join(random.sample(string.ascii_lowercase, 5))
  392. domain = '{0}.com'.format(
  393. ''.join(random.sample(string.ascii_lowercase, 3)))
  394. return '{0}@{1}'.format(name, domain)
  395. class IPAddressField(BaseField):
  396. INTERNAL_TYPE = IP
  397. FIELD_TYPE_NAME = 'ip_address'
  398. PARAMS = ['version']
  399. SUPPORT_VERSIONS = ['ipv4', 'ipv6', 'both']
  400. def __init__(self, version='both', **kwargs):
  401. if version not in self.SUPPORT_VERSIONS:
  402. raise ValueError(_('{} version is not supported').format(version))
  403. self.version = version
  404. kwargs.setdefault('strict', False)
  405. super(IPAddressField, self).__init__(**kwargs)
  406. def _validate(self, value):
  407. try:
  408. value = IP(value)
  409. except ValueError as e:
  410. raise exceptions.FieldValidationError(str(e))
  411. if self.version == 'ipv4' and value.version() != 4:
  412. raise exceptions.FieldValidationError(
  413. _('expected an ipv4 address, got {}').format(value.strNormal()))
  414. if self.version == 'ipv6' and value.version() != 6:
  415. raise exceptions.FieldValidationError(
  416. -('expected an ipv6 address, got {}').format(value.strNormal()))
  417. return value
  418. def to_presentation(self, value):
  419. return value.strNormal()
  420. def mock_data(self):
  421. v = self.version
  422. if v == 'both':
  423. v = random.choice(['ipv4', 'ipv6'])
  424. if v == 'ipv4':
  425. ip = random.randint(0, MAX_IPV4_ADDRESS)
  426. return IP(ip)
  427. else:
  428. ip = random.randint(0, MAX_IPV6_ADDRESS)
  429. return IP(ip)
  430. class URLField(StringField):
  431. FIELD_TYPE_NAME = 'url'
  432. PARAMS = []
  433. SCHEMAS = ('http', 'https')
  434. def __init__(self, **kwargs):
  435. kwargs['strict'] = True
  436. super(URLField, self).__init__(min_length=0, **kwargs)
  437. def _validate(self, value):
  438. value = self._validate_type(value)
  439. url = urlparse.urlparse(value)
  440. if url.scheme not in self.SCHEMAS:
  441. raise exceptions.FieldValidationError(_('schema is lost'))
  442. if url.hostname == '':
  443. raise exceptions.FieldValidationError(_('hostname is lost'))
  444. return url.geturl()
  445. def mock_data(self):
  446. return 'http://www.example.com/media/image/demo.jpg'
  447. class EnumField(BaseField):
  448. INTERNAL_TYPE = object
  449. FIELD_TYPE_NAME = 'enum'
  450. PARAMS = ['choices']
  451. def __init__(self, choices=None, **kwargs):
  452. if choices is None or len(choices) == 0:
  453. raise ValueError('choices cant be empty or None')
  454. self.choices = choices
  455. super(EnumField, self).__init__(**kwargs)
  456. def _validate(self, value):
  457. if value not in self.choices:
  458. raise exceptions.FieldValidationError(
  459. _('{!r} not in the choices').format(value))
  460. return value
  461. def mock_data(self):
  462. return random.choice(self.choices)
  463. class DictField(BaseField):
  464. INTERNAL_TYPE = dict
  465. FIELD_TYPE_NAME = 'dict'
  466. PARAMS = ['validator']
  467. def __init__(self, validator=None, **kwargs):
  468. """
  469. :param validator: Validator object
  470. """
  471. self.validator = validator
  472. super(DictField, self).__init__(**kwargs)
  473. def _validate(self, value):
  474. value = self._validate_type(value)
  475. needValid = True
  476. if not self.validator:
  477. needValid = False
  478. if not value and not self.required:
  479. needValid = False
  480. if needValid:
  481. v = self.validator(value)
  482. if v.is_valid():
  483. value = v.validated_data
  484. else:
  485. raise exceptions.FieldValidationError(v.errors)
  486. else:
  487. value = copy.deepcopy(value)
  488. return value
  489. def to_dict(self):
  490. d = super(DictField, self).to_dict()
  491. if d['validator'] is not None:
  492. d['validator'] = d['validator'].to_dict()
  493. return d
  494. def mock_data(self):
  495. if self.validator:
  496. return self.validator.mock_data()
  497. else:
  498. return {}
  499. class ListField(BaseField):
  500. INTERNAL_TYPE = (list, tuple)
  501. FIELD_TYPE_NAME = 'list'
  502. PARAMS = ['field', 'min_length', 'max_length']
  503. def __init__(self, field=None, min_length=0, max_length=None, **kwargs):
  504. if field is not None and not isinstance(field, BaseField):
  505. raise ValueError(
  506. _('field param expect a instance of BaseField, but got {!r}').format(field))
  507. self.field = field
  508. self._check_value_range(min_length, max_length)
  509. self.min_length = min_length
  510. self.max_length = max_length
  511. super(ListField, self).__init__(**kwargs)
  512. def _validate(self, value):
  513. value = self._validate_type(value)
  514. if self.min_length is not None and len(value) < self.min_length:
  515. raise exceptions.FieldValidationError(
  516. _('this list has too few elements, min length is {}').format(self.min_length))
  517. if self.max_length is not None and len(value) > self.max_length:
  518. raise exceptions.FieldValidationError(
  519. _('this list has too many elements, max length is {}').format(self.max_length))
  520. if self.field:
  521. new_value = []
  522. for item in value:
  523. new_item = self.field.validate(item)
  524. new_value.append(new_item)
  525. value = new_value
  526. else:
  527. value = copy.deepcopy(value)
  528. return value
  529. def to_dict(self):
  530. d = super(ListField, self).to_dict()
  531. if d['field'] is not None:
  532. d['field'] = d['field'].to_dict()
  533. return d
  534. @classmethod
  535. def from_dict(cls, params):
  536. if 'field' in params and isinstance(params['field'], dict):
  537. params['field'] = create_field(params['field'])
  538. return super(ListField, cls).from_dict(params)
  539. def mock_data(self):
  540. min_ = self.min_length
  541. if min_ is None:
  542. min_ = 0
  543. max_ = self.max_length
  544. if max_ is None:
  545. max_ = 10
  546. length = random.choice(range(min_, max_))
  547. data = [None] * length
  548. if self.field:
  549. for i in range(length):
  550. data[i] = self.field.mock_data()
  551. return data
  552. class TimestampField(IntegerField):
  553. FIELD_TYPE_NAME = 'timestamp'
  554. PARAMS = []
  555. def __init__(self, **kwargs):
  556. super(TimestampField, self).__init__(
  557. min_value=0, max_value=2 ** 32 - 1, **kwargs)
  558. def _validate(self, value):
  559. try:
  560. return super(TimestampField, self)._validate(value)
  561. except exceptions.FieldValidationError as e:
  562. raise exceptions.FieldValidationError(
  563. _('Got wrong timestamp: {}').format(value))
  564. class DatetimeField(BaseField):
  565. INTERNAL_TYPE = datetime.datetime
  566. FIELD_TYPE_NAME = 'datetime'
  567. PARAMS = ['dt_format', 'tzinfo']
  568. DEFAULT_FORMAT = '%Y/%m/%d %H:%M:%S'
  569. def __init__(self, dt_format=None, tzinfo=None, **kwargs):
  570. if dt_format is None:
  571. dt_format = self.DEFAULT_FORMAT
  572. self.dt_format = dt_format
  573. if isinstance(tzinfo, six.string_types):
  574. try:
  575. import pytz
  576. except ImportError as e:
  577. raise ValueError(
  578. _('Cant create DatetimeField instance with tzinfo {}, please install pytz and try again').format(tzinfo))
  579. tzinfo = pytz.timezone(tzinfo)
  580. self.tzinfo = tzinfo
  581. kwargs.setdefault('strict', False)
  582. super(DatetimeField, self).__init__(**kwargs)
  583. def _convert_type(self, value):
  584. # override
  585. if isinstance(value, six.string_types):
  586. if value.isdigit():
  587. value = int(value)
  588. return self.INTERNAL_TYPE.fromtimestamp(value, tz=self.tzinfo)
  589. else:
  590. dt = self.INTERNAL_TYPE.strptime(value, self.dt_format)
  591. if self.tzinfo:
  592. dt = dt.replace(tzinfo=self.tzinfo)
  593. return dt
  594. elif isinstance(value, six.integer_types):
  595. return self.INTERNAL_TYPE.fromtimestamp(value, tz=self.tzinfo)
  596. else:
  597. raise ValueError(_('Got wrong datetime value: {}').format(value))
  598. def _validate(self, value):
  599. value = self._validate_type(value)
  600. return copy.copy(value)
  601. def to_presentation(self, value):
  602. return value.strftime(self.dt_format)
  603. def to_dict(self):
  604. d = super(DatetimeField, self).to_dict()
  605. if d['tzinfo'] is not None:
  606. d['tzinfo'] = force_text(d['tzinfo'])
  607. return d
  608. def mock_data(self):
  609. return self.INTERNAL_TYPE.fromtimestamp(random.randint(0, 2 ** 32 - 1))
  610. class DateField(BaseField):
  611. INTERNAL_TYPE = datetime.date
  612. FIELD_TYPE_NAME = 'date'
  613. PARAMS = ['dt_format']
  614. DEFAULT_FORMAT = '%Y/%m/%d'
  615. def __init__(self, dt_format=None, **kwargs):
  616. if dt_format is None:
  617. dt_format = self.DEFAULT_FORMAT
  618. self.dt_format = dt_format
  619. kwargs.setdefault('strict', False)
  620. super(DateField, self).__init__(**kwargs)
  621. def _convert_type(self, value):
  622. # override
  623. if isinstance(value, six.string_types):
  624. if value.isdigit():
  625. value = int(value)
  626. return self.INTERNAL_TYPE.fromtimestamp(value)
  627. else:
  628. dt = datetime.datetime.strptime(value, self.dt_format)
  629. return dt.date()
  630. elif isinstance(value, six.integer_types):
  631. return self.INTERNAL_TYPE.fromtimestamp(value)
  632. else:
  633. raise ValueError()
  634. def _validate(self, value):
  635. value = self._validate_type(value)
  636. return copy.copy(value)
  637. def to_presentation(self, value):
  638. return value.strftime(self.dt_format)
  639. def mock_data(self):
  640. return self.INTERNAL_TYPE.fromtimestamp(random.randint(0, 2 ** 32 - 1))