Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/rest_framework/fields.py: 58%

1040 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import copy 

2import datetime 

3import decimal 

4import functools 

5import inspect 

6import re 

7import uuid 

8import warnings 

9from collections import OrderedDict 

10from collections.abc import Mapping 

11 

12from django.conf import settings 

13from django.core.exceptions import ObjectDoesNotExist 

14from django.core.exceptions import ValidationError as DjangoValidationError 

15from django.core.validators import ( 

16 EmailValidator, MaxLengthValidator, MaxValueValidator, MinLengthValidator, 

17 MinValueValidator, ProhibitNullCharactersValidator, RegexValidator, 

18 URLValidator, ip_address_validators 

19) 

20from django.forms import FilePathField as DjangoFilePathField 

21from django.forms import ImageField as DjangoImageField 

22from django.utils import timezone 

23from django.utils.dateparse import ( 

24 parse_date, parse_datetime, parse_duration, parse_time 

25) 

26from django.utils.duration import duration_string 

27from django.utils.encoding import is_protected_type, smart_str 

28from django.utils.formats import localize_input, sanitize_separators 

29from django.utils.ipv6 import clean_ipv6_address 

30from django.utils.timezone import utc 

31from django.utils.translation import gettext_lazy as _ 

32from pytz.exceptions import InvalidTimeError 

33 

34from rest_framework import ( 

35 ISO_8601, RemovedInDRF313Warning, RemovedInDRF314Warning 

36) 

37from rest_framework.exceptions import ErrorDetail, ValidationError 

38from rest_framework.settings import api_settings 

39from rest_framework.utils import html, humanize_datetime, json, representation 

40from rest_framework.utils.formatting import lazy_format 

41from rest_framework.validators import ProhibitSurrogateCharactersValidator 

42 

43 

44class empty: 

45 """ 

46 This class is used to represent no data being provided for a given input 

47 or output value. 

48 

49 It is required because `None` may be a valid input or output value. 

50 """ 

51 pass 

52 

53 

54class BuiltinSignatureError(Exception): 

55 """ 

56 Built-in function signatures are not inspectable. This exception is raised 

57 so the serializer can raise a helpful error message. 

58 """ 

59 pass 

60 

61 

62def is_simple_callable(obj): 

63 """ 

64 True if the object is a callable that takes no arguments. 

65 """ 

66 # Bail early since we cannot inspect built-in function signatures. 

67 if inspect.isbuiltin(obj): 67 ↛ 68line 67 didn't jump to line 68, because the condition on line 67 was never true

68 raise BuiltinSignatureError( 

69 'Built-in function signatures are not inspectable. ' 

70 'Wrap the function call in a simple, pure Python function.') 

71 

72 if not (inspect.isfunction(obj) or inspect.ismethod(obj) or isinstance(obj, functools.partial)): 

73 return False 

74 

75 sig = inspect.signature(obj) 

76 params = sig.parameters.values() 

77 return all( 

78 param.kind == param.VAR_POSITIONAL or 

79 param.kind == param.VAR_KEYWORD or 

80 param.default != param.empty 

81 for param in params 

82 ) 

83 

84 

85def get_attribute(instance, attrs): 

86 """ 

87 Similar to Python's built in `getattr(instance, attr)`, 

88 but takes a list of nested attributes, instead of a single attribute. 

89 

90 Also accepts either attribute lookup on objects or dictionary lookups. 

91 """ 

92 for attr in attrs: 

93 try: 

94 if isinstance(instance, Mapping): 94 ↛ 95line 94 didn't jump to line 95, because the condition on line 94 was never true

95 instance = instance[attr] 

96 else: 

97 instance = getattr(instance, attr) 

98 except ObjectDoesNotExist: 

99 return None 

100 if is_simple_callable(instance): 

101 try: 

102 instance = instance() 

103 except (AttributeError, KeyError) as exc: 

104 # If we raised an Attribute or KeyError here it'd get treated 

105 # as an omitted field in `Field.get_attribute()`. Instead we 

106 # raise a ValueError to ensure the exception is not masked. 

107 raise ValueError('Exception raised in callable attribute "{}"; original exception was: {}'.format(attr, exc)) 

108 

109 return instance 

110 

111 

112def set_value(dictionary, keys, value): 

113 """ 

114 Similar to Python's built in `dictionary[key] = value`, 

115 but takes a list of nested keys instead of a single key. 

116 

117 set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2} 

118 set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2} 

119 set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}} 

120 """ 

121 if not keys: 121 ↛ 122line 121 didn't jump to line 122, because the condition on line 121 was never true

122 dictionary.update(value) 

123 return 

124 

125 for key in keys[:-1]: 

126 if key not in dictionary: 126 ↛ 128line 126 didn't jump to line 128, because the condition on line 126 was never false

127 dictionary[key] = {} 

128 dictionary = dictionary[key] 

129 

130 dictionary[keys[-1]] = value 

131 

132 

133def to_choices_dict(choices): 

134 """ 

135 Convert choices into key/value dicts. 

136 

137 to_choices_dict([1]) -> {1: 1} 

138 to_choices_dict([(1, '1st'), (2, '2nd')]) -> {1: '1st', 2: '2nd'} 

139 to_choices_dict([('Group', ((1, '1st'), 2))]) -> {'Group': {1: '1st', 2: '2'}} 

140 """ 

141 # Allow single, paired or grouped choices style: 

142 # choices = [1, 2, 3] 

143 # choices = [(1, 'First'), (2, 'Second'), (3, 'Third')] 

144 # choices = [('Category', ((1, 'First'), (2, 'Second'))), (3, 'Third')] 

145 ret = OrderedDict() 

146 for choice in choices: 

147 if not isinstance(choice, (list, tuple)): 147 ↛ 149line 147 didn't jump to line 149, because the condition on line 147 was never true

148 # single choice 

149 ret[choice] = choice 

150 else: 

151 key, value = choice 

152 if isinstance(value, (list, tuple)): 152 ↛ 154line 152 didn't jump to line 154, because the condition on line 152 was never true

153 # grouped choices (category, sub choices) 

154 ret[key] = to_choices_dict(value) 

155 else: 

156 # paired choice (key, display value) 

157 ret[key] = value 

158 return ret 

159 

160 

161def flatten_choices_dict(choices): 

162 """ 

163 Convert a group choices dict into a flat dict of choices. 

164 

165 flatten_choices_dict({1: '1st', 2: '2nd'}) -> {1: '1st', 2: '2nd'} 

166 flatten_choices_dict({'Group': {1: '1st', 2: '2nd'}}) -> {1: '1st', 2: '2nd'} 

167 """ 

168 ret = OrderedDict() 

169 for key, value in choices.items(): 

170 if isinstance(value, dict): 170 ↛ 172line 170 didn't jump to line 172, because the condition on line 170 was never true

171 # grouped choices (category, sub choices) 

172 for sub_key, sub_value in value.items(): 

173 ret[sub_key] = sub_value 

174 else: 

175 # choice (key, display value) 

176 ret[key] = value 

177 return ret 

178 

179 

180def iter_options(grouped_choices, cutoff=None, cutoff_text=None): 

181 """ 

182 Helper function for options and option groups in templates. 

183 """ 

184 class StartOptionGroup: 

185 start_option_group = True 

186 end_option_group = False 

187 

188 def __init__(self, label): 

189 self.label = label 

190 

191 class EndOptionGroup: 

192 start_option_group = False 

193 end_option_group = True 

194 

195 class Option: 

196 start_option_group = False 

197 end_option_group = False 

198 

199 def __init__(self, value, display_text, disabled=False): 

200 self.value = value 

201 self.display_text = display_text 

202 self.disabled = disabled 

203 

204 count = 0 

205 

206 for key, value in grouped_choices.items(): 

207 if cutoff and count >= cutoff: 

208 break 

209 

210 if isinstance(value, dict): 

211 yield StartOptionGroup(label=key) 

212 for sub_key, sub_value in value.items(): 

213 if cutoff and count >= cutoff: 

214 break 

215 yield Option(value=sub_key, display_text=sub_value) 

216 count += 1 

217 yield EndOptionGroup() 

218 else: 

219 yield Option(value=key, display_text=value) 

220 count += 1 

221 

222 if cutoff and count >= cutoff and cutoff_text: 

223 cutoff_text = cutoff_text.format(count=cutoff) 

224 yield Option(value='n/a', display_text=cutoff_text, disabled=True) 

225 

226 

227def get_error_detail(exc_info): 

228 """ 

229 Given a Django ValidationError, return a list of ErrorDetail, 

230 with the `code` populated. 

231 """ 

232 code = getattr(exc_info, 'code', None) or 'invalid' 

233 

234 try: 

235 error_dict = exc_info.error_dict 

236 except AttributeError: 

237 return [ 

238 ErrorDetail((error.message % error.params) if error.params else error.message, 

239 code=error.code if error.code else code) 

240 for error in exc_info.error_list] 

241 return { 

242 k: [ 

243 ErrorDetail((error.message % error.params) if error.params else error.message, 

244 code=error.code if error.code else code) 

245 for error in errors 

246 ] for k, errors in error_dict.items() 

247 } 

248 

249 

250class CreateOnlyDefault: 

251 """ 

252 This class may be used to provide default values that are only used 

253 for create operations, but that do not return any value for update 

254 operations. 

255 """ 

256 requires_context = True 

257 

258 def __init__(self, default): 

259 self.default = default 

260 

261 def __call__(self, serializer_field): 

262 is_update = serializer_field.parent.instance is not None 

263 if is_update: 

264 raise SkipField() 

265 if callable(self.default): 

266 if hasattr(self.default, 'set_context'): 

267 warnings.warn( 

268 "Method `set_context` on defaults is deprecated and will " 

269 "no longer be called starting with 3.13. Instead set " 

270 "`requires_context = True` on the class, and accept the " 

271 "context as an additional argument.", 

272 RemovedInDRF313Warning, stacklevel=2 

273 ) 

274 self.default.set_context(self) 

275 

276 if getattr(self.default, 'requires_context', False): 

277 return self.default(serializer_field) 

278 else: 

279 return self.default() 

280 return self.default 

281 

282 def __repr__(self): 

283 return '%s(%s)' % (self.__class__.__name__, repr(self.default)) 

284 

285 

286class CurrentUserDefault: 

287 requires_context = True 

288 

289 def __call__(self, serializer_field): 

290 return serializer_field.context['request'].user 

291 

292 def __repr__(self): 

293 return '%s()' % self.__class__.__name__ 

294 

295 

296class SkipField(Exception): 

297 pass 

298 

299 

300REGEX_TYPE = type(re.compile('')) 

301 

302NOT_READ_ONLY_WRITE_ONLY = 'May not set both `read_only` and `write_only`' 

303NOT_READ_ONLY_REQUIRED = 'May not set both `read_only` and `required`' 

304NOT_REQUIRED_DEFAULT = 'May not set both `required` and `default`' 

305USE_READONLYFIELD = 'Field(read_only=True) should be ReadOnlyField' 

306MISSING_ERROR_MESSAGE = ( 

307 'ValidationError raised by `{class_name}`, but error key `{key}` does ' 

308 'not exist in the `error_messages` dictionary.' 

309) 

310 

311 

312class Field: 

313 _creation_counter = 0 

314 

315 default_error_messages = { 

316 'required': _('This field is required.'), 

317 'null': _('This field may not be null.') 

318 } 

319 default_validators = [] 

320 default_empty_html = empty 

321 initial = None 

322 

323 def __init__(self, *, read_only=False, write_only=False, 

324 required=None, default=empty, initial=empty, source=None, 

325 label=None, help_text=None, style=None, 

326 error_messages=None, validators=None, allow_null=False): 

327 self._creation_counter = Field._creation_counter 

328 Field._creation_counter += 1 

329 

330 # If `required` is unset, then use `True` unless a default is provided. 

331 if required is None: 

332 required = default is empty and not read_only 

333 

334 # Some combinations of keyword arguments do not make sense. 

335 assert not (read_only and write_only), NOT_READ_ONLY_WRITE_ONLY 

336 assert not (read_only and required), NOT_READ_ONLY_REQUIRED 

337 assert not (required and default is not empty), NOT_REQUIRED_DEFAULT 

338 assert not (read_only and self.__class__ == Field), USE_READONLYFIELD 

339 

340 self.read_only = read_only 

341 self.write_only = write_only 

342 self.required = required 

343 self.default = default 

344 self.source = source 

345 self.initial = self.initial if (initial is empty) else initial 

346 self.label = label 

347 self.help_text = help_text 

348 self.style = {} if style is None else style 

349 self.allow_null = allow_null 

350 

351 if self.default_empty_html is not empty: 

352 if default is not empty: 352 ↛ 353line 352 didn't jump to line 353, because the condition on line 352 was never true

353 self.default_empty_html = default 

354 

355 if validators is not None: 

356 self.validators = list(validators) 

357 

358 # These are set up by `.bind()` when the field is added to a serializer. 

359 self.field_name = None 

360 self.parent = None 

361 

362 # Collect default error message from self and parent classes 

363 messages = {} 

364 for cls in reversed(self.__class__.__mro__): 

365 messages.update(getattr(cls, 'default_error_messages', {})) 

366 messages.update(error_messages or {}) 

367 self.error_messages = messages 

368 

369 def bind(self, field_name, parent): 

370 """ 

371 Initializes the field name and parent for the field instance. 

372 Called when a field is added to the parent serializer instance. 

373 """ 

374 

375 # In order to enforce a consistent style, we error if a redundant 

376 # 'source' argument has been used. For example: 

377 # my_field = serializer.CharField(source='my_field') 

378 assert self.source != field_name, ( 

379 "It is redundant to specify `source='%s'` on field '%s' in " 

380 "serializer '%s', because it is the same as the field name. " 

381 "Remove the `source` keyword argument." % 

382 (field_name, self.__class__.__name__, parent.__class__.__name__) 

383 ) 

384 

385 self.field_name = field_name 

386 self.parent = parent 

387 

388 # `self.label` should default to being based on the field name. 

389 if self.label is None: 

390 self.label = field_name.replace('_', ' ').capitalize() 

391 

392 # self.source should default to being the same as the field name. 

393 if self.source is None: 

394 self.source = field_name 

395 

396 # self.source_attrs is a list of attributes that need to be looked up 

397 # when serializing the instance, or populating the validated data. 

398 if self.source == '*': 

399 self.source_attrs = [] 

400 else: 

401 self.source_attrs = self.source.split('.') 

402 

403 # .validators is a lazily loaded property, that gets its default 

404 # value from `get_validators`. 

405 @property 

406 def validators(self): 

407 if not hasattr(self, '_validators'): 

408 self._validators = self.get_validators() 

409 return self._validators 

410 

411 @validators.setter 

412 def validators(self, validators): 

413 self._validators = validators 

414 

415 def get_validators(self): 

416 return list(self.default_validators) 

417 

418 def get_initial(self): 

419 """ 

420 Return a value to use when the field is being returned as a primitive 

421 value, without any object instance. 

422 """ 

423 if callable(self.initial): 423 ↛ 424line 423 didn't jump to line 424, because the condition on line 423 was never true

424 return self.initial() 

425 return self.initial 

426 

427 def get_value(self, dictionary): 

428 """ 

429 Given the *incoming* primitive data, return the value for this field 

430 that should be validated and transformed to a native value. 

431 """ 

432 if html.is_html_input(dictionary): 

433 # HTML forms will represent empty fields as '', and cannot 

434 # represent None or False values directly. 

435 if self.field_name not in dictionary: 

436 if getattr(self.root, 'partial', False): 436 ↛ 438line 436 didn't jump to line 438, because the condition on line 436 was never false

437 return empty 

438 return self.default_empty_html 

439 ret = dictionary[self.field_name] 

440 if ret == '' and self.allow_null: 440 ↛ 443line 440 didn't jump to line 443, because the condition on line 440 was never true

441 # If the field is blank, and null is a valid value then 

442 # determine if we should use null instead. 

443 return '' if getattr(self, 'allow_blank', False) else None 

444 elif ret == '' and not self.required: 444 ↛ 447line 444 didn't jump to line 447, because the condition on line 444 was never true

445 # If the field is blank, and emptiness is valid then 

446 # determine if we should use emptiness instead. 

447 return '' if getattr(self, 'allow_blank', False) else empty 

448 return ret 

449 return dictionary.get(self.field_name, empty) 

450 

451 def get_attribute(self, instance): 

452 """ 

453 Given the *outgoing* object instance, return the primitive value 

454 that should be used for this field. 

455 """ 

456 try: 

457 return get_attribute(instance, self.source_attrs) 

458 except BuiltinSignatureError as exc: 

459 msg = ( 

460 'Field source for `{serializer}.{field}` maps to a built-in ' 

461 'function type and is invalid. Define a property or method on ' 

462 'the `{instance}` instance that wraps the call to the built-in ' 

463 'function.'.format( 

464 serializer=self.parent.__class__.__name__, 

465 field=self.field_name, 

466 instance=instance.__class__.__name__, 

467 ) 

468 ) 

469 raise type(exc)(msg) 

470 except (KeyError, AttributeError) as exc: 

471 if self.default is not empty: 

472 return self.get_default() 

473 if self.allow_null: 

474 return None 

475 if not self.required: 

476 raise SkipField() 

477 msg = ( 

478 'Got {exc_type} when attempting to get a value for field ' 

479 '`{field}` on serializer `{serializer}`.\nThe serializer ' 

480 'field might be named incorrectly and not match ' 

481 'any attribute or key on the `{instance}` instance.\n' 

482 'Original exception text was: {exc}.'.format( 

483 exc_type=type(exc).__name__, 

484 field=self.field_name, 

485 serializer=self.parent.__class__.__name__, 

486 instance=instance.__class__.__name__, 

487 exc=exc 

488 ) 

489 ) 

490 raise type(exc)(msg) 

491 

492 def get_default(self): 

493 """ 

494 Return the default value to use when validating data if no input 

495 is provided for this field. 

496 

497 If a default has not been set for this field then this will simply 

498 raise `SkipField`, indicating that no value should be set in the 

499 validated data for this field. 

500 """ 

501 if self.default is empty or getattr(self.root, 'partial', False): 501 ↛ 504line 501 didn't jump to line 504, because the condition on line 501 was never false

502 # No default, or this is a partial update. 

503 raise SkipField() 

504 if callable(self.default): 

505 if hasattr(self.default, 'set_context'): 

506 warnings.warn( 

507 "Method `set_context` on defaults is deprecated and will " 

508 "no longer be called starting with 3.13. Instead set " 

509 "`requires_context = True` on the class, and accept the " 

510 "context as an additional argument.", 

511 RemovedInDRF313Warning, stacklevel=2 

512 ) 

513 self.default.set_context(self) 

514 

515 if getattr(self.default, 'requires_context', False): 

516 return self.default(self) 

517 else: 

518 return self.default() 

519 

520 return self.default 

521 

522 def validate_empty_values(self, data): 

523 """ 

524 Validate empty values, and either: 

525 

526 * Raise `ValidationError`, indicating invalid data. 

527 * Raise `SkipField`, indicating that the field should be ignored. 

528 * Return (True, data), indicating an empty value that should be 

529 returned without any further validation being applied. 

530 * Return (False, data), indicating a non-empty value, that should 

531 have validation applied as normal. 

532 """ 

533 if self.read_only: 533 ↛ 534line 533 didn't jump to line 534, because the condition on line 533 was never true

534 return (True, self.get_default()) 

535 

536 if data is empty: 

537 if getattr(self.root, 'partial', False): 

538 raise SkipField() 

539 if self.required: 

540 self.fail('required') 

541 return (True, self.get_default()) 

542 

543 if data is None: 

544 if not self.allow_null: 544 ↛ 545line 544 didn't jump to line 545, because the condition on line 544 was never true

545 self.fail('null') 

546 # Nullable `source='*'` fields should not be skipped when its named 

547 # field is given a null value. This is because `source='*'` means 

548 # the field is passed the entire object, which is not null. 

549 elif self.source == '*': 549 ↛ 550line 549 didn't jump to line 550, because the condition on line 549 was never true

550 return (False, None) 

551 return (True, None) 

552 

553 return (False, data) 

554 

555 def run_validation(self, data=empty): 

556 """ 

557 Validate a simple representation and return the internal value. 

558 

559 The provided data may be `empty` if no representation was included 

560 in the input. 

561 

562 May raise `SkipField` if the field should not be included in the 

563 validated data. 

564 """ 

565 (is_empty_value, data) = self.validate_empty_values(data) 

566 if is_empty_value: 

567 return data 

568 value = self.to_internal_value(data) 

569 self.run_validators(value) 

570 return value 

571 

572 def run_validators(self, value): 

573 """ 

574 Test the given value against all the validators on the field, 

575 and either raise a `ValidationError` or simply return. 

576 """ 

577 errors = [] 

578 for validator in self.validators: 

579 if hasattr(validator, 'set_context'): 579 ↛ 580line 579 didn't jump to line 580, because the condition on line 579 was never true

580 warnings.warn( 

581 "Method `set_context` on validators is deprecated and will " 

582 "no longer be called starting with 3.13. Instead set " 

583 "`requires_context = True` on the class, and accept the " 

584 "context as an additional argument.", 

585 RemovedInDRF313Warning, stacklevel=2 

586 ) 

587 validator.set_context(self) 

588 

589 try: 

590 if getattr(validator, 'requires_context', False): 

591 validator(value, self) 

592 else: 

593 validator(value) 

594 except ValidationError as exc: 

595 # If the validation error contains a mapping of fields to 

596 # errors then simply raise it immediately rather than 

597 # attempting to accumulate a list of errors. 

598 if isinstance(exc.detail, dict): 

599 raise 

600 errors.extend(exc.detail) 

601 except DjangoValidationError as exc: 

602 errors.extend(get_error_detail(exc)) 

603 if errors: 603 ↛ 604line 603 didn't jump to line 604, because the condition on line 603 was never true

604 raise ValidationError(errors) 

605 

606 def to_internal_value(self, data): 

607 """ 

608 Transform the *incoming* primitive data into a native value. 

609 """ 

610 raise NotImplementedError( 

611 '{cls}.to_internal_value() must be implemented for field ' 

612 '{field_name}. If you do not need to support write operations ' 

613 'you probably want to subclass `ReadOnlyField` instead.'.format( 

614 cls=self.__class__.__name__, 

615 field_name=self.field_name, 

616 ) 

617 ) 

618 

619 def to_representation(self, value): 

620 """ 

621 Transform the *outgoing* native value into primitive data. 

622 """ 

623 raise NotImplementedError( 

624 '{cls}.to_representation() must be implemented for field {field_name}.'.format( 

625 cls=self.__class__.__name__, 

626 field_name=self.field_name, 

627 ) 

628 ) 

629 

630 def fail(self, key, **kwargs): 

631 """ 

632 A helper method that simply raises a validation error. 

633 """ 

634 try: 

635 msg = self.error_messages[key] 

636 except KeyError: 

637 class_name = self.__class__.__name__ 

638 msg = MISSING_ERROR_MESSAGE.format(class_name=class_name, key=key) 

639 raise AssertionError(msg) 

640 message_string = msg.format(**kwargs) 

641 raise ValidationError(message_string, code=key) 

642 

643 @property 

644 def root(self): 

645 """ 

646 Returns the top-level serializer for this field. 

647 """ 

648 root = self 

649 while root.parent is not None: 

650 root = root.parent 

651 return root 

652 

653 @property 

654 def context(self): 

655 """ 

656 Returns the context as passed to the root serializer on initialization. 

657 """ 

658 return getattr(self.root, '_context', {}) 

659 

660 def __new__(cls, *args, **kwargs): 

661 """ 

662 When a field is instantiated, we store the arguments that were used, 

663 so that we can present a helpful representation of the object. 

664 """ 

665 instance = super().__new__(cls) 

666 instance._args = args 

667 instance._kwargs = kwargs 

668 return instance 

669 

670 def __deepcopy__(self, memo): 

671 """ 

672 When cloning fields we instantiate using the arguments it was 

673 originally created with, rather than copying the complete state. 

674 """ 

675 # Treat regexes and validators as immutable. 

676 # See https://github.com/encode/django-rest-framework/issues/1954 

677 # and https://github.com/encode/django-rest-framework/pull/4489 

678 args = [ 

679 copy.deepcopy(item) if not isinstance(item, REGEX_TYPE) else item 

680 for item in self._args 

681 ] 

682 kwargs = { 

683 key: (copy.deepcopy(value, memo) if (key not in ('validators', 'regex')) else value) 

684 for key, value in self._kwargs.items() 

685 } 

686 return self.__class__(*args, **kwargs) 

687 

688 def __repr__(self): 

689 """ 

690 Fields are represented using their initial calling arguments. 

691 This allows us to create descriptive representations for serializer 

692 instances that show all the declared fields on the serializer. 

693 """ 

694 return representation.field_repr(self) 

695 

696 

697# Boolean types... 

698 

699class BooleanField(Field): 

700 default_error_messages = { 

701 'invalid': _('Must be a valid boolean.') 

702 } 

703 default_empty_html = False 

704 initial = False 

705 TRUE_VALUES = { 

706 't', 'T', 

707 'y', 'Y', 'yes', 'Yes', 'YES', 

708 'true', 'True', 'TRUE', 

709 'on', 'On', 'ON', 

710 '1', 1, 

711 True 

712 } 

713 FALSE_VALUES = { 

714 'f', 'F', 

715 'n', 'N', 'no', 'No', 'NO', 

716 'false', 'False', 'FALSE', 

717 'off', 'Off', 'OFF', 

718 '0', 0, 0.0, 

719 False 

720 } 

721 NULL_VALUES = {'null', 'Null', 'NULL', '', None} 

722 

723 def to_internal_value(self, data): 

724 try: 

725 if data in self.TRUE_VALUES: 

726 return True 

727 elif data in self.FALSE_VALUES: 727 ↛ 729line 727 didn't jump to line 729, because the condition on line 727 was never false

728 return False 

729 elif data in self.NULL_VALUES and self.allow_null: 

730 return None 

731 except TypeError: # Input is an unhashable type 

732 pass 

733 self.fail('invalid', input=data) 

734 

735 def to_representation(self, value): 

736 if value in self.TRUE_VALUES: 

737 return True 

738 elif value in self.FALSE_VALUES: 738 ↛ 740line 738 didn't jump to line 740, because the condition on line 738 was never false

739 return False 

740 if value in self.NULL_VALUES and self.allow_null: 

741 return None 

742 return bool(value) 

743 

744 

745class NullBooleanField(BooleanField): 

746 initial = None 

747 

748 def __init__(self, **kwargs): 

749 warnings.warn( 

750 "The `NullBooleanField` is deprecated and will be removed starting " 

751 "with 3.14. Instead use the `BooleanField` field and set " 

752 "`allow_null=True` which does the same thing.", 

753 RemovedInDRF314Warning, stacklevel=2 

754 ) 

755 

756 assert 'allow_null' not in kwargs, '`allow_null` is not a valid option.' 

757 kwargs['allow_null'] = True 

758 

759 super().__init__(**kwargs) 

760 

761 

762# String types... 

763 

764class CharField(Field): 

765 default_error_messages = { 

766 'invalid': _('Not a valid string.'), 

767 'blank': _('This field may not be blank.'), 

768 'max_length': _('Ensure this field has no more than {max_length} characters.'), 

769 'min_length': _('Ensure this field has at least {min_length} characters.'), 

770 } 

771 initial = '' 

772 

773 def __init__(self, **kwargs): 

774 self.allow_blank = kwargs.pop('allow_blank', False) 

775 self.trim_whitespace = kwargs.pop('trim_whitespace', True) 

776 self.max_length = kwargs.pop('max_length', None) 

777 self.min_length = kwargs.pop('min_length', None) 

778 super().__init__(**kwargs) 

779 if self.max_length is not None: 

780 message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) 

781 self.validators.append( 

782 MaxLengthValidator(self.max_length, message=message)) 

783 if self.min_length is not None: 783 ↛ 784line 783 didn't jump to line 784, because the condition on line 783 was never true

784 message = lazy_format(self.error_messages['min_length'], min_length=self.min_length) 

785 self.validators.append( 

786 MinLengthValidator(self.min_length, message=message)) 

787 

788 self.validators.append(ProhibitNullCharactersValidator()) 

789 self.validators.append(ProhibitSurrogateCharactersValidator()) 

790 

791 def run_validation(self, data=empty): 

792 # Test for the empty string here so that it does not get validated, 

793 # and so that subclasses do not need to handle it explicitly 

794 # inside the `to_internal_value()` method. 

795 if data == '' or (self.trim_whitespace and str(data).strip() == ''): 795 ↛ 796line 795 didn't jump to line 796, because the condition on line 795 was never true

796 if not self.allow_blank: 

797 self.fail('blank') 

798 return '' 

799 return super().run_validation(data) 

800 

801 def to_internal_value(self, data): 

802 # We're lenient with allowing basic numerics to be coerced into strings, 

803 # but other types should fail. Eg. unclear if booleans should represent as `true` or `True`, 

804 # and composites such as lists are likely user error. 

805 if isinstance(data, bool) or not isinstance(data, (str, int, float,)): 805 ↛ 806line 805 didn't jump to line 806, because the condition on line 805 was never true

806 self.fail('invalid') 

807 value = str(data) 

808 return value.strip() if self.trim_whitespace else value 

809 

810 def to_representation(self, value): 

811 return str(value) 

812 

813 

814class EmailField(CharField): 

815 default_error_messages = { 

816 'invalid': _('Enter a valid email address.') 

817 } 

818 

819 def __init__(self, **kwargs): 

820 super().__init__(**kwargs) 

821 validator = EmailValidator(message=self.error_messages['invalid']) 

822 self.validators.append(validator) 

823 

824 

825class RegexField(CharField): 

826 default_error_messages = { 

827 'invalid': _('This value does not match the required pattern.') 

828 } 

829 

830 def __init__(self, regex, **kwargs): 

831 super().__init__(**kwargs) 

832 validator = RegexValidator(regex, message=self.error_messages['invalid']) 

833 self.validators.append(validator) 

834 

835 

836class SlugField(CharField): 

837 default_error_messages = { 

838 'invalid': _('Enter a valid "slug" consisting of letters, numbers, underscores or hyphens.'), 

839 'invalid_unicode': _('Enter a valid "slug" consisting of Unicode letters, numbers, underscores, or hyphens.') 

840 } 

841 

842 def __init__(self, allow_unicode=False, **kwargs): 

843 super().__init__(**kwargs) 

844 self.allow_unicode = allow_unicode 

845 if self.allow_unicode: 845 ↛ 846line 845 didn't jump to line 846, because the condition on line 845 was never true

846 validator = RegexValidator(re.compile(r'^[-\w]+\Z', re.UNICODE), message=self.error_messages['invalid_unicode']) 

847 else: 

848 validator = RegexValidator(re.compile(r'^[-a-zA-Z0-9_]+$'), message=self.error_messages['invalid']) 

849 self.validators.append(validator) 

850 

851 

852class URLField(CharField): 

853 default_error_messages = { 

854 'invalid': _('Enter a valid URL.') 

855 } 

856 

857 def __init__(self, **kwargs): 

858 super().__init__(**kwargs) 

859 validator = URLValidator(message=self.error_messages['invalid']) 

860 self.validators.append(validator) 

861 

862 

863class UUIDField(Field): 

864 valid_formats = ('hex_verbose', 'hex', 'int', 'urn') 

865 

866 default_error_messages = { 

867 'invalid': _('Must be a valid UUID.'), 

868 } 

869 

870 def __init__(self, **kwargs): 

871 self.uuid_format = kwargs.pop('format', 'hex_verbose') 

872 if self.uuid_format not in self.valid_formats: 872 ↛ 873line 872 didn't jump to line 873, because the condition on line 872 was never true

873 raise ValueError( 

874 'Invalid format for uuid representation. ' 

875 'Must be one of "{}"'.format('", "'.join(self.valid_formats)) 

876 ) 

877 super().__init__(**kwargs) 

878 

879 def to_internal_value(self, data): 

880 if not isinstance(data, uuid.UUID): 

881 try: 

882 if isinstance(data, int): 

883 return uuid.UUID(int=data) 

884 elif isinstance(data, str): 

885 return uuid.UUID(hex=data) 

886 else: 

887 self.fail('invalid', value=data) 

888 except (ValueError): 

889 self.fail('invalid', value=data) 

890 return data 

891 

892 def to_representation(self, value): 

893 if self.uuid_format == 'hex_verbose': 893 ↛ 896line 893 didn't jump to line 896, because the condition on line 893 was never false

894 return str(value) 

895 else: 

896 return getattr(value, self.uuid_format) 

897 

898 

899class IPAddressField(CharField): 

900 """Support both IPAddressField and GenericIPAddressField""" 

901 

902 default_error_messages = { 

903 'invalid': _('Enter a valid IPv4 or IPv6 address.'), 

904 } 

905 

906 def __init__(self, protocol='both', **kwargs): 

907 self.protocol = protocol.lower() 

908 self.unpack_ipv4 = (self.protocol == 'both') 

909 super().__init__(**kwargs) 

910 validators, error_message = ip_address_validators(protocol, self.unpack_ipv4) 

911 self.validators.extend(validators) 

912 

913 def to_internal_value(self, data): 

914 if not isinstance(data, str): 

915 self.fail('invalid', value=data) 

916 

917 if ':' in data: 

918 try: 

919 if self.protocol in ('both', 'ipv6'): 

920 return clean_ipv6_address(data, self.unpack_ipv4) 

921 except DjangoValidationError: 

922 self.fail('invalid', value=data) 

923 

924 return super().to_internal_value(data) 

925 

926 

927# Number types... 

928 

929class IntegerField(Field): 

930 default_error_messages = { 

931 'invalid': _('A valid integer is required.'), 

932 'max_value': _('Ensure this value is less than or equal to {max_value}.'), 

933 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), 

934 'max_string_length': _('String value too large.') 

935 } 

936 MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. 

937 re_decimal = re.compile(r'\.0*\s*$') # allow e.g. '1.0' as an int, but not '1.2' 

938 

939 def __init__(self, **kwargs): 

940 self.max_value = kwargs.pop('max_value', None) 

941 self.min_value = kwargs.pop('min_value', None) 

942 super().__init__(**kwargs) 

943 if self.max_value is not None: 

944 message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) 

945 self.validators.append( 

946 MaxValueValidator(self.max_value, message=message)) 

947 if self.min_value is not None: 

948 message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) 

949 self.validators.append( 

950 MinValueValidator(self.min_value, message=message)) 

951 

952 def to_internal_value(self, data): 

953 if isinstance(data, str) and len(data) > self.MAX_STRING_LENGTH: 953 ↛ 954line 953 didn't jump to line 954, because the condition on line 953 was never true

954 self.fail('max_string_length') 

955 

956 try: 

957 data = int(self.re_decimal.sub('', str(data))) 

958 except (ValueError, TypeError): 

959 self.fail('invalid') 

960 return data 

961 

962 def to_representation(self, value): 

963 return int(value) 

964 

965 

966class FloatField(Field): 

967 default_error_messages = { 

968 'invalid': _('A valid number is required.'), 

969 'max_value': _('Ensure this value is less than or equal to {max_value}.'), 

970 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), 

971 'max_string_length': _('String value too large.') 

972 } 

973 MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. 

974 

975 def __init__(self, **kwargs): 

976 self.max_value = kwargs.pop('max_value', None) 

977 self.min_value = kwargs.pop('min_value', None) 

978 super().__init__(**kwargs) 

979 if self.max_value is not None: 

980 message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) 

981 self.validators.append( 

982 MaxValueValidator(self.max_value, message=message)) 

983 if self.min_value is not None: 

984 message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) 

985 self.validators.append( 

986 MinValueValidator(self.min_value, message=message)) 

987 

988 def to_internal_value(self, data): 

989 

990 if isinstance(data, str) and len(data) > self.MAX_STRING_LENGTH: 

991 self.fail('max_string_length') 

992 

993 try: 

994 return float(data) 

995 except (TypeError, ValueError): 

996 self.fail('invalid') 

997 

998 def to_representation(self, value): 

999 return float(value) 

1000 

1001 

1002class DecimalField(Field): 

1003 default_error_messages = { 

1004 'invalid': _('A valid number is required.'), 

1005 'max_value': _('Ensure this value is less than or equal to {max_value}.'), 

1006 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), 

1007 'max_digits': _('Ensure that there are no more than {max_digits} digits in total.'), 

1008 'max_decimal_places': _('Ensure that there are no more than {max_decimal_places} decimal places.'), 

1009 'max_whole_digits': _('Ensure that there are no more than {max_whole_digits} digits before the decimal point.'), 

1010 'max_string_length': _('String value too large.') 

1011 } 

1012 MAX_STRING_LENGTH = 1000 # Guard against malicious string inputs. 

1013 

1014 def __init__(self, max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None, 

1015 localize=False, rounding=None, **kwargs): 

1016 self.max_digits = max_digits 

1017 self.decimal_places = decimal_places 

1018 self.localize = localize 

1019 if coerce_to_string is not None: 1019 ↛ 1020line 1019 didn't jump to line 1020, because the condition on line 1019 was never true

1020 self.coerce_to_string = coerce_to_string 

1021 if self.localize: 1021 ↛ 1022line 1021 didn't jump to line 1022, because the condition on line 1021 was never true

1022 self.coerce_to_string = True 

1023 

1024 self.max_value = max_value 

1025 self.min_value = min_value 

1026 

1027 if self.max_digits is not None and self.decimal_places is not None: 1027 ↛ 1030line 1027 didn't jump to line 1030, because the condition on line 1027 was never false

1028 self.max_whole_digits = self.max_digits - self.decimal_places 

1029 else: 

1030 self.max_whole_digits = None 

1031 

1032 super().__init__(**kwargs) 

1033 

1034 if self.max_value is not None: 1034 ↛ 1035line 1034 didn't jump to line 1035, because the condition on line 1034 was never true

1035 message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) 

1036 self.validators.append( 

1037 MaxValueValidator(self.max_value, message=message)) 

1038 if self.min_value is not None: 1038 ↛ 1039line 1038 didn't jump to line 1039, because the condition on line 1038 was never true

1039 message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) 

1040 self.validators.append( 

1041 MinValueValidator(self.min_value, message=message)) 

1042 

1043 if rounding is not None: 1043 ↛ 1044line 1043 didn't jump to line 1044, because the condition on line 1043 was never true

1044 valid_roundings = [v for k, v in vars(decimal).items() if k.startswith('ROUND_')] 

1045 assert rounding in valid_roundings, ( 

1046 'Invalid rounding option %s. Valid values for rounding are: %s' % (rounding, valid_roundings)) 

1047 self.rounding = rounding 

1048 

1049 def validate_empty_values(self, data): 

1050 if smart_str(data).strip() == '' and self.allow_null: 1050 ↛ 1051line 1050 didn't jump to line 1051, because the condition on line 1050 was never true

1051 return (True, None) 

1052 return super().validate_empty_values(data) 

1053 

1054 def to_internal_value(self, data): 

1055 """ 

1056 Validate that the input is a decimal number and return a Decimal 

1057 instance. 

1058 """ 

1059 

1060 data = smart_str(data).strip() 

1061 

1062 if self.localize: 1062 ↛ 1063line 1062 didn't jump to line 1063, because the condition on line 1062 was never true

1063 data = sanitize_separators(data) 

1064 

1065 if len(data) > self.MAX_STRING_LENGTH: 1065 ↛ 1066line 1065 didn't jump to line 1066, because the condition on line 1065 was never true

1066 self.fail('max_string_length') 

1067 

1068 try: 

1069 value = decimal.Decimal(data) 

1070 except decimal.DecimalException: 

1071 self.fail('invalid') 

1072 

1073 if value.is_nan(): 1073 ↛ 1074line 1073 didn't jump to line 1074, because the condition on line 1073 was never true

1074 self.fail('invalid') 

1075 

1076 # Check for infinity and negative infinity. 

1077 if value in (decimal.Decimal('Inf'), decimal.Decimal('-Inf')): 1077 ↛ 1078line 1077 didn't jump to line 1078, because the condition on line 1077 was never true

1078 self.fail('invalid') 

1079 

1080 return self.quantize(self.validate_precision(value)) 

1081 

1082 def validate_precision(self, value): 

1083 """ 

1084 Ensure that there are no more than max_digits in the number, and no 

1085 more than decimal_places digits after the decimal point. 

1086 

1087 Override this method to disable the precision validation for input 

1088 values or to enhance it in any way you need to. 

1089 """ 

1090 sign, digittuple, exponent = value.as_tuple() 

1091 

1092 if exponent >= 0: 

1093 # 1234500.0 

1094 total_digits = len(digittuple) + exponent 

1095 whole_digits = total_digits 

1096 decimal_places = 0 

1097 elif len(digittuple) > abs(exponent): 1097 ↛ 1104line 1097 didn't jump to line 1104, because the condition on line 1097 was never false

1098 # 123.45 

1099 total_digits = len(digittuple) 

1100 whole_digits = total_digits - abs(exponent) 

1101 decimal_places = abs(exponent) 

1102 else: 

1103 # 0.001234 

1104 total_digits = abs(exponent) 

1105 whole_digits = 0 

1106 decimal_places = total_digits 

1107 

1108 if self.max_digits is not None and total_digits > self.max_digits: 1108 ↛ 1109line 1108 didn't jump to line 1109, because the condition on line 1108 was never true

1109 self.fail('max_digits', max_digits=self.max_digits) 

1110 if self.decimal_places is not None and decimal_places > self.decimal_places: 1110 ↛ 1111line 1110 didn't jump to line 1111, because the condition on line 1110 was never true

1111 self.fail('max_decimal_places', max_decimal_places=self.decimal_places) 

1112 if self.max_whole_digits is not None and whole_digits > self.max_whole_digits: 1112 ↛ 1113line 1112 didn't jump to line 1113, because the condition on line 1112 was never true

1113 self.fail('max_whole_digits', max_whole_digits=self.max_whole_digits) 

1114 

1115 return value 

1116 

1117 def to_representation(self, value): 

1118 coerce_to_string = getattr(self, 'coerce_to_string', api_settings.COERCE_DECIMAL_TO_STRING) 

1119 

1120 if value is None: 1120 ↛ 1121line 1120 didn't jump to line 1121, because the condition on line 1120 was never true

1121 if coerce_to_string: 

1122 return '' 

1123 else: 

1124 return None 

1125 

1126 if not isinstance(value, decimal.Decimal): 

1127 value = decimal.Decimal(str(value).strip()) 

1128 

1129 quantized = self.quantize(value) 

1130 

1131 if not coerce_to_string: 1131 ↛ 1132line 1131 didn't jump to line 1132, because the condition on line 1131 was never true

1132 return quantized 

1133 if self.localize: 1133 ↛ 1134line 1133 didn't jump to line 1134, because the condition on line 1133 was never true

1134 return localize_input(quantized) 

1135 

1136 return '{:f}'.format(quantized) 

1137 

1138 def quantize(self, value): 

1139 """ 

1140 Quantize the decimal value to the configured precision. 

1141 """ 

1142 if self.decimal_places is None: 1142 ↛ 1143line 1142 didn't jump to line 1143, because the condition on line 1142 was never true

1143 return value 

1144 

1145 context = decimal.getcontext().copy() 

1146 if self.max_digits is not None: 1146 ↛ 1148line 1146 didn't jump to line 1148, because the condition on line 1146 was never false

1147 context.prec = self.max_digits 

1148 return value.quantize( 

1149 decimal.Decimal('.1') ** self.decimal_places, 

1150 rounding=self.rounding, 

1151 context=context 

1152 ) 

1153 

1154 

1155# Date & time fields... 

1156 

1157class DateTimeField(Field): 

1158 default_error_messages = { 

1159 'invalid': _('Datetime has wrong format. Use one of these formats instead: {format}.'), 

1160 'date': _('Expected a datetime but got a date.'), 

1161 'make_aware': _('Invalid datetime for the timezone "{timezone}".'), 

1162 'overflow': _('Datetime value out of range.') 

1163 } 

1164 datetime_parser = datetime.datetime.strptime 

1165 

1166 def __init__(self, format=empty, input_formats=None, default_timezone=None, **kwargs): 

1167 if format is not empty: 1167 ↛ 1168line 1167 didn't jump to line 1168, because the condition on line 1167 was never true

1168 self.format = format 

1169 if input_formats is not None: 1169 ↛ 1170line 1169 didn't jump to line 1170, because the condition on line 1169 was never true

1170 self.input_formats = input_formats 

1171 if default_timezone is not None: 1171 ↛ 1172line 1171 didn't jump to line 1172, because the condition on line 1171 was never true

1172 self.timezone = default_timezone 

1173 super().__init__(**kwargs) 

1174 

1175 def enforce_timezone(self, value): 

1176 """ 

1177 When `self.default_timezone` is `None`, always return naive datetimes. 

1178 When `self.default_timezone` is not `None`, always return aware datetimes. 

1179 """ 

1180 field_timezone = getattr(self, 'timezone', self.default_timezone()) 

1181 

1182 if field_timezone is not None: 1182 ↛ 1192line 1182 didn't jump to line 1192, because the condition on line 1182 was never false

1183 if timezone.is_aware(value): 1183 ↛ 1188line 1183 didn't jump to line 1188, because the condition on line 1183 was never false

1184 try: 

1185 return value.astimezone(field_timezone) 

1186 except OverflowError: 

1187 self.fail('overflow') 

1188 try: 

1189 return timezone.make_aware(value, field_timezone) 

1190 except InvalidTimeError: 

1191 self.fail('make_aware', timezone=field_timezone) 

1192 elif (field_timezone is None) and timezone.is_aware(value): 

1193 return timezone.make_naive(value, utc) 

1194 return value 

1195 

1196 def default_timezone(self): 

1197 return timezone.get_current_timezone() if settings.USE_TZ else None 

1198 

1199 def to_internal_value(self, value): 

1200 input_formats = getattr(self, 'input_formats', api_settings.DATETIME_INPUT_FORMATS) 

1201 

1202 if isinstance(value, datetime.date) and not isinstance(value, datetime.datetime): 

1203 self.fail('date') 

1204 

1205 if isinstance(value, datetime.datetime): 

1206 return self.enforce_timezone(value) 

1207 

1208 for input_format in input_formats: 

1209 if input_format.lower() == ISO_8601: 

1210 try: 

1211 parsed = parse_datetime(value) 

1212 if parsed is not None: 

1213 return self.enforce_timezone(parsed) 

1214 except (ValueError, TypeError): 

1215 pass 

1216 else: 

1217 try: 

1218 parsed = self.datetime_parser(value, input_format) 

1219 return self.enforce_timezone(parsed) 

1220 except (ValueError, TypeError): 

1221 pass 

1222 

1223 humanized_format = humanize_datetime.datetime_formats(input_formats) 

1224 self.fail('invalid', format=humanized_format) 

1225 

1226 def to_representation(self, value): 

1227 if not value: 1227 ↛ 1228line 1227 didn't jump to line 1228, because the condition on line 1227 was never true

1228 return None 

1229 

1230 output_format = getattr(self, 'format', api_settings.DATETIME_FORMAT) 

1231 

1232 if output_format is None or isinstance(value, str): 1232 ↛ 1233line 1232 didn't jump to line 1233, because the condition on line 1232 was never true

1233 return value 

1234 

1235 value = self.enforce_timezone(value) 

1236 

1237 if output_format.lower() == ISO_8601: 1237 ↛ 1242line 1237 didn't jump to line 1242, because the condition on line 1237 was never false

1238 value = value.isoformat() 

1239 if value.endswith('+00:00'): 1239 ↛ 1240line 1239 didn't jump to line 1240, because the condition on line 1239 was never true

1240 value = value[:-6] + 'Z' 

1241 return value 

1242 return value.strftime(output_format) 

1243 

1244 

1245class DateField(Field): 

1246 default_error_messages = { 

1247 'invalid': _('Date has wrong format. Use one of these formats instead: {format}.'), 

1248 'datetime': _('Expected a date but got a datetime.'), 

1249 } 

1250 datetime_parser = datetime.datetime.strptime 

1251 

1252 def __init__(self, format=empty, input_formats=None, **kwargs): 

1253 if format is not empty: 1253 ↛ 1254line 1253 didn't jump to line 1254, because the condition on line 1253 was never true

1254 self.format = format 

1255 if input_formats is not None: 1255 ↛ 1256line 1255 didn't jump to line 1256, because the condition on line 1255 was never true

1256 self.input_formats = input_formats 

1257 super().__init__(**kwargs) 

1258 

1259 def to_internal_value(self, value): 

1260 input_formats = getattr(self, 'input_formats', api_settings.DATE_INPUT_FORMATS) 

1261 

1262 if isinstance(value, datetime.datetime): 1262 ↛ 1263line 1262 didn't jump to line 1263, because the condition on line 1262 was never true

1263 self.fail('datetime') 

1264 

1265 if isinstance(value, datetime.date): 1265 ↛ 1266line 1265 didn't jump to line 1266, because the condition on line 1265 was never true

1266 return value 

1267 

1268 for input_format in input_formats: 1268 ↛ 1285line 1268 didn't jump to line 1285, because the loop on line 1268 didn't complete

1269 if input_format.lower() == ISO_8601: 1269 ↛ 1278line 1269 didn't jump to line 1278, because the condition on line 1269 was never false

1270 try: 

1271 parsed = parse_date(value) 

1272 except (ValueError, TypeError): 

1273 pass 

1274 else: 

1275 if parsed is not None: 1275 ↛ 1268line 1275 didn't jump to line 1268, because the condition on line 1275 was never false

1276 return parsed 

1277 else: 

1278 try: 

1279 parsed = self.datetime_parser(value, input_format) 

1280 except (ValueError, TypeError): 

1281 pass 

1282 else: 

1283 return parsed.date() 

1284 

1285 humanized_format = humanize_datetime.date_formats(input_formats) 

1286 self.fail('invalid', format=humanized_format) 

1287 

1288 def to_representation(self, value): 

1289 if not value: 1289 ↛ 1290line 1289 didn't jump to line 1290, because the condition on line 1289 was never true

1290 return None 

1291 

1292 output_format = getattr(self, 'format', api_settings.DATE_FORMAT) 

1293 

1294 if output_format is None or isinstance(value, str): 

1295 return value 

1296 

1297 # Applying a `DateField` to a datetime value is almost always 

1298 # not a sensible thing to do, as it means naively dropping 

1299 # any explicit or implicit timezone info. 

1300 assert not isinstance(value, datetime.datetime), ( 

1301 'Expected a `date`, but got a `datetime`. Refusing to coerce, ' 

1302 'as this may mean losing timezone information. Use a custom ' 

1303 'read-only field and deal with timezone issues explicitly.' 

1304 ) 

1305 

1306 if output_format.lower() == ISO_8601: 1306 ↛ 1309line 1306 didn't jump to line 1309, because the condition on line 1306 was never false

1307 return value.isoformat() 

1308 

1309 return value.strftime(output_format) 

1310 

1311 

1312class TimeField(Field): 

1313 default_error_messages = { 

1314 'invalid': _('Time has wrong format. Use one of these formats instead: {format}.'), 

1315 } 

1316 datetime_parser = datetime.datetime.strptime 

1317 

1318 def __init__(self, format=empty, input_formats=None, **kwargs): 

1319 if format is not empty: 1319 ↛ 1320line 1319 didn't jump to line 1320, because the condition on line 1319 was never true

1320 self.format = format 

1321 if input_formats is not None: 1321 ↛ 1322line 1321 didn't jump to line 1322, because the condition on line 1321 was never true

1322 self.input_formats = input_formats 

1323 super().__init__(**kwargs) 

1324 

1325 def to_internal_value(self, value): 

1326 input_formats = getattr(self, 'input_formats', api_settings.TIME_INPUT_FORMATS) 

1327 

1328 if isinstance(value, datetime.time): 1328 ↛ 1329line 1328 didn't jump to line 1329, because the condition on line 1328 was never true

1329 return value 

1330 

1331 for input_format in input_formats: 1331 ↛ 1348line 1331 didn't jump to line 1348, because the loop on line 1331 didn't complete

1332 if input_format.lower() == ISO_8601: 1332 ↛ 1341line 1332 didn't jump to line 1341, because the condition on line 1332 was never false

1333 try: 

1334 parsed = parse_time(value) 

1335 except (ValueError, TypeError): 

1336 pass 

1337 else: 

1338 if parsed is not None: 1338 ↛ 1331line 1338 didn't jump to line 1331, because the condition on line 1338 was never false

1339 return parsed 

1340 else: 

1341 try: 

1342 parsed = self.datetime_parser(value, input_format) 

1343 except (ValueError, TypeError): 

1344 pass 

1345 else: 

1346 return parsed.time() 

1347 

1348 humanized_format = humanize_datetime.time_formats(input_formats) 

1349 self.fail('invalid', format=humanized_format) 

1350 

1351 def to_representation(self, value): 

1352 if value in (None, ''): 1352 ↛ 1353line 1352 didn't jump to line 1353, because the condition on line 1352 was never true

1353 return None 

1354 

1355 output_format = getattr(self, 'format', api_settings.TIME_FORMAT) 

1356 

1357 if output_format is None or isinstance(value, str): 1357 ↛ 1358line 1357 didn't jump to line 1358, because the condition on line 1357 was never true

1358 return value 

1359 

1360 # Applying a `TimeField` to a datetime value is almost always 

1361 # not a sensible thing to do, as it means naively dropping 

1362 # any explicit or implicit timezone info. 

1363 assert not isinstance(value, datetime.datetime), ( 

1364 'Expected a `time`, but got a `datetime`. Refusing to coerce, ' 

1365 'as this may mean losing timezone information. Use a custom ' 

1366 'read-only field and deal with timezone issues explicitly.' 

1367 ) 

1368 

1369 if output_format.lower() == ISO_8601: 1369 ↛ 1371line 1369 didn't jump to line 1371, because the condition on line 1369 was never false

1370 return value.isoformat() 

1371 return value.strftime(output_format) 

1372 

1373 

1374class DurationField(Field): 

1375 default_error_messages = { 

1376 'invalid': _('Duration has wrong format. Use one of these formats instead: {format}.'), 

1377 'max_value': _('Ensure this value is less than or equal to {max_value}.'), 

1378 'min_value': _('Ensure this value is greater than or equal to {min_value}.'), 

1379 } 

1380 

1381 def __init__(self, **kwargs): 

1382 self.max_value = kwargs.pop('max_value', None) 

1383 self.min_value = kwargs.pop('min_value', None) 

1384 super().__init__(**kwargs) 

1385 if self.max_value is not None: 

1386 message = lazy_format(self.error_messages['max_value'], max_value=self.max_value) 

1387 self.validators.append( 

1388 MaxValueValidator(self.max_value, message=message)) 

1389 if self.min_value is not None: 

1390 message = lazy_format(self.error_messages['min_value'], min_value=self.min_value) 

1391 self.validators.append( 

1392 MinValueValidator(self.min_value, message=message)) 

1393 

1394 def to_internal_value(self, value): 

1395 if isinstance(value, datetime.timedelta): 

1396 return value 

1397 parsed = parse_duration(str(value)) 

1398 if parsed is not None: 

1399 return parsed 

1400 self.fail('invalid', format='[DD] [HH:[MM:]]ss[.uuuuuu]') 

1401 

1402 def to_representation(self, value): 

1403 return duration_string(value) 

1404 

1405 

1406# Choice types... 

1407 

1408class ChoiceField(Field): 

1409 default_error_messages = { 

1410 'invalid_choice': _('"{input}" is not a valid choice.') 

1411 } 

1412 html_cutoff = None 

1413 html_cutoff_text = _('More than {count} items...') 

1414 

1415 def __init__(self, choices, **kwargs): 

1416 self.choices = choices 

1417 self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff) 

1418 self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text) 

1419 

1420 self.allow_blank = kwargs.pop('allow_blank', False) 

1421 

1422 super().__init__(**kwargs) 

1423 

1424 def to_internal_value(self, data): 

1425 if data == '' and self.allow_blank: 1425 ↛ 1426line 1425 didn't jump to line 1426, because the condition on line 1425 was never true

1426 return '' 

1427 

1428 try: 

1429 return self.choice_strings_to_values[str(data)] 

1430 except KeyError: 

1431 self.fail('invalid_choice', input=data) 

1432 

1433 def to_representation(self, value): 

1434 if value in ('', None): 1434 ↛ 1435line 1434 didn't jump to line 1435, because the condition on line 1434 was never true

1435 return value 

1436 return self.choice_strings_to_values.get(str(value), value) 

1437 

1438 def iter_options(self): 

1439 """ 

1440 Helper method for use with templates rendering select widgets. 

1441 """ 

1442 return iter_options( 

1443 self.grouped_choices, 

1444 cutoff=self.html_cutoff, 

1445 cutoff_text=self.html_cutoff_text 

1446 ) 

1447 

1448 def _get_choices(self): 

1449 return self._choices 

1450 

1451 def _set_choices(self, choices): 

1452 self.grouped_choices = to_choices_dict(choices) 

1453 self._choices = flatten_choices_dict(self.grouped_choices) 

1454 

1455 # Map the string representation of choices to the underlying value. 

1456 # Allows us to deal with eg. integer choices while supporting either 

1457 # integer or string input, but still get the correct datatype out. 

1458 self.choice_strings_to_values = { 

1459 str(key): key for key in self.choices 

1460 } 

1461 

1462 choices = property(_get_choices, _set_choices) 

1463 

1464 

1465class MultipleChoiceField(ChoiceField): 

1466 default_error_messages = { 

1467 'invalid_choice': _('"{input}" is not a valid choice.'), 

1468 'not_a_list': _('Expected a list of items but got type "{input_type}".'), 

1469 'empty': _('This selection may not be empty.') 

1470 } 

1471 default_empty_html = [] 

1472 

1473 def __init__(self, **kwargs): 

1474 self.allow_empty = kwargs.pop('allow_empty', True) 

1475 super().__init__(**kwargs) 

1476 

1477 def get_value(self, dictionary): 

1478 if self.field_name not in dictionary: 

1479 if getattr(self.root, 'partial', False): 

1480 return empty 

1481 # We override the default field access in order to support 

1482 # lists in HTML forms. 

1483 if html.is_html_input(dictionary): 

1484 return dictionary.getlist(self.field_name) 

1485 return dictionary.get(self.field_name, empty) 

1486 

1487 def to_internal_value(self, data): 

1488 if isinstance(data, str) or not hasattr(data, '__iter__'): 

1489 self.fail('not_a_list', input_type=type(data).__name__) 

1490 if not self.allow_empty and len(data) == 0: 

1491 self.fail('empty') 

1492 

1493 return { 

1494 # Arguments for super() are needed because of scoping inside 

1495 # comprehensions. 

1496 super(MultipleChoiceField, self).to_internal_value(item) 

1497 for item in data 

1498 } 

1499 

1500 def to_representation(self, value): 

1501 return { 

1502 self.choice_strings_to_values.get(str(item), item) for item in value 

1503 } 

1504 

1505 

1506class FilePathField(ChoiceField): 

1507 default_error_messages = { 

1508 'invalid_choice': _('"{input}" is not a valid path choice.') 

1509 } 

1510 

1511 def __init__(self, path, match=None, recursive=False, allow_files=True, 

1512 allow_folders=False, required=None, **kwargs): 

1513 # Defer to Django's FilePathField implementation to get the 

1514 # valid set of choices. 

1515 field = DjangoFilePathField( 

1516 path, match=match, recursive=recursive, allow_files=allow_files, 

1517 allow_folders=allow_folders, required=required 

1518 ) 

1519 kwargs['choices'] = field.choices 

1520 super().__init__(**kwargs) 

1521 

1522 

1523# File types... 

1524 

1525class FileField(Field): 

1526 default_error_messages = { 

1527 'required': _('No file was submitted.'), 

1528 'invalid': _('The submitted data was not a file. Check the encoding type on the form.'), 

1529 'no_name': _('No filename could be determined.'), 

1530 'empty': _('The submitted file is empty.'), 

1531 'max_length': _('Ensure this filename has at most {max_length} characters (it has {length}).'), 

1532 } 

1533 

1534 def __init__(self, **kwargs): 

1535 self.max_length = kwargs.pop('max_length', None) 

1536 self.allow_empty_file = kwargs.pop('allow_empty_file', False) 

1537 if 'use_url' in kwargs: 1537 ↛ 1538line 1537 didn't jump to line 1538, because the condition on line 1537 was never true

1538 self.use_url = kwargs.pop('use_url') 

1539 super().__init__(**kwargs) 

1540 

1541 def to_internal_value(self, data): 

1542 try: 

1543 # `UploadedFile` objects should have name and size attributes. 

1544 file_name = data.name 

1545 file_size = data.size 

1546 except AttributeError: 

1547 self.fail('invalid') 

1548 

1549 if not file_name: 1549 ↛ 1550line 1549 didn't jump to line 1550, because the condition on line 1549 was never true

1550 self.fail('no_name') 

1551 if not self.allow_empty_file and not file_size: 1551 ↛ 1552line 1551 didn't jump to line 1552, because the condition on line 1551 was never true

1552 self.fail('empty') 

1553 if self.max_length and len(file_name) > self.max_length: 1553 ↛ 1554line 1553 didn't jump to line 1554, because the condition on line 1553 was never true

1554 self.fail('max_length', max_length=self.max_length, length=len(file_name)) 

1555 

1556 return data 

1557 

1558 def to_representation(self, value): 

1559 if not value: 

1560 return None 

1561 

1562 use_url = getattr(self, 'use_url', api_settings.UPLOADED_FILES_USE_URL) 

1563 if use_url: 1563 ↛ 1573line 1563 didn't jump to line 1573, because the condition on line 1563 was never false

1564 try: 

1565 url = value.url 

1566 except AttributeError: 

1567 return None 

1568 request = self.context.get('request', None) 

1569 if request is not None: 

1570 return request.build_absolute_uri(url) 

1571 return url 

1572 

1573 return value.name 

1574 

1575 

1576class ImageField(FileField): 

1577 default_error_messages = { 

1578 'invalid_image': _( 

1579 'Upload a valid image. The file you uploaded was either not an image or a corrupted image.' 

1580 ), 

1581 } 

1582 

1583 def __init__(self, **kwargs): 

1584 self._DjangoImageField = kwargs.pop('_DjangoImageField', DjangoImageField) 

1585 super().__init__(**kwargs) 

1586 

1587 def to_internal_value(self, data): 

1588 # Image validation is a bit grungy, so we'll just outright 

1589 # defer to Django's implementation so we don't need to 

1590 # consider it, or treat PIL as a test dependency. 

1591 file_object = super().to_internal_value(data) 

1592 django_field = self._DjangoImageField() 

1593 django_field.error_messages = self.error_messages 

1594 return django_field.clean(file_object) 

1595 

1596 

1597# Composite field types... 

1598 

1599class _UnvalidatedField(Field): 

1600 def __init__(self, **kwargs): 

1601 super().__init__(**kwargs) 

1602 self.allow_blank = True 

1603 self.allow_null = True 

1604 

1605 def to_internal_value(self, data): 

1606 return data 

1607 

1608 def to_representation(self, value): 

1609 return value 

1610 

1611 

1612class ListField(Field): 

1613 child = _UnvalidatedField() 

1614 initial = [] 

1615 default_error_messages = { 

1616 'not_a_list': _('Expected a list of items but got type "{input_type}".'), 

1617 'empty': _('This list may not be empty.'), 

1618 'min_length': _('Ensure this field has at least {min_length} elements.'), 

1619 'max_length': _('Ensure this field has no more than {max_length} elements.') 

1620 } 

1621 

1622 def __init__(self, **kwargs): 

1623 self.child = kwargs.pop('child', copy.deepcopy(self.child)) 

1624 self.allow_empty = kwargs.pop('allow_empty', True) 

1625 self.max_length = kwargs.pop('max_length', None) 

1626 self.min_length = kwargs.pop('min_length', None) 

1627 

1628 assert not inspect.isclass(self.child), '`child` has not been instantiated.' 

1629 assert self.child.source is None, ( 

1630 "The `source` argument is not meaningful when applied to a `child=` field. " 

1631 "Remove `source=` from the field declaration." 

1632 ) 

1633 

1634 super().__init__(**kwargs) 

1635 self.child.bind(field_name='', parent=self) 

1636 if self.max_length is not None: 

1637 message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) 

1638 self.validators.append(MaxLengthValidator(self.max_length, message=message)) 

1639 if self.min_length is not None: 

1640 message = lazy_format(self.error_messages['min_length'], min_length=self.min_length) 

1641 self.validators.append(MinLengthValidator(self.min_length, message=message)) 

1642 

1643 def get_value(self, dictionary): 

1644 if self.field_name not in dictionary: 

1645 if getattr(self.root, 'partial', False): 

1646 return empty 

1647 # We override the default field access in order to support 

1648 # lists in HTML forms. 

1649 if html.is_html_input(dictionary): 

1650 val = dictionary.getlist(self.field_name, []) 

1651 if len(val) > 0: 

1652 # Support QueryDict lists in HTML input. 

1653 return val 

1654 return html.parse_html_list(dictionary, prefix=self.field_name, default=empty) 

1655 

1656 return dictionary.get(self.field_name, empty) 

1657 

1658 def to_internal_value(self, data): 

1659 """ 

1660 List of dicts of native values <- List of dicts of primitive datatypes. 

1661 """ 

1662 if html.is_html_input(data): 

1663 data = html.parse_html_list(data, default=[]) 

1664 if isinstance(data, (str, Mapping)) or not hasattr(data, '__iter__'): 

1665 self.fail('not_a_list', input_type=type(data).__name__) 

1666 if not self.allow_empty and len(data) == 0: 

1667 self.fail('empty') 

1668 return self.run_child_validation(data) 

1669 

1670 def to_representation(self, data): 

1671 """ 

1672 List of object instances -> List of dicts of primitive datatypes. 

1673 """ 

1674 return [self.child.to_representation(item) if item is not None else None for item in data] 

1675 

1676 def run_child_validation(self, data): 

1677 result = [] 

1678 errors = OrderedDict() 

1679 

1680 for idx, item in enumerate(data): 

1681 try: 

1682 result.append(self.child.run_validation(item)) 

1683 except ValidationError as e: 

1684 errors[idx] = e.detail 

1685 

1686 if not errors: 

1687 return result 

1688 raise ValidationError(errors) 

1689 

1690 

1691class DictField(Field): 

1692 child = _UnvalidatedField() 

1693 initial = {} 

1694 default_error_messages = { 

1695 'not_a_dict': _('Expected a dictionary of items but got type "{input_type}".'), 

1696 'empty': _('This dictionary may not be empty.'), 

1697 } 

1698 

1699 def __init__(self, **kwargs): 

1700 self.child = kwargs.pop('child', copy.deepcopy(self.child)) 

1701 self.allow_empty = kwargs.pop('allow_empty', True) 

1702 

1703 assert not inspect.isclass(self.child), '`child` has not been instantiated.' 

1704 assert self.child.source is None, ( 

1705 "The `source` argument is not meaningful when applied to a `child=` field. " 

1706 "Remove `source=` from the field declaration." 

1707 ) 

1708 

1709 super().__init__(**kwargs) 

1710 self.child.bind(field_name='', parent=self) 

1711 

1712 def get_value(self, dictionary): 

1713 # We override the default field access in order to support 

1714 # dictionaries in HTML forms. 

1715 if html.is_html_input(dictionary): 

1716 return html.parse_html_dict(dictionary, prefix=self.field_name) 

1717 return dictionary.get(self.field_name, empty) 

1718 

1719 def to_internal_value(self, data): 

1720 """ 

1721 Dicts of native values <- Dicts of primitive datatypes. 

1722 """ 

1723 if html.is_html_input(data): 

1724 data = html.parse_html_dict(data) 

1725 if not isinstance(data, dict): 

1726 self.fail('not_a_dict', input_type=type(data).__name__) 

1727 if not self.allow_empty and len(data) == 0: 1727 ↛ 1728line 1727 didn't jump to line 1728, because the condition on line 1727 was never true

1728 self.fail('empty') 

1729 

1730 return self.run_child_validation(data) 

1731 

1732 def to_representation(self, value): 

1733 return { 

1734 str(key): self.child.to_representation(val) if val is not None else None 

1735 for key, val in value.items() 

1736 } 

1737 

1738 def run_child_validation(self, data): 

1739 result = {} 

1740 errors = OrderedDict() 

1741 

1742 for key, value in data.items(): 

1743 key = str(key) 

1744 

1745 try: 

1746 result[key] = self.child.run_validation(value) 

1747 except ValidationError as e: 

1748 errors[key] = e.detail 

1749 

1750 if not errors: 1750 ↛ 1752line 1750 didn't jump to line 1752, because the condition on line 1750 was never false

1751 return result 

1752 raise ValidationError(errors) 

1753 

1754 

1755class HStoreField(DictField): 

1756 child = CharField(allow_blank=True, allow_null=True) 

1757 

1758 def __init__(self, **kwargs): 

1759 super().__init__(**kwargs) 

1760 assert isinstance(self.child, CharField), ( 

1761 "The `child` argument must be an instance of `CharField`, " 

1762 "as the hstore extension stores values as strings." 

1763 ) 

1764 

1765 

1766class JSONField(Field): 

1767 default_error_messages = { 

1768 'invalid': _('Value must be valid JSON.') 

1769 } 

1770 

1771 # Workaround for isinstance calls when importing the field isn't possible 

1772 _is_jsonfield = True 

1773 

1774 def __init__(self, **kwargs): 

1775 self.binary = kwargs.pop('binary', False) 

1776 self.encoder = kwargs.pop('encoder', None) 

1777 self.decoder = kwargs.pop('decoder', None) 

1778 super().__init__(**kwargs) 

1779 

1780 def get_value(self, dictionary): 

1781 if html.is_html_input(dictionary) and self.field_name in dictionary: 1781 ↛ 1784line 1781 didn't jump to line 1784, because the condition on line 1781 was never true

1782 # When HTML form input is used, mark up the input 

1783 # as being a JSON string, rather than a JSON primitive. 

1784 class JSONString(str): 

1785 def __new__(cls, value): 

1786 ret = str.__new__(cls, value) 

1787 ret.is_json_string = True 

1788 return ret 

1789 return JSONString(dictionary[self.field_name]) 

1790 return dictionary.get(self.field_name, empty) 

1791 

1792 def to_internal_value(self, data): 

1793 try: 

1794 if self.binary or getattr(data, 'is_json_string', False): 1794 ↛ 1795line 1794 didn't jump to line 1795, because the condition on line 1794 was never true

1795 if isinstance(data, bytes): 

1796 data = data.decode() 

1797 return json.loads(data, cls=self.decoder) 

1798 else: 

1799 json.dumps(data, cls=self.encoder) 

1800 except (TypeError, ValueError): 

1801 self.fail('invalid') 

1802 return data 

1803 

1804 def to_representation(self, value): 

1805 if self.binary: 1805 ↛ 1806line 1805 didn't jump to line 1806, because the condition on line 1805 was never true

1806 value = json.dumps(value, cls=self.encoder) 

1807 value = value.encode() 

1808 return value 

1809 

1810 

1811# Miscellaneous field types... 

1812 

1813class ReadOnlyField(Field): 

1814 """ 

1815 A read-only field that simply returns the field value. 

1816 

1817 If the field is a method with no parameters, the method will be called 

1818 and its return value used as the representation. 

1819 

1820 For example, the following would call `get_expiry_date()` on the object: 

1821 

1822 class ExampleSerializer(Serializer): 

1823 expiry_date = ReadOnlyField(source='get_expiry_date') 

1824 """ 

1825 

1826 def __init__(self, **kwargs): 

1827 kwargs['read_only'] = True 

1828 super().__init__(**kwargs) 

1829 

1830 def to_representation(self, value): 

1831 return value 

1832 

1833 

1834class HiddenField(Field): 

1835 """ 

1836 A hidden field does not take input from the user, or present any output, 

1837 but it does populate a field in `validated_data`, based on its default 

1838 value. This is particularly useful when we have a `unique_for_date` 

1839 constraint on a pair of fields, as we need some way to include the date in 

1840 the validated data. 

1841 """ 

1842 def __init__(self, **kwargs): 

1843 assert 'default' in kwargs, 'default is a required argument.' 

1844 kwargs['write_only'] = True 

1845 super().__init__(**kwargs) 

1846 

1847 def get_value(self, dictionary): 

1848 # We always use the default value for `HiddenField`. 

1849 # User input is never provided or accepted. 

1850 return empty 

1851 

1852 def to_internal_value(self, data): 

1853 return data 

1854 

1855 

1856class SerializerMethodField(Field): 

1857 """ 

1858 A read-only field that get its representation from calling a method on the 

1859 parent serializer class. The method called will be of the form 

1860 "get_{field_name}", and should take a single argument, which is the 

1861 object being serialized. 

1862 

1863 For example: 

1864 

1865 class ExampleSerializer(self): 

1866 extra_info = SerializerMethodField() 

1867 

1868 def get_extra_info(self, obj): 

1869 return ... # Calculate some data to return. 

1870 """ 

1871 def __init__(self, method_name=None, **kwargs): 

1872 self.method_name = method_name 

1873 kwargs['source'] = '*' 

1874 kwargs['read_only'] = True 

1875 super().__init__(**kwargs) 

1876 

1877 def bind(self, field_name, parent): 

1878 # The method name defaults to `get_{field_name}`. 

1879 if self.method_name is None: 1879 ↛ 1882line 1879 didn't jump to line 1882, because the condition on line 1879 was never false

1880 self.method_name = 'get_{field_name}'.format(field_name=field_name) 

1881 

1882 super().bind(field_name, parent) 

1883 

1884 def to_representation(self, value): 

1885 method = getattr(self.parent, self.method_name) 

1886 return method(value) 

1887 

1888 

1889class ModelField(Field): 

1890 """ 

1891 A generic field that can be used against an arbitrary model field. 

1892 

1893 This is used by `ModelSerializer` when dealing with custom model fields, 

1894 that do not have a serializer field to be mapped to. 

1895 """ 

1896 default_error_messages = { 

1897 'max_length': _('Ensure this field has no more than {max_length} characters.'), 

1898 } 

1899 

1900 def __init__(self, model_field, **kwargs): 

1901 self.model_field = model_field 

1902 # The `max_length` option is supported by Django's base `Field` class, 

1903 # so we'd better support it here. 

1904 self.max_length = kwargs.pop('max_length', None) 

1905 super().__init__(**kwargs) 

1906 if self.max_length is not None: 

1907 message = lazy_format(self.error_messages['max_length'], max_length=self.max_length) 

1908 self.validators.append( 

1909 MaxLengthValidator(self.max_length, message=message)) 

1910 

1911 def to_internal_value(self, data): 

1912 rel = self.model_field.remote_field 

1913 if rel is not None: 

1914 return rel.model._meta.get_field(rel.field_name).to_python(data) 

1915 return self.model_field.to_python(data) 

1916 

1917 def get_attribute(self, obj): 

1918 # We pass the object instance onto `to_representation`, 

1919 # not just the field attribute. 

1920 return obj 

1921 

1922 def to_representation(self, obj): 

1923 value = self.model_field.value_from_object(obj) 

1924 if is_protected_type(value): 

1925 return value 

1926 return self.model_field.value_to_string(obj)