Coverage for /Users/davegaeddert/Developer/dropseed/plain/plain-models/plain/models/fields/__init__.py: 41%

1203 statements  

« prev     ^ index     » next       coverage.py v7.6.9, created at 2024-12-23 11:16 -0600

1import collections.abc 

2import copy 

3import datetime 

4import decimal 

5import operator 

6import uuid 

7import warnings 

8from base64 import b64decode, b64encode 

9from functools import partialmethod, total_ordering 

10 

11from plain import exceptions, preflight, validators 

12from plain.models.constants import LOOKUP_SEP 

13from plain.models.db import connection, connections, router 

14from plain.models.enums import ChoicesMeta 

15from plain.models.query_utils import DeferredAttribute, RegisterLookupMixin 

16from plain.packages import packages 

17from plain.runtime import settings 

18from plain.utils import timezone 

19from plain.utils.datastructures import DictWrapper 

20from plain.utils.dateparse import ( 

21 parse_date, 

22 parse_datetime, 

23 parse_duration, 

24 parse_time, 

25) 

26from plain.utils.duration import duration_microseconds, duration_string 

27from plain.utils.functional import Promise, cached_property 

28from plain.utils.ipv6 import clean_ipv6_address 

29from plain.utils.itercompat import is_iterable 

30 

31__all__ = [ 

32 "AutoField", 

33 "BLANK_CHOICE_DASH", 

34 "BigAutoField", 

35 "BigIntegerField", 

36 "BinaryField", 

37 "BooleanField", 

38 "CharField", 

39 "CommaSeparatedIntegerField", 

40 "DateField", 

41 "DateTimeField", 

42 "DecimalField", 

43 "DurationField", 

44 "EmailField", 

45 "Empty", 

46 "Field", 

47 "FloatField", 

48 "GenericIPAddressField", 

49 "IPAddressField", 

50 "IntegerField", 

51 "NOT_PROVIDED", 

52 "NullBooleanField", 

53 "PositiveBigIntegerField", 

54 "PositiveIntegerField", 

55 "PositiveSmallIntegerField", 

56 "SlugField", 

57 "SmallAutoField", 

58 "SmallIntegerField", 

59 "TextField", 

60 "TimeField", 

61 "URLField", 

62 "UUIDField", 

63] 

64 

65 

66class Empty: 

67 pass 

68 

69 

70class NOT_PROVIDED: 

71 pass 

72 

73 

74# The values to use for "blank" in SelectFields. Will be appended to the start 

75# of most "choices" lists. 

76BLANK_CHOICE_DASH = [("", "---------")] 

77 

78 

79def _load_field(package_label, model_name, field_name): 

80 return packages.get_model(package_label, model_name)._meta.get_field(field_name) 

81 

82 

83# A guide to Field parameters: 

84# 

85# * name: The name of the field specified in the model. 

86# * attname: The attribute to use on the model object. This is the same as 

87# "name", except in the case of ForeignKeys, where "_id" is 

88# appended. 

89# * db_column: The db_column specified in the model (or None). 

90# * column: The database column for this field. This is the same as 

91# "attname", except if db_column is specified. 

92# 

93# Code that introspects values, or does other dynamic things, should use 

94# attname. For example, this gets the primary key value of object "obj": 

95# 

96# getattr(obj, opts.pk.attname) 

97 

98 

99def _empty(of_cls): 

100 new = Empty() 

101 new.__class__ = of_cls 

102 return new 

103 

104 

105def return_None(): 

106 return None 

107 

108 

109@total_ordering 

110class Field(RegisterLookupMixin): 

111 """Base class for all field types""" 

112 

113 # Designates whether empty strings fundamentally are allowed at the 

114 # database level. 

115 empty_strings_allowed = True 

116 empty_values = list(validators.EMPTY_VALUES) 

117 

118 # These track each time a Field instance is created. Used to retain order. 

119 # The auto_creation_counter is used for fields that Plain implicitly 

120 # creates, creation_counter is used for all user-specified fields. 

121 creation_counter = 0 

122 auto_creation_counter = -1 

123 default_validators = [] # Default set of validators 

124 default_error_messages = { 

125 "invalid_choice": "Value %(value)r is not a valid choice.", 

126 "null": "This field cannot be null.", 

127 "blank": "This field cannot be blank.", 

128 "unique": "A %(model_name)s with this %(field_label)s already exists.", 

129 } 

130 system_check_deprecated_details = None 

131 system_check_removed_details = None 

132 

133 # Attributes that don't affect a column definition. 

134 # These attributes are ignored when altering the field. 

135 non_db_attrs = ( 

136 "blank", 

137 "choices", 

138 "db_column", 

139 "editable", 

140 "error_messages", 

141 "limit_choices_to", 

142 # Database-level options are not supported, see #21961. 

143 "on_delete", 

144 "related_name", 

145 "related_query_name", 

146 "validators", 

147 ) 

148 

149 # Field flags 

150 hidden = False 

151 

152 many_to_many = None 

153 many_to_one = None 

154 one_to_many = None 

155 one_to_one = None 

156 related_model = None 

157 

158 descriptor_class = DeferredAttribute 

159 

160 # Generic field type description, usually overridden by subclasses 

161 def _description(self): 

162 return f"Field of type: {self.__class__.__name__}" 

163 

164 description = property(_description) 

165 

166 def __init__( 

167 self, 

168 name=None, 

169 primary_key=False, 

170 max_length=None, 

171 unique=False, 

172 blank=False, 

173 null=False, 

174 db_index=False, 

175 rel=None, 

176 default=NOT_PROVIDED, 

177 editable=True, 

178 choices=None, 

179 db_column=None, 

180 db_tablespace=None, 

181 auto_created=False, 

182 validators=(), 

183 error_messages=None, 

184 db_comment=None, 

185 ): 

186 self.name = name 

187 self.primary_key = primary_key 

188 self.max_length, self._unique = max_length, unique 

189 self.blank, self.null = blank, null 

190 self.remote_field = rel 

191 self.is_relation = self.remote_field is not None 

192 self.default = default 

193 self.editable = editable 

194 if isinstance(choices, ChoicesMeta): 

195 choices = choices.choices 

196 if isinstance(choices, collections.abc.Iterator): 

197 choices = list(choices) 

198 self.choices = choices 

199 self.db_index = db_index 

200 self.db_column = db_column 

201 self.db_comment = db_comment 

202 self._db_tablespace = db_tablespace 

203 self.auto_created = auto_created 

204 

205 # Adjust the appropriate creation counter, and save our local copy. 

206 if auto_created: 

207 self.creation_counter = Field.auto_creation_counter 

208 Field.auto_creation_counter -= 1 

209 else: 

210 self.creation_counter = Field.creation_counter 

211 Field.creation_counter += 1 

212 

213 self._validators = list(validators) # Store for deconstruction later 

214 

215 self._error_messages = error_messages # Store for deconstruction later 

216 

217 def __str__(self): 

218 """ 

219 Return "package_label.model_label.field_name" for fields attached to 

220 models. 

221 """ 

222 if not hasattr(self, "model"): 

223 return super().__str__() 

224 model = self.model 

225 return f"{model._meta.label}.{self.name}" 

226 

227 def __repr__(self): 

228 """Display the module, class, and name of the field.""" 

229 path = f"{self.__class__.__module__}.{self.__class__.__qualname__}" 

230 name = getattr(self, "name", None) 

231 if name is not None: 

232 return f"<{path}: {name}>" 

233 return f"<{path}>" 

234 

235 def check(self, **kwargs): 

236 return [ 

237 *self._check_field_name(), 

238 *self._check_choices(), 

239 *self._check_db_index(), 

240 *self._check_db_comment(**kwargs), 

241 *self._check_null_allowed_for_primary_keys(), 

242 *self._check_backend_specific_checks(**kwargs), 

243 *self._check_validators(), 

244 *self._check_deprecation_details(), 

245 ] 

246 

247 def _check_field_name(self): 

248 """ 

249 Check if field name is valid, i.e. 1) does not end with an 

250 underscore, 2) does not contain "__" and 3) is not "pk". 

251 """ 

252 if self.name.endswith("_"): 

253 return [ 

254 preflight.Error( 

255 "Field names must not end with an underscore.", 

256 obj=self, 

257 id="fields.E001", 

258 ) 

259 ] 

260 elif LOOKUP_SEP in self.name: 

261 return [ 

262 preflight.Error( 

263 f'Field names must not contain "{LOOKUP_SEP}".', 

264 obj=self, 

265 id="fields.E002", 

266 ) 

267 ] 

268 elif self.name == "pk": 

269 return [ 

270 preflight.Error( 

271 "'pk' is a reserved word that cannot be used as a field name.", 

272 obj=self, 

273 id="fields.E003", 

274 ) 

275 ] 

276 else: 

277 return [] 

278 

279 @classmethod 

280 def _choices_is_value(cls, value): 

281 return isinstance(value, str | Promise) or not is_iterable(value) 

282 

283 def _check_choices(self): 

284 if not self.choices: 

285 return [] 

286 

287 if not is_iterable(self.choices) or isinstance(self.choices, str): 

288 return [ 

289 preflight.Error( 

290 "'choices' must be an iterable (e.g., a list or tuple).", 

291 obj=self, 

292 id="fields.E004", 

293 ) 

294 ] 

295 

296 choice_max_length = 0 

297 # Expect [group_name, [value, display]] 

298 for choices_group in self.choices: 

299 try: 

300 group_name, group_choices = choices_group 

301 except (TypeError, ValueError): 

302 # Containing non-pairs 

303 break 

304 try: 

305 if not all( 

306 self._choices_is_value(value) and self._choices_is_value(human_name) 

307 for value, human_name in group_choices 

308 ): 

309 break 

310 if self.max_length is not None and group_choices: 

311 choice_max_length = max( 

312 [ 

313 choice_max_length, 

314 *( 

315 len(value) 

316 for value, _ in group_choices 

317 if isinstance(value, str) 

318 ), 

319 ] 

320 ) 

321 except (TypeError, ValueError): 

322 # No groups, choices in the form [value, display] 

323 value, human_name = group_name, group_choices 

324 if not self._choices_is_value(value) or not self._choices_is_value( 

325 human_name 

326 ): 

327 break 

328 if self.max_length is not None and isinstance(value, str): 

329 choice_max_length = max(choice_max_length, len(value)) 

330 

331 # Special case: choices=['ab'] 

332 if isinstance(choices_group, str): 

333 break 

334 else: 

335 if self.max_length is not None and choice_max_length > self.max_length: 

336 return [ 

337 preflight.Error( 

338 "'max_length' is too small to fit the longest value " 

339 "in 'choices' (%d characters)." % choice_max_length, 

340 obj=self, 

341 id="fields.E009", 

342 ), 

343 ] 

344 return [] 

345 

346 return [ 

347 preflight.Error( 

348 "'choices' must be an iterable containing " 

349 "(actual value, human readable name) tuples.", 

350 obj=self, 

351 id="fields.E005", 

352 ) 

353 ] 

354 

355 def _check_db_index(self): 

356 if self.db_index not in (None, True, False): 

357 return [ 

358 preflight.Error( 

359 "'db_index' must be None, True or False.", 

360 obj=self, 

361 id="fields.E006", 

362 ) 

363 ] 

364 else: 

365 return [] 

366 

367 def _check_db_comment(self, databases=None, **kwargs): 

368 if not self.db_comment or not databases: 

369 return [] 

370 errors = [] 

371 for db in databases: 

372 if not router.allow_migrate_model(db, self.model): 

373 continue 

374 connection = connections[db] 

375 if not ( 

376 connection.features.supports_comments 

377 or "supports_comments" in self.model._meta.required_db_features 

378 ): 

379 errors.append( 

380 preflight.Warning( 

381 f"{connection.display_name} does not support comments on " 

382 f"columns (db_comment).", 

383 obj=self, 

384 id="fields.W163", 

385 ) 

386 ) 

387 return errors 

388 

389 def _check_null_allowed_for_primary_keys(self): 

390 if ( 

391 self.primary_key 

392 and self.null 

393 and not connection.features.interprets_empty_strings_as_nulls 

394 ): 

395 # We cannot reliably check this for backends like Oracle which 

396 # consider NULL and '' to be equal (and thus set up 

397 # character-based fields a little differently). 

398 return [ 

399 preflight.Error( 

400 "Primary keys must not have null=True.", 

401 hint=( 

402 "Set null=False on the field, or " 

403 "remove primary_key=True argument." 

404 ), 

405 obj=self, 

406 id="fields.E007", 

407 ) 

408 ] 

409 else: 

410 return [] 

411 

412 def _check_backend_specific_checks(self, databases=None, **kwargs): 

413 if databases is None: 

414 return [] 

415 errors = [] 

416 for alias in databases: 

417 if router.allow_migrate_model(alias, self.model): 

418 errors.extend(connections[alias].validation.check_field(self, **kwargs)) 

419 return errors 

420 

421 def _check_validators(self): 

422 errors = [] 

423 for i, validator in enumerate(self.validators): 

424 if not callable(validator): 

425 errors.append( 

426 preflight.Error( 

427 "All 'validators' must be callable.", 

428 hint=( 

429 f"validators[{i}] ({repr(validator)}) isn't a function or " 

430 "instance of a validator class." 

431 ), 

432 obj=self, 

433 id="fields.E008", 

434 ) 

435 ) 

436 return errors 

437 

438 def _check_deprecation_details(self): 

439 if self.system_check_removed_details is not None: 

440 return [ 

441 preflight.Error( 

442 self.system_check_removed_details.get( 

443 "msg", 

444 f"{self.__class__.__name__} has been removed except for support in historical " 

445 "migrations.", 

446 ), 

447 hint=self.system_check_removed_details.get("hint"), 

448 obj=self, 

449 id=self.system_check_removed_details.get("id", "fields.EXXX"), 

450 ) 

451 ] 

452 elif self.system_check_deprecated_details is not None: 

453 return [ 

454 preflight.Warning( 

455 self.system_check_deprecated_details.get( 

456 "msg", f"{self.__class__.__name__} has been deprecated." 

457 ), 

458 hint=self.system_check_deprecated_details.get("hint"), 

459 obj=self, 

460 id=self.system_check_deprecated_details.get("id", "fields.WXXX"), 

461 ) 

462 ] 

463 return [] 

464 

465 def get_col(self, alias, output_field=None): 

466 if alias == self.model._meta.db_table and ( 

467 output_field is None or output_field == self 

468 ): 

469 return self.cached_col 

470 from plain.models.expressions import Col 

471 

472 return Col(alias, self, output_field) 

473 

474 @cached_property 

475 def cached_col(self): 

476 from plain.models.expressions import Col 

477 

478 return Col(self.model._meta.db_table, self) 

479 

480 def select_format(self, compiler, sql, params): 

481 """ 

482 Custom format for select clauses. For example, GIS columns need to be 

483 selected as AsText(table.col) on MySQL as the table.col data can't be 

484 used by Plain. 

485 """ 

486 return sql, params 

487 

488 def deconstruct(self): 

489 """ 

490 Return enough information to recreate the field as a 4-tuple: 

491 

492 * The name of the field on the model, if contribute_to_class() has 

493 been run. 

494 * The import path of the field, including the class, e.g. 

495 plain.models.IntegerField. This should be the most portable 

496 version, so less specific may be better. 

497 * A list of positional arguments. 

498 * A dict of keyword arguments. 

499 

500 Note that the positional or keyword arguments must contain values of 

501 the following types (including inner values of collection types): 

502 

503 * None, bool, str, int, float, complex, set, frozenset, list, tuple, 

504 dict 

505 * UUID 

506 * datetime.datetime (naive), datetime.date 

507 * top-level classes, top-level functions - will be referenced by their 

508 full import path 

509 * Storage instances - these have their own deconstruct() method 

510 

511 This is because the values here must be serialized into a text format 

512 (possibly new Python code, possibly JSON) and these are the only types 

513 with encoding handlers defined. 

514 

515 There's no need to return the exact way the field was instantiated this 

516 time, just ensure that the resulting field is the same - prefer keyword 

517 arguments over positional ones, and omit parameters with their default 

518 values. 

519 """ 

520 # Short-form way of fetching all the default parameters 

521 keywords = {} 

522 possibles = { 

523 "primary_key": False, 

524 "max_length": None, 

525 "unique": False, 

526 "blank": False, 

527 "null": False, 

528 "db_index": False, 

529 "default": NOT_PROVIDED, 

530 "editable": True, 

531 "choices": None, 

532 "db_column": None, 

533 "db_comment": None, 

534 "db_tablespace": None, 

535 "auto_created": False, 

536 "validators": [], 

537 "error_messages": None, 

538 } 

539 attr_overrides = { 

540 "unique": "_unique", 

541 "error_messages": "_error_messages", 

542 "validators": "_validators", 

543 "db_tablespace": "_db_tablespace", 

544 } 

545 equals_comparison = {"choices", "validators"} 

546 for name, default in possibles.items(): 

547 value = getattr(self, attr_overrides.get(name, name)) 

548 # Unroll anything iterable for choices into a concrete list 

549 if name == "choices" and isinstance(value, collections.abc.Iterable): 

550 value = list(value) 

551 # Do correct kind of comparison 

552 if name in equals_comparison: 

553 if value != default: 

554 keywords[name] = value 

555 else: 

556 if value is not default: 

557 keywords[name] = value 

558 # Work out path - we shorten it for known Plain core fields 

559 path = f"{self.__class__.__module__}.{self.__class__.__qualname__}" 

560 if path.startswith("plain.models.fields.related"): 

561 path = path.replace("plain.models.fields.related", "plain.models") 

562 elif path.startswith("plain.models.fields.json"): 

563 path = path.replace("plain.models.fields.json", "plain.models") 

564 elif path.startswith("plain.models.fields.proxy"): 

565 path = path.replace("plain.models.fields.proxy", "plain.models") 

566 elif path.startswith("plain.models.fields"): 

567 path = path.replace("plain.models.fields", "plain.models") 

568 # Return basic info - other fields should override this. 

569 return (self.name, path, [], keywords) 

570 

571 def clone(self): 

572 """ 

573 Uses deconstruct() to clone a new copy of this Field. 

574 Will not preserve any class attachments/attribute names. 

575 """ 

576 name, path, args, kwargs = self.deconstruct() 

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

578 

579 def __eq__(self, other): 

580 # Needed for @total_ordering 

581 if isinstance(other, Field): 

582 return self.creation_counter == other.creation_counter and getattr( 

583 self, "model", None 

584 ) == getattr(other, "model", None) 

585 return NotImplemented 

586 

587 def __lt__(self, other): 

588 # This is needed because bisect does not take a comparison function. 

589 # Order by creation_counter first for backward compatibility. 

590 if isinstance(other, Field): 

591 if ( 

592 self.creation_counter != other.creation_counter 

593 or not hasattr(self, "model") 

594 and not hasattr(other, "model") 

595 ): 

596 return self.creation_counter < other.creation_counter 

597 elif hasattr(self, "model") != hasattr(other, "model"): 

598 return not hasattr(self, "model") # Order no-model fields first 

599 else: 

600 # creation_counter's are equal, compare only models. 

601 return (self.model._meta.package_label, self.model._meta.model_name) < ( 

602 other.model._meta.package_label, 

603 other.model._meta.model_name, 

604 ) 

605 return NotImplemented 

606 

607 def __hash__(self): 

608 return hash(self.creation_counter) 

609 

610 def __deepcopy__(self, memodict): 

611 # We don't have to deepcopy very much here, since most things are not 

612 # intended to be altered after initial creation. 

613 obj = copy.copy(self) 

614 if self.remote_field: 

615 obj.remote_field = copy.copy(self.remote_field) 

616 if hasattr(self.remote_field, "field") and self.remote_field.field is self: 

617 obj.remote_field.field = obj 

618 memodict[id(self)] = obj 

619 return obj 

620 

621 def __copy__(self): 

622 # We need to avoid hitting __reduce__, so define this 

623 # slightly weird copy construct. 

624 obj = Empty() 

625 obj.__class__ = self.__class__ 

626 obj.__dict__ = self.__dict__.copy() 

627 return obj 

628 

629 def __reduce__(self): 

630 """ 

631 Pickling should return the model._meta.fields instance of the field, 

632 not a new copy of that field. So, use the app registry to load the 

633 model and then the field back. 

634 """ 

635 if not hasattr(self, "model"): 

636 # Fields are sometimes used without attaching them to models (for 

637 # example in aggregation). In this case give back a plain field 

638 # instance. The code below will create a new empty instance of 

639 # class self.__class__, then update its dict with self.__dict__ 

640 # values - so, this is very close to normal pickle. 

641 state = self.__dict__.copy() 

642 # The _get_default cached_property can't be pickled due to lambda 

643 # usage. 

644 state.pop("_get_default", None) 

645 return _empty, (self.__class__,), state 

646 return _load_field, ( 

647 self.model._meta.package_label, 

648 self.model._meta.object_name, 

649 self.name, 

650 ) 

651 

652 def get_pk_value_on_save(self, instance): 

653 """ 

654 Hook to generate new PK values on save. This method is called when 

655 saving instances with no primary key value set. If this method returns 

656 something else than None, then the returned value is used when saving 

657 the new instance. 

658 """ 

659 if self.default: 

660 return self.get_default() 

661 return None 

662 

663 def to_python(self, value): 

664 """ 

665 Convert the input value into the expected Python data type, raising 

666 plain.exceptions.ValidationError if the data can't be converted. 

667 Return the converted value. Subclasses should override this. 

668 """ 

669 return value 

670 

671 @cached_property 

672 def error_messages(self): 

673 messages = {} 

674 for c in reversed(self.__class__.__mro__): 

675 messages.update(getattr(c, "default_error_messages", {})) 

676 messages.update(self._error_messages or {}) 

677 return messages 

678 

679 @cached_property 

680 def validators(self): 

681 """ 

682 Some validators can't be created at field initialization time. 

683 This method provides a way to delay their creation until required. 

684 """ 

685 return [*self.default_validators, *self._validators] 

686 

687 def run_validators(self, value): 

688 if value in self.empty_values: 

689 return 

690 

691 errors = [] 

692 for v in self.validators: 

693 try: 

694 v(value) 

695 except exceptions.ValidationError as e: 

696 if hasattr(e, "code") and e.code in self.error_messages: 

697 e.message = self.error_messages[e.code] 

698 errors.extend(e.error_list) 

699 

700 if errors: 

701 raise exceptions.ValidationError(errors) 

702 

703 def validate(self, value, model_instance): 

704 """ 

705 Validate value and raise ValidationError if necessary. Subclasses 

706 should override this to provide validation logic. 

707 """ 

708 if not self.editable: 

709 # Skip validation for non-editable fields. 

710 return 

711 

712 if self.choices is not None and value not in self.empty_values: 

713 for option_key, option_value in self.choices: 

714 if isinstance(option_value, list | tuple): 

715 # This is an optgroup, so look inside the group for 

716 # options. 

717 for optgroup_key, optgroup_value in option_value: 

718 if value == optgroup_key: 

719 return 

720 elif value == option_key: 

721 return 

722 raise exceptions.ValidationError( 

723 self.error_messages["invalid_choice"], 

724 code="invalid_choice", 

725 params={"value": value}, 

726 ) 

727 

728 if value is None and not self.null: 

729 raise exceptions.ValidationError(self.error_messages["null"], code="null") 

730 

731 if not self.blank and value in self.empty_values: 

732 raise exceptions.ValidationError(self.error_messages["blank"], code="blank") 

733 

734 def clean(self, value, model_instance): 

735 """ 

736 Convert the value's type and run validation. Validation errors 

737 from to_python() and validate() are propagated. Return the correct 

738 value if no error is raised. 

739 """ 

740 value = self.to_python(value) 

741 self.validate(value, model_instance) 

742 self.run_validators(value) 

743 return value 

744 

745 def db_type_parameters(self, connection): 

746 return DictWrapper(self.__dict__, connection.ops.quote_name, "qn_") 

747 

748 def db_check(self, connection): 

749 """ 

750 Return the database column check constraint for this field, for the 

751 provided connection. Works the same way as db_type() for the case that 

752 get_internal_type() does not map to a preexisting model field. 

753 """ 

754 data = self.db_type_parameters(connection) 

755 try: 

756 return ( 

757 connection.data_type_check_constraints[self.get_internal_type()] % data 

758 ) 

759 except KeyError: 

760 return None 

761 

762 def db_type(self, connection): 

763 """ 

764 Return the database column data type for this field, for the provided 

765 connection. 

766 """ 

767 # The default implementation of this method looks at the 

768 # backend-specific data_types dictionary, looking up the field by its 

769 # "internal type". 

770 # 

771 # A Field class can implement the get_internal_type() method to specify 

772 # which *preexisting* Plain Field class it's most similar to -- i.e., 

773 # a custom field might be represented by a TEXT column type, which is 

774 # the same as the TextField Plain field type, which means the custom 

775 # field's get_internal_type() returns 'TextField'. 

776 # 

777 # But the limitation of the get_internal_type() / data_types approach 

778 # is that it cannot handle database column types that aren't already 

779 # mapped to one of the built-in Plain field types. In this case, you 

780 # can implement db_type() instead of get_internal_type() to specify 

781 # exactly which wacky database column type you want to use. 

782 data = self.db_type_parameters(connection) 

783 try: 

784 column_type = connection.data_types[self.get_internal_type()] 

785 except KeyError: 

786 return None 

787 else: 

788 # column_type is either a single-parameter function or a string. 

789 if callable(column_type): 

790 return column_type(data) 

791 return column_type % data 

792 

793 def rel_db_type(self, connection): 

794 """ 

795 Return the data type that a related field pointing to this field should 

796 use. For example, this method is called by ForeignKey and OneToOneField 

797 to determine its data type. 

798 """ 

799 return self.db_type(connection) 

800 

801 def cast_db_type(self, connection): 

802 """Return the data type to use in the Cast() function.""" 

803 db_type = connection.ops.cast_data_types.get(self.get_internal_type()) 

804 if db_type: 

805 return db_type % self.db_type_parameters(connection) 

806 return self.db_type(connection) 

807 

808 def db_parameters(self, connection): 

809 """ 

810 Extension of db_type(), providing a range of different return values 

811 (type, checks). This will look at db_type(), allowing custom model 

812 fields to override it. 

813 """ 

814 type_string = self.db_type(connection) 

815 check_string = self.db_check(connection) 

816 return { 

817 "type": type_string, 

818 "check": check_string, 

819 } 

820 

821 def db_type_suffix(self, connection): 

822 return connection.data_types_suffix.get(self.get_internal_type()) 

823 

824 def get_db_converters(self, connection): 

825 if hasattr(self, "from_db_value"): 

826 return [self.from_db_value] 

827 return [] 

828 

829 @property 

830 def unique(self): 

831 return self._unique or self.primary_key 

832 

833 @property 

834 def db_tablespace(self): 

835 return self._db_tablespace or settings.DEFAULT_INDEX_TABLESPACE 

836 

837 @property 

838 def db_returning(self): 

839 """ 

840 Private API intended only to be used by Plain itself. Currently only 

841 the PostgreSQL backend supports returning multiple fields on a model. 

842 """ 

843 return False 

844 

845 def set_attributes_from_name(self, name): 

846 self.name = self.name or name 

847 self.attname, self.column = self.get_attname_column() 

848 self.concrete = self.column is not None 

849 

850 def contribute_to_class(self, cls, name, private_only=False): 

851 """ 

852 Register the field with the model class it belongs to. 

853 

854 If private_only is True, create a separate instance of this field 

855 for every subclass of cls, even if cls is not an abstract model. 

856 """ 

857 self.set_attributes_from_name(name) 

858 self.model = cls 

859 cls._meta.add_field(self, private=private_only) 

860 if self.column: 

861 setattr(cls, self.attname, self.descriptor_class(self)) 

862 if self.choices is not None: 

863 # Don't override a get_FOO_display() method defined explicitly on 

864 # this class, but don't check methods derived from inheritance, to 

865 # allow overriding inherited choices. For more complex inheritance 

866 # structures users should override contribute_to_class(). 

867 if f"get_{self.name}_display" not in cls.__dict__: 

868 setattr( 

869 cls, 

870 f"get_{self.name}_display", 

871 partialmethod(cls._get_FIELD_display, field=self), 

872 ) 

873 

874 def get_filter_kwargs_for_object(self, obj): 

875 """ 

876 Return a dict that when passed as kwargs to self.model.filter(), would 

877 yield all instances having the same value for this field as obj has. 

878 """ 

879 return {self.name: getattr(obj, self.attname)} 

880 

881 def get_attname(self): 

882 return self.name 

883 

884 def get_attname_column(self): 

885 attname = self.get_attname() 

886 column = self.db_column or attname 

887 return attname, column 

888 

889 def get_internal_type(self): 

890 return self.__class__.__name__ 

891 

892 def pre_save(self, model_instance, add): 

893 """Return field's value just before saving.""" 

894 return getattr(model_instance, self.attname) 

895 

896 def get_prep_value(self, value): 

897 """Perform preliminary non-db specific value checks and conversions.""" 

898 if isinstance(value, Promise): 

899 value = value._proxy____cast() 

900 return value 

901 

902 def get_db_prep_value(self, value, connection, prepared=False): 

903 """ 

904 Return field's value prepared for interacting with the database backend. 

905 

906 Used by the default implementations of get_db_prep_save(). 

907 """ 

908 if not prepared: 

909 value = self.get_prep_value(value) 

910 return value 

911 

912 def get_db_prep_save(self, value, connection): 

913 """Return field's value prepared for saving into a database.""" 

914 if hasattr(value, "as_sql"): 

915 return value 

916 return self.get_db_prep_value(value, connection=connection, prepared=False) 

917 

918 def has_default(self): 

919 """Return a boolean of whether this field has a default value.""" 

920 return self.default is not NOT_PROVIDED 

921 

922 def get_default(self): 

923 """Return the default value for this field.""" 

924 return self._get_default() 

925 

926 @cached_property 

927 def _get_default(self): 

928 if self.has_default(): 

929 if callable(self.default): 

930 return self.default 

931 return lambda: self.default 

932 

933 if ( 

934 not self.empty_strings_allowed 

935 or self.null 

936 and not connection.features.interprets_empty_strings_as_nulls 

937 ): 

938 return return_None 

939 return str # return empty string 

940 

941 def get_choices( 

942 self, 

943 include_blank=True, 

944 blank_choice=BLANK_CHOICE_DASH, 

945 limit_choices_to=None, 

946 ordering=(), 

947 ): 

948 """ 

949 Return choices with a default blank choices included, for use 

950 as <select> choices for this field. 

951 """ 

952 if self.choices is not None: 

953 choices = list(self.choices) 

954 if include_blank: 

955 blank_defined = any( 

956 choice in ("", None) for choice, _ in self.flatchoices 

957 ) 

958 if not blank_defined: 

959 choices = blank_choice + choices 

960 return choices 

961 rel_model = self.remote_field.model 

962 limit_choices_to = limit_choices_to or self.get_limit_choices_to() 

963 choice_func = operator.attrgetter( 

964 self.remote_field.get_related_field().attname 

965 if hasattr(self.remote_field, "get_related_field") 

966 else "pk" 

967 ) 

968 qs = rel_model._default_manager.complex_filter(limit_choices_to) 

969 if ordering: 

970 qs = qs.order_by(*ordering) 

971 return (blank_choice if include_blank else []) + [ 

972 (choice_func(x), str(x)) for x in qs 

973 ] 

974 

975 def value_to_string(self, obj): 

976 """ 

977 Return a string value of this field from the passed obj. 

978 This is used by the serialization framework. 

979 """ 

980 return str(self.value_from_object(obj)) 

981 

982 def _get_flatchoices(self): 

983 """Flattened version of choices tuple.""" 

984 if self.choices is None: 

985 return [] 

986 flat = [] 

987 for choice, value in self.choices: 

988 if isinstance(value, list | tuple): 

989 flat.extend(value) 

990 else: 

991 flat.append((choice, value)) 

992 return flat 

993 

994 flatchoices = property(_get_flatchoices) 

995 

996 def save_form_data(self, instance, data): 

997 setattr(instance, self.name, data) 

998 

999 def value_from_object(self, obj): 

1000 """Return the value of this field in the given model instance.""" 

1001 return getattr(obj, self.attname) 

1002 

1003 

1004class BooleanField(Field): 

1005 empty_strings_allowed = False 

1006 default_error_messages = { 

1007 "invalid": "“%(value)s” value must be either True or False.", 

1008 "invalid_nullable": "“%(value)s” value must be either True, False, or None.", 

1009 } 

1010 description = "Boolean (Either True or False)" 

1011 

1012 def get_internal_type(self): 

1013 return "BooleanField" 

1014 

1015 def to_python(self, value): 

1016 if self.null and value in self.empty_values: 

1017 return None 

1018 if value in (True, False): 

1019 # 1/0 are equal to True/False. bool() converts former to latter. 

1020 return bool(value) 

1021 if value in ("t", "True", "1"): 

1022 return True 

1023 if value in ("f", "False", "0"): 

1024 return False 

1025 raise exceptions.ValidationError( 

1026 self.error_messages["invalid_nullable" if self.null else "invalid"], 

1027 code="invalid", 

1028 params={"value": value}, 

1029 ) 

1030 

1031 def get_prep_value(self, value): 

1032 value = super().get_prep_value(value) 

1033 if value is None: 

1034 return None 

1035 return self.to_python(value) 

1036 

1037 

1038class CharField(Field): 

1039 def __init__(self, *args, db_collation=None, **kwargs): 

1040 super().__init__(*args, **kwargs) 

1041 self.db_collation = db_collation 

1042 if self.max_length is not None: 

1043 self.validators.append(validators.MaxLengthValidator(self.max_length)) 

1044 

1045 @property 

1046 def description(self): 

1047 if self.max_length is not None: 

1048 return "String (up to %(max_length)s)" 

1049 else: 

1050 return "String (unlimited)" 

1051 

1052 def check(self, **kwargs): 

1053 databases = kwargs.get("databases") or [] 

1054 return [ 

1055 *super().check(**kwargs), 

1056 *self._check_db_collation(databases), 

1057 *self._check_max_length_attribute(**kwargs), 

1058 ] 

1059 

1060 def _check_max_length_attribute(self, **kwargs): 

1061 if self.max_length is None: 

1062 if ( 

1063 connection.features.supports_unlimited_charfield 

1064 or "supports_unlimited_charfield" 

1065 in self.model._meta.required_db_features 

1066 ): 

1067 return [] 

1068 return [ 

1069 preflight.Error( 

1070 "CharFields must define a 'max_length' attribute.", 

1071 obj=self, 

1072 id="fields.E120", 

1073 ) 

1074 ] 

1075 elif ( 

1076 not isinstance(self.max_length, int) 

1077 or isinstance(self.max_length, bool) 

1078 or self.max_length <= 0 

1079 ): 

1080 return [ 

1081 preflight.Error( 

1082 "'max_length' must be a positive integer.", 

1083 obj=self, 

1084 id="fields.E121", 

1085 ) 

1086 ] 

1087 else: 

1088 return [] 

1089 

1090 def _check_db_collation(self, databases): 

1091 errors = [] 

1092 for db in databases: 

1093 if not router.allow_migrate_model(db, self.model): 

1094 continue 

1095 connection = connections[db] 

1096 if not ( 

1097 self.db_collation is None 

1098 or "supports_collation_on_charfield" 

1099 in self.model._meta.required_db_features 

1100 or connection.features.supports_collation_on_charfield 

1101 ): 

1102 errors.append( 

1103 preflight.Error( 

1104 f"{connection.display_name} does not support a database collation on " 

1105 "CharFields.", 

1106 obj=self, 

1107 id="fields.E190", 

1108 ), 

1109 ) 

1110 return errors 

1111 

1112 def cast_db_type(self, connection): 

1113 if self.max_length is None: 

1114 return connection.ops.cast_char_field_without_max_length 

1115 return super().cast_db_type(connection) 

1116 

1117 def db_parameters(self, connection): 

1118 db_params = super().db_parameters(connection) 

1119 db_params["collation"] = self.db_collation 

1120 return db_params 

1121 

1122 def get_internal_type(self): 

1123 return "CharField" 

1124 

1125 def to_python(self, value): 

1126 if isinstance(value, str) or value is None: 

1127 return value 

1128 return str(value) 

1129 

1130 def get_prep_value(self, value): 

1131 value = super().get_prep_value(value) 

1132 return self.to_python(value) 

1133 

1134 def deconstruct(self): 

1135 name, path, args, kwargs = super().deconstruct() 

1136 if self.db_collation: 

1137 kwargs["db_collation"] = self.db_collation 

1138 return name, path, args, kwargs 

1139 

1140 

1141class CommaSeparatedIntegerField(CharField): 

1142 default_validators = [validators.validate_comma_separated_integer_list] 

1143 description = "Comma-separated integers" 

1144 system_check_removed_details = { 

1145 "msg": ( 

1146 "CommaSeparatedIntegerField is removed except for support in " 

1147 "historical migrations." 

1148 ), 

1149 "hint": ( 

1150 "Use CharField(validators=[validate_comma_separated_integer_list]) " 

1151 "instead." 

1152 ), 

1153 "id": "fields.E901", 

1154 } 

1155 

1156 

1157def _to_naive(value): 

1158 if timezone.is_aware(value): 

1159 value = timezone.make_naive(value, datetime.UTC) 

1160 return value 

1161 

1162 

1163def _get_naive_now(): 

1164 return _to_naive(timezone.now()) 

1165 

1166 

1167class DateTimeCheckMixin: 

1168 def check(self, **kwargs): 

1169 return [ 

1170 *super().check(**kwargs), 

1171 *self._check_mutually_exclusive_options(), 

1172 *self._check_fix_default_value(), 

1173 ] 

1174 

1175 def _check_mutually_exclusive_options(self): 

1176 # auto_now, auto_now_add, and default are mutually exclusive 

1177 # options. The use of more than one of these options together 

1178 # will trigger an Error 

1179 mutually_exclusive_options = [ 

1180 self.auto_now_add, 

1181 self.auto_now, 

1182 self.has_default(), 

1183 ] 

1184 enabled_options = [ 

1185 option not in (None, False) for option in mutually_exclusive_options 

1186 ].count(True) 

1187 if enabled_options > 1: 

1188 return [ 

1189 preflight.Error( 

1190 "The options auto_now, auto_now_add, and default " 

1191 "are mutually exclusive. Only one of these options " 

1192 "may be present.", 

1193 obj=self, 

1194 id="fields.E160", 

1195 ) 

1196 ] 

1197 else: 

1198 return [] 

1199 

1200 def _check_fix_default_value(self): 

1201 return [] 

1202 

1203 # Concrete subclasses use this in their implementations of 

1204 # _check_fix_default_value(). 

1205 def _check_if_value_fixed(self, value, now=None): 

1206 """ 

1207 Check if the given value appears to have been provided as a "fixed" 

1208 time value, and include a warning in the returned list if it does. The 

1209 value argument must be a date object or aware/naive datetime object. If 

1210 now is provided, it must be a naive datetime object. 

1211 """ 

1212 if now is None: 

1213 now = _get_naive_now() 

1214 offset = datetime.timedelta(seconds=10) 

1215 lower = now - offset 

1216 upper = now + offset 

1217 if isinstance(value, datetime.datetime): 

1218 value = _to_naive(value) 

1219 else: 

1220 assert isinstance(value, datetime.date) 

1221 lower = lower.date() 

1222 upper = upper.date() 

1223 if lower <= value <= upper: 

1224 return [ 

1225 preflight.Warning( 

1226 "Fixed default value provided.", 

1227 hint=( 

1228 "It seems you set a fixed date / time / datetime " 

1229 "value as default for this field. This may not be " 

1230 "what you want. If you want to have the current date " 

1231 "as default, use `plain.utils.timezone.now`" 

1232 ), 

1233 obj=self, 

1234 id="fields.W161", 

1235 ) 

1236 ] 

1237 return [] 

1238 

1239 

1240class DateField(DateTimeCheckMixin, Field): 

1241 empty_strings_allowed = False 

1242 default_error_messages = { 

1243 "invalid": "“%(value)s” value has an invalid date format. It must be in YYYY-MM-DD format.", 

1244 "invalid_date": "“%(value)s” value has the correct format (YYYY-MM-DD) but it is an invalid date.", 

1245 } 

1246 description = "Date (without time)" 

1247 

1248 def __init__(self, name=None, auto_now=False, auto_now_add=False, **kwargs): 

1249 self.auto_now, self.auto_now_add = auto_now, auto_now_add 

1250 if auto_now or auto_now_add: 

1251 kwargs["editable"] = False 

1252 kwargs["blank"] = True 

1253 super().__init__(name, **kwargs) 

1254 

1255 def _check_fix_default_value(self): 

1256 """ 

1257 Warn that using an actual date or datetime value is probably wrong; 

1258 it's only evaluated on server startup. 

1259 """ 

1260 if not self.has_default(): 

1261 return [] 

1262 

1263 value = self.default 

1264 if isinstance(value, datetime.datetime): 

1265 value = _to_naive(value).date() 

1266 elif isinstance(value, datetime.date): 

1267 pass 

1268 else: 

1269 # No explicit date / datetime value -- no checks necessary 

1270 return [] 

1271 # At this point, value is a date object. 

1272 return self._check_if_value_fixed(value) 

1273 

1274 def deconstruct(self): 

1275 name, path, args, kwargs = super().deconstruct() 

1276 if self.auto_now: 

1277 kwargs["auto_now"] = True 

1278 if self.auto_now_add: 

1279 kwargs["auto_now_add"] = True 

1280 if self.auto_now or self.auto_now_add: 

1281 del kwargs["editable"] 

1282 del kwargs["blank"] 

1283 return name, path, args, kwargs 

1284 

1285 def get_internal_type(self): 

1286 return "DateField" 

1287 

1288 def to_python(self, value): 

1289 if value is None: 

1290 return value 

1291 if isinstance(value, datetime.datetime): 

1292 if timezone.is_aware(value): 

1293 # Convert aware datetimes to the default time zone 

1294 # before casting them to dates (#17742). 

1295 default_timezone = timezone.get_default_timezone() 

1296 value = timezone.make_naive(value, default_timezone) 

1297 return value.date() 

1298 if isinstance(value, datetime.date): 

1299 return value 

1300 

1301 try: 

1302 parsed = parse_date(value) 

1303 if parsed is not None: 

1304 return parsed 

1305 except ValueError: 

1306 raise exceptions.ValidationError( 

1307 self.error_messages["invalid_date"], 

1308 code="invalid_date", 

1309 params={"value": value}, 

1310 ) 

1311 

1312 raise exceptions.ValidationError( 

1313 self.error_messages["invalid"], 

1314 code="invalid", 

1315 params={"value": value}, 

1316 ) 

1317 

1318 def pre_save(self, model_instance, add): 

1319 if self.auto_now or (self.auto_now_add and add): 

1320 value = datetime.date.today() 

1321 setattr(model_instance, self.attname, value) 

1322 return value 

1323 else: 

1324 return super().pre_save(model_instance, add) 

1325 

1326 def contribute_to_class(self, cls, name, **kwargs): 

1327 super().contribute_to_class(cls, name, **kwargs) 

1328 if not self.null: 

1329 setattr( 

1330 cls, 

1331 f"get_next_by_{self.name}", 

1332 partialmethod( 

1333 cls._get_next_or_previous_by_FIELD, field=self, is_next=True 

1334 ), 

1335 ) 

1336 setattr( 

1337 cls, 

1338 f"get_previous_by_{self.name}", 

1339 partialmethod( 

1340 cls._get_next_or_previous_by_FIELD, field=self, is_next=False 

1341 ), 

1342 ) 

1343 

1344 def get_prep_value(self, value): 

1345 value = super().get_prep_value(value) 

1346 return self.to_python(value) 

1347 

1348 def get_db_prep_value(self, value, connection, prepared=False): 

1349 # Casts dates into the format expected by the backend 

1350 if not prepared: 

1351 value = self.get_prep_value(value) 

1352 return connection.ops.adapt_datefield_value(value) 

1353 

1354 def value_to_string(self, obj): 

1355 val = self.value_from_object(obj) 

1356 return "" if val is None else val.isoformat() 

1357 

1358 

1359class DateTimeField(DateField): 

1360 empty_strings_allowed = False 

1361 default_error_messages = { 

1362 "invalid": "“%(value)s” value has an invalid format. It must be in YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ] format.", 

1363 "invalid_date": "“%(value)s” value has the correct format (YYYY-MM-DD) but it is an invalid date.", 

1364 "invalid_datetime": "“%(value)s” value has the correct format (YYYY-MM-DD HH:MM[:ss[.uuuuuu]][TZ]) but it is an invalid date/time.", 

1365 } 

1366 description = "Date (with time)" 

1367 

1368 # __init__ is inherited from DateField 

1369 

1370 def _check_fix_default_value(self): 

1371 """ 

1372 Warn that using an actual date or datetime value is probably wrong; 

1373 it's only evaluated on server startup. 

1374 """ 

1375 if not self.has_default(): 

1376 return [] 

1377 

1378 value = self.default 

1379 if isinstance(value, datetime.datetime | datetime.date): 

1380 return self._check_if_value_fixed(value) 

1381 # No explicit date / datetime value -- no checks necessary. 

1382 return [] 

1383 

1384 def get_internal_type(self): 

1385 return "DateTimeField" 

1386 

1387 def to_python(self, value): 

1388 if value is None: 

1389 return value 

1390 if isinstance(value, datetime.datetime): 

1391 return value 

1392 if isinstance(value, datetime.date): 

1393 value = datetime.datetime(value.year, value.month, value.day) 

1394 

1395 # For backwards compatibility, interpret naive datetimes in 

1396 # local time. This won't work during DST change, but we can't 

1397 # do much about it, so we let the exceptions percolate up the 

1398 # call stack. 

1399 warnings.warn( 

1400 f"DateTimeField {self.model.__name__}.{self.name} received a naive datetime " 

1401 f"({value}) while time zone support is active.", 

1402 RuntimeWarning, 

1403 ) 

1404 default_timezone = timezone.get_default_timezone() 

1405 value = timezone.make_aware(value, default_timezone) 

1406 

1407 return value 

1408 

1409 try: 

1410 parsed = parse_datetime(value) 

1411 if parsed is not None: 

1412 return parsed 

1413 except ValueError: 

1414 raise exceptions.ValidationError( 

1415 self.error_messages["invalid_datetime"], 

1416 code="invalid_datetime", 

1417 params={"value": value}, 

1418 ) 

1419 

1420 try: 

1421 parsed = parse_date(value) 

1422 if parsed is not None: 

1423 return datetime.datetime(parsed.year, parsed.month, parsed.day) 

1424 except ValueError: 

1425 raise exceptions.ValidationError( 

1426 self.error_messages["invalid_date"], 

1427 code="invalid_date", 

1428 params={"value": value}, 

1429 ) 

1430 

1431 raise exceptions.ValidationError( 

1432 self.error_messages["invalid"], 

1433 code="invalid", 

1434 params={"value": value}, 

1435 ) 

1436 

1437 def pre_save(self, model_instance, add): 

1438 if self.auto_now or (self.auto_now_add and add): 

1439 value = timezone.now() 

1440 setattr(model_instance, self.attname, value) 

1441 return value 

1442 else: 

1443 return super().pre_save(model_instance, add) 

1444 

1445 # contribute_to_class is inherited from DateField, it registers 

1446 # get_next_by_FOO and get_prev_by_FOO 

1447 

1448 def get_prep_value(self, value): 

1449 value = super().get_prep_value(value) 

1450 value = self.to_python(value) 

1451 if value is not None and timezone.is_naive(value): 

1452 # For backwards compatibility, interpret naive datetimes in local 

1453 # time. This won't work during DST change, but we can't do much 

1454 # about it, so we let the exceptions percolate up the call stack. 

1455 try: 

1456 name = f"{self.model.__name__}.{self.name}" 

1457 except AttributeError: 

1458 name = "(unbound)" 

1459 warnings.warn( 

1460 f"DateTimeField {name} received a naive datetime ({value})" 

1461 " while time zone support is active.", 

1462 RuntimeWarning, 

1463 ) 

1464 default_timezone = timezone.get_default_timezone() 

1465 value = timezone.make_aware(value, default_timezone) 

1466 return value 

1467 

1468 def get_db_prep_value(self, value, connection, prepared=False): 

1469 # Casts datetimes into the format expected by the backend 

1470 if not prepared: 

1471 value = self.get_prep_value(value) 

1472 return connection.ops.adapt_datetimefield_value(value) 

1473 

1474 def value_to_string(self, obj): 

1475 val = self.value_from_object(obj) 

1476 return "" if val is None else val.isoformat() 

1477 

1478 

1479class DecimalField(Field): 

1480 empty_strings_allowed = False 

1481 default_error_messages = { 

1482 "invalid": "“%(value)s” value must be a decimal number.", 

1483 } 

1484 description = "Decimal number" 

1485 

1486 def __init__( 

1487 self, 

1488 name=None, 

1489 max_digits=None, 

1490 decimal_places=None, 

1491 **kwargs, 

1492 ): 

1493 self.max_digits, self.decimal_places = max_digits, decimal_places 

1494 super().__init__(name, **kwargs) 

1495 

1496 def check(self, **kwargs): 

1497 errors = super().check(**kwargs) 

1498 

1499 digits_errors = [ 

1500 *self._check_decimal_places(), 

1501 *self._check_max_digits(), 

1502 ] 

1503 if not digits_errors: 

1504 errors.extend(self._check_decimal_places_and_max_digits(**kwargs)) 

1505 else: 

1506 errors.extend(digits_errors) 

1507 return errors 

1508 

1509 def _check_decimal_places(self): 

1510 try: 

1511 decimal_places = int(self.decimal_places) 

1512 if decimal_places < 0: 

1513 raise ValueError() 

1514 except TypeError: 

1515 return [ 

1516 preflight.Error( 

1517 "DecimalFields must define a 'decimal_places' attribute.", 

1518 obj=self, 

1519 id="fields.E130", 

1520 ) 

1521 ] 

1522 except ValueError: 

1523 return [ 

1524 preflight.Error( 

1525 "'decimal_places' must be a non-negative integer.", 

1526 obj=self, 

1527 id="fields.E131", 

1528 ) 

1529 ] 

1530 else: 

1531 return [] 

1532 

1533 def _check_max_digits(self): 

1534 try: 

1535 max_digits = int(self.max_digits) 

1536 if max_digits <= 0: 

1537 raise ValueError() 

1538 except TypeError: 

1539 return [ 

1540 preflight.Error( 

1541 "DecimalFields must define a 'max_digits' attribute.", 

1542 obj=self, 

1543 id="fields.E132", 

1544 ) 

1545 ] 

1546 except ValueError: 

1547 return [ 

1548 preflight.Error( 

1549 "'max_digits' must be a positive integer.", 

1550 obj=self, 

1551 id="fields.E133", 

1552 ) 

1553 ] 

1554 else: 

1555 return [] 

1556 

1557 def _check_decimal_places_and_max_digits(self, **kwargs): 

1558 if int(self.decimal_places) > int(self.max_digits): 

1559 return [ 

1560 preflight.Error( 

1561 "'max_digits' must be greater or equal to 'decimal_places'.", 

1562 obj=self, 

1563 id="fields.E134", 

1564 ) 

1565 ] 

1566 return [] 

1567 

1568 @cached_property 

1569 def validators(self): 

1570 return super().validators + [ 

1571 validators.DecimalValidator(self.max_digits, self.decimal_places) 

1572 ] 

1573 

1574 @cached_property 

1575 def context(self): 

1576 return decimal.Context(prec=self.max_digits) 

1577 

1578 def deconstruct(self): 

1579 name, path, args, kwargs = super().deconstruct() 

1580 if self.max_digits is not None: 

1581 kwargs["max_digits"] = self.max_digits 

1582 if self.decimal_places is not None: 

1583 kwargs["decimal_places"] = self.decimal_places 

1584 return name, path, args, kwargs 

1585 

1586 def get_internal_type(self): 

1587 return "DecimalField" 

1588 

1589 def to_python(self, value): 

1590 if value is None: 

1591 return value 

1592 try: 

1593 if isinstance(value, float): 

1594 decimal_value = self.context.create_decimal_from_float(value) 

1595 else: 

1596 decimal_value = decimal.Decimal(value) 

1597 except (decimal.InvalidOperation, TypeError, ValueError): 

1598 raise exceptions.ValidationError( 

1599 self.error_messages["invalid"], 

1600 code="invalid", 

1601 params={"value": value}, 

1602 ) 

1603 if not decimal_value.is_finite(): 

1604 raise exceptions.ValidationError( 

1605 self.error_messages["invalid"], 

1606 code="invalid", 

1607 params={"value": value}, 

1608 ) 

1609 return decimal_value 

1610 

1611 def get_db_prep_value(self, value, connection, prepared=False): 

1612 if not prepared: 

1613 value = self.get_prep_value(value) 

1614 if hasattr(value, "as_sql"): 

1615 return value 

1616 return connection.ops.adapt_decimalfield_value( 

1617 value, self.max_digits, self.decimal_places 

1618 ) 

1619 

1620 def get_prep_value(self, value): 

1621 value = super().get_prep_value(value) 

1622 return self.to_python(value) 

1623 

1624 

1625class DurationField(Field): 

1626 """ 

1627 Store timedelta objects. 

1628 

1629 Use interval on PostgreSQL, INTERVAL DAY TO SECOND on Oracle, and bigint 

1630 of microseconds on other databases. 

1631 """ 

1632 

1633 empty_strings_allowed = False 

1634 default_error_messages = { 

1635 "invalid": "“%(value)s” value has an invalid format. It must be in [DD] [[HH:]MM:]ss[.uuuuuu] format.", 

1636 } 

1637 description = "Duration" 

1638 

1639 def get_internal_type(self): 

1640 return "DurationField" 

1641 

1642 def to_python(self, value): 

1643 if value is None: 

1644 return value 

1645 if isinstance(value, datetime.timedelta): 

1646 return value 

1647 try: 

1648 parsed = parse_duration(value) 

1649 except ValueError: 

1650 pass 

1651 else: 

1652 if parsed is not None: 

1653 return parsed 

1654 

1655 raise exceptions.ValidationError( 

1656 self.error_messages["invalid"], 

1657 code="invalid", 

1658 params={"value": value}, 

1659 ) 

1660 

1661 def get_db_prep_value(self, value, connection, prepared=False): 

1662 if connection.features.has_native_duration_field: 

1663 return value 

1664 if value is None: 

1665 return None 

1666 return duration_microseconds(value) 

1667 

1668 def get_db_converters(self, connection): 

1669 converters = [] 

1670 if not connection.features.has_native_duration_field: 

1671 converters.append(connection.ops.convert_durationfield_value) 

1672 return converters + super().get_db_converters(connection) 

1673 

1674 def value_to_string(self, obj): 

1675 val = self.value_from_object(obj) 

1676 return "" if val is None else duration_string(val) 

1677 

1678 

1679class EmailField(CharField): 

1680 default_validators = [validators.validate_email] 

1681 description = "Email address" 

1682 

1683 def __init__(self, *args, **kwargs): 

1684 # max_length=254 to be compliant with RFCs 3696 and 5321 

1685 kwargs.setdefault("max_length", 254) 

1686 super().__init__(*args, **kwargs) 

1687 

1688 def deconstruct(self): 

1689 name, path, args, kwargs = super().deconstruct() 

1690 # We do not exclude max_length if it matches default as we want to change 

1691 # the default in future. 

1692 return name, path, args, kwargs 

1693 

1694 

1695class FloatField(Field): 

1696 empty_strings_allowed = False 

1697 default_error_messages = { 

1698 "invalid": "“%(value)s” value must be a float.", 

1699 } 

1700 description = "Floating point number" 

1701 

1702 def get_prep_value(self, value): 

1703 value = super().get_prep_value(value) 

1704 if value is None: 

1705 return None 

1706 try: 

1707 return float(value) 

1708 except (TypeError, ValueError) as e: 

1709 raise e.__class__( 

1710 f"Field '{self.name}' expected a number but got {value!r}.", 

1711 ) from e 

1712 

1713 def get_internal_type(self): 

1714 return "FloatField" 

1715 

1716 def to_python(self, value): 

1717 if value is None: 

1718 return value 

1719 try: 

1720 return float(value) 

1721 except (TypeError, ValueError): 

1722 raise exceptions.ValidationError( 

1723 self.error_messages["invalid"], 

1724 code="invalid", 

1725 params={"value": value}, 

1726 ) 

1727 

1728 

1729class IntegerField(Field): 

1730 empty_strings_allowed = False 

1731 default_error_messages = { 

1732 "invalid": "“%(value)s” value must be an integer.", 

1733 } 

1734 description = "Integer" 

1735 

1736 def check(self, **kwargs): 

1737 return [ 

1738 *super().check(**kwargs), 

1739 *self._check_max_length_warning(), 

1740 ] 

1741 

1742 def _check_max_length_warning(self): 

1743 if self.max_length is not None: 

1744 return [ 

1745 preflight.Warning( 

1746 f"'max_length' is ignored when used with {self.__class__.__name__}.", 

1747 hint="Remove 'max_length' from field", 

1748 obj=self, 

1749 id="fields.W122", 

1750 ) 

1751 ] 

1752 return [] 

1753 

1754 @cached_property 

1755 def validators(self): 

1756 # These validators can't be added at field initialization time since 

1757 # they're based on values retrieved from `connection`. 

1758 validators_ = super().validators 

1759 internal_type = self.get_internal_type() 

1760 min_value, max_value = connection.ops.integer_field_range(internal_type) 

1761 if min_value is not None and not any( 

1762 ( 

1763 isinstance(validator, validators.MinValueValidator) 

1764 and ( 

1765 validator.limit_value() 

1766 if callable(validator.limit_value) 

1767 else validator.limit_value 

1768 ) 

1769 >= min_value 

1770 ) 

1771 for validator in validators_ 

1772 ): 

1773 validators_.append(validators.MinValueValidator(min_value)) 

1774 if max_value is not None and not any( 

1775 ( 

1776 isinstance(validator, validators.MaxValueValidator) 

1777 and ( 

1778 validator.limit_value() 

1779 if callable(validator.limit_value) 

1780 else validator.limit_value 

1781 ) 

1782 <= max_value 

1783 ) 

1784 for validator in validators_ 

1785 ): 

1786 validators_.append(validators.MaxValueValidator(max_value)) 

1787 return validators_ 

1788 

1789 def get_prep_value(self, value): 

1790 value = super().get_prep_value(value) 

1791 if value is None: 

1792 return None 

1793 try: 

1794 return int(value) 

1795 except (TypeError, ValueError) as e: 

1796 raise e.__class__( 

1797 f"Field '{self.name}' expected a number but got {value!r}.", 

1798 ) from e 

1799 

1800 def get_db_prep_value(self, value, connection, prepared=False): 

1801 value = super().get_db_prep_value(value, connection, prepared) 

1802 return connection.ops.adapt_integerfield_value(value, self.get_internal_type()) 

1803 

1804 def get_internal_type(self): 

1805 return "IntegerField" 

1806 

1807 def to_python(self, value): 

1808 if value is None: 

1809 return value 

1810 try: 

1811 return int(value) 

1812 except (TypeError, ValueError): 

1813 raise exceptions.ValidationError( 

1814 self.error_messages["invalid"], 

1815 code="invalid", 

1816 params={"value": value}, 

1817 ) 

1818 

1819 

1820class BigIntegerField(IntegerField): 

1821 description = "Big (8 byte) integer" 

1822 MAX_BIGINT = 9223372036854775807 

1823 

1824 def get_internal_type(self): 

1825 return "BigIntegerField" 

1826 

1827 

1828class SmallIntegerField(IntegerField): 

1829 description = "Small integer" 

1830 

1831 def get_internal_type(self): 

1832 return "SmallIntegerField" 

1833 

1834 

1835class IPAddressField(Field): 

1836 empty_strings_allowed = False 

1837 description = "IPv4 address" 

1838 system_check_removed_details = { 

1839 "msg": ( 

1840 "IPAddressField has been removed except for support in " 

1841 "historical migrations." 

1842 ), 

1843 "hint": "Use GenericIPAddressField instead.", 

1844 "id": "fields.E900", 

1845 } 

1846 

1847 def __init__(self, *args, **kwargs): 

1848 kwargs["max_length"] = 15 

1849 super().__init__(*args, **kwargs) 

1850 

1851 def deconstruct(self): 

1852 name, path, args, kwargs = super().deconstruct() 

1853 del kwargs["max_length"] 

1854 return name, path, args, kwargs 

1855 

1856 def get_prep_value(self, value): 

1857 value = super().get_prep_value(value) 

1858 if value is None: 

1859 return None 

1860 return str(value) 

1861 

1862 def get_internal_type(self): 

1863 return "IPAddressField" 

1864 

1865 

1866class GenericIPAddressField(Field): 

1867 empty_strings_allowed = False 

1868 description = "IP address" 

1869 default_error_messages = {} 

1870 

1871 def __init__( 

1872 self, 

1873 name=None, 

1874 protocol="both", 

1875 unpack_ipv4=False, 

1876 *args, 

1877 **kwargs, 

1878 ): 

1879 self.unpack_ipv4 = unpack_ipv4 

1880 self.protocol = protocol 

1881 ( 

1882 self.default_validators, 

1883 invalid_error_message, 

1884 ) = validators.ip_address_validators(protocol, unpack_ipv4) 

1885 self.default_error_messages["invalid"] = invalid_error_message 

1886 kwargs["max_length"] = 39 

1887 super().__init__(name, *args, **kwargs) 

1888 

1889 def check(self, **kwargs): 

1890 return [ 

1891 *super().check(**kwargs), 

1892 *self._check_blank_and_null_values(**kwargs), 

1893 ] 

1894 

1895 def _check_blank_and_null_values(self, **kwargs): 

1896 if not getattr(self, "null", False) and getattr(self, "blank", False): 

1897 return [ 

1898 preflight.Error( 

1899 "GenericIPAddressFields cannot have blank=True if null=False, " 

1900 "as blank values are stored as nulls.", 

1901 obj=self, 

1902 id="fields.E150", 

1903 ) 

1904 ] 

1905 return [] 

1906 

1907 def deconstruct(self): 

1908 name, path, args, kwargs = super().deconstruct() 

1909 if self.unpack_ipv4 is not False: 

1910 kwargs["unpack_ipv4"] = self.unpack_ipv4 

1911 if self.protocol != "both": 

1912 kwargs["protocol"] = self.protocol 

1913 if kwargs.get("max_length") == 39: 

1914 del kwargs["max_length"] 

1915 return name, path, args, kwargs 

1916 

1917 def get_internal_type(self): 

1918 return "GenericIPAddressField" 

1919 

1920 def to_python(self, value): 

1921 if value is None: 

1922 return None 

1923 if not isinstance(value, str): 

1924 value = str(value) 

1925 value = value.strip() 

1926 if ":" in value: 

1927 return clean_ipv6_address( 

1928 value, self.unpack_ipv4, self.error_messages["invalid"] 

1929 ) 

1930 return value 

1931 

1932 def get_db_prep_value(self, value, connection, prepared=False): 

1933 if not prepared: 

1934 value = self.get_prep_value(value) 

1935 return connection.ops.adapt_ipaddressfield_value(value) 

1936 

1937 def get_prep_value(self, value): 

1938 value = super().get_prep_value(value) 

1939 if value is None: 

1940 return None 

1941 if value and ":" in value: 

1942 try: 

1943 return clean_ipv6_address(value, self.unpack_ipv4) 

1944 except exceptions.ValidationError: 

1945 pass 

1946 return str(value) 

1947 

1948 

1949class NullBooleanField(BooleanField): 

1950 default_error_messages = { 

1951 "invalid": "“%(value)s” value must be either None, True or False.", 

1952 "invalid_nullable": "“%(value)s” value must be either None, True or False.", 

1953 } 

1954 description = "Boolean (Either True, False or None)" 

1955 system_check_removed_details = { 

1956 "msg": ( 

1957 "NullBooleanField is removed except for support in historical " 

1958 "migrations." 

1959 ), 

1960 "hint": "Use BooleanField(null=True) instead.", 

1961 "id": "fields.E903", 

1962 } 

1963 

1964 def __init__(self, *args, **kwargs): 

1965 kwargs["null"] = True 

1966 kwargs["blank"] = True 

1967 super().__init__(*args, **kwargs) 

1968 

1969 def deconstruct(self): 

1970 name, path, args, kwargs = super().deconstruct() 

1971 del kwargs["null"] 

1972 del kwargs["blank"] 

1973 return name, path, args, kwargs 

1974 

1975 

1976class PositiveIntegerRelDbTypeMixin: 

1977 def __init_subclass__(cls, **kwargs): 

1978 super().__init_subclass__(**kwargs) 

1979 if not hasattr(cls, "integer_field_class"): 

1980 cls.integer_field_class = next( 

1981 ( 

1982 parent 

1983 for parent in cls.__mro__[1:] 

1984 if issubclass(parent, IntegerField) 

1985 ), 

1986 None, 

1987 ) 

1988 

1989 def rel_db_type(self, connection): 

1990 """ 

1991 Return the data type that a related field pointing to this field should 

1992 use. In most cases, a foreign key pointing to a positive integer 

1993 primary key will have an integer column data type but some databases 

1994 (e.g. MySQL) have an unsigned integer type. In that case 

1995 (related_fields_match_type=True), the primary key should return its 

1996 db_type. 

1997 """ 

1998 if connection.features.related_fields_match_type: 

1999 return self.db_type(connection) 

2000 else: 

2001 return self.integer_field_class().db_type(connection=connection) 

2002 

2003 

2004class PositiveBigIntegerField(PositiveIntegerRelDbTypeMixin, BigIntegerField): 

2005 description = "Positive big integer" 

2006 

2007 def get_internal_type(self): 

2008 return "PositiveBigIntegerField" 

2009 

2010 

2011class PositiveIntegerField(PositiveIntegerRelDbTypeMixin, IntegerField): 

2012 description = "Positive integer" 

2013 

2014 def get_internal_type(self): 

2015 return "PositiveIntegerField" 

2016 

2017 

2018class PositiveSmallIntegerField(PositiveIntegerRelDbTypeMixin, SmallIntegerField): 

2019 description = "Positive small integer" 

2020 

2021 def get_internal_type(self): 

2022 return "PositiveSmallIntegerField" 

2023 

2024 

2025class SlugField(CharField): 

2026 default_validators = [validators.validate_slug] 

2027 description = "Slug (up to %(max_length)s)" 

2028 

2029 def __init__( 

2030 self, *args, max_length=50, db_index=True, allow_unicode=False, **kwargs 

2031 ): 

2032 self.allow_unicode = allow_unicode 

2033 if self.allow_unicode: 

2034 self.default_validators = [validators.validate_unicode_slug] 

2035 super().__init__(*args, max_length=max_length, db_index=db_index, **kwargs) 

2036 

2037 def deconstruct(self): 

2038 name, path, args, kwargs = super().deconstruct() 

2039 if kwargs.get("max_length") == 50: 

2040 del kwargs["max_length"] 

2041 if self.db_index is False: 

2042 kwargs["db_index"] = False 

2043 else: 

2044 del kwargs["db_index"] 

2045 if self.allow_unicode is not False: 

2046 kwargs["allow_unicode"] = self.allow_unicode 

2047 return name, path, args, kwargs 

2048 

2049 def get_internal_type(self): 

2050 return "SlugField" 

2051 

2052 

2053class TextField(Field): 

2054 description = "Text" 

2055 

2056 def __init__(self, *args, db_collation=None, **kwargs): 

2057 super().__init__(*args, **kwargs) 

2058 self.db_collation = db_collation 

2059 

2060 def check(self, **kwargs): 

2061 databases = kwargs.get("databases") or [] 

2062 return [ 

2063 *super().check(**kwargs), 

2064 *self._check_db_collation(databases), 

2065 ] 

2066 

2067 def _check_db_collation(self, databases): 

2068 errors = [] 

2069 for db in databases: 

2070 if not router.allow_migrate_model(db, self.model): 

2071 continue 

2072 connection = connections[db] 

2073 if not ( 

2074 self.db_collation is None 

2075 or "supports_collation_on_textfield" 

2076 in self.model._meta.required_db_features 

2077 or connection.features.supports_collation_on_textfield 

2078 ): 

2079 errors.append( 

2080 preflight.Error( 

2081 f"{connection.display_name} does not support a database collation on " 

2082 "TextFields.", 

2083 obj=self, 

2084 id="fields.E190", 

2085 ), 

2086 ) 

2087 return errors 

2088 

2089 def db_parameters(self, connection): 

2090 db_params = super().db_parameters(connection) 

2091 db_params["collation"] = self.db_collation 

2092 return db_params 

2093 

2094 def get_internal_type(self): 

2095 return "TextField" 

2096 

2097 def to_python(self, value): 

2098 if isinstance(value, str) or value is None: 

2099 return value 

2100 return str(value) 

2101 

2102 def get_prep_value(self, value): 

2103 value = super().get_prep_value(value) 

2104 return self.to_python(value) 

2105 

2106 def deconstruct(self): 

2107 name, path, args, kwargs = super().deconstruct() 

2108 if self.db_collation: 

2109 kwargs["db_collation"] = self.db_collation 

2110 return name, path, args, kwargs 

2111 

2112 

2113class TimeField(DateTimeCheckMixin, Field): 

2114 empty_strings_allowed = False 

2115 default_error_messages = { 

2116 "invalid": "“%(value)s” value has an invalid format. It must be in HH:MM[:ss[.uuuuuu]] format.", 

2117 "invalid_time": "“%(value)s” value has the correct format (HH:MM[:ss[.uuuuuu]]) but it is an invalid time.", 

2118 } 

2119 description = "Time" 

2120 

2121 def __init__(self, name=None, auto_now=False, auto_now_add=False, **kwargs): 

2122 self.auto_now, self.auto_now_add = auto_now, auto_now_add 

2123 if auto_now or auto_now_add: 

2124 kwargs["editable"] = False 

2125 kwargs["blank"] = True 

2126 super().__init__(name, **kwargs) 

2127 

2128 def _check_fix_default_value(self): 

2129 """ 

2130 Warn that using an actual date or datetime value is probably wrong; 

2131 it's only evaluated on server startup. 

2132 """ 

2133 if not self.has_default(): 

2134 return [] 

2135 

2136 value = self.default 

2137 if isinstance(value, datetime.datetime): 

2138 now = None 

2139 elif isinstance(value, datetime.time): 

2140 now = _get_naive_now() 

2141 # This will not use the right date in the race condition where now 

2142 # is just before the date change and value is just past 0:00. 

2143 value = datetime.datetime.combine(now.date(), value) 

2144 else: 

2145 # No explicit time / datetime value -- no checks necessary 

2146 return [] 

2147 # At this point, value is a datetime object. 

2148 return self._check_if_value_fixed(value, now=now) 

2149 

2150 def deconstruct(self): 

2151 name, path, args, kwargs = super().deconstruct() 

2152 if self.auto_now is not False: 

2153 kwargs["auto_now"] = self.auto_now 

2154 if self.auto_now_add is not False: 

2155 kwargs["auto_now_add"] = self.auto_now_add 

2156 if self.auto_now or self.auto_now_add: 

2157 del kwargs["blank"] 

2158 del kwargs["editable"] 

2159 return name, path, args, kwargs 

2160 

2161 def get_internal_type(self): 

2162 return "TimeField" 

2163 

2164 def to_python(self, value): 

2165 if value is None: 

2166 return None 

2167 if isinstance(value, datetime.time): 

2168 return value 

2169 if isinstance(value, datetime.datetime): 

2170 # Not usually a good idea to pass in a datetime here (it loses 

2171 # information), but this can be a side-effect of interacting with a 

2172 # database backend (e.g. Oracle), so we'll be accommodating. 

2173 return value.time() 

2174 

2175 try: 

2176 parsed = parse_time(value) 

2177 if parsed is not None: 

2178 return parsed 

2179 except ValueError: 

2180 raise exceptions.ValidationError( 

2181 self.error_messages["invalid_time"], 

2182 code="invalid_time", 

2183 params={"value": value}, 

2184 ) 

2185 

2186 raise exceptions.ValidationError( 

2187 self.error_messages["invalid"], 

2188 code="invalid", 

2189 params={"value": value}, 

2190 ) 

2191 

2192 def pre_save(self, model_instance, add): 

2193 if self.auto_now or (self.auto_now_add and add): 

2194 value = datetime.datetime.now().time() 

2195 setattr(model_instance, self.attname, value) 

2196 return value 

2197 else: 

2198 return super().pre_save(model_instance, add) 

2199 

2200 def get_prep_value(self, value): 

2201 value = super().get_prep_value(value) 

2202 return self.to_python(value) 

2203 

2204 def get_db_prep_value(self, value, connection, prepared=False): 

2205 # Casts times into the format expected by the backend 

2206 if not prepared: 

2207 value = self.get_prep_value(value) 

2208 return connection.ops.adapt_timefield_value(value) 

2209 

2210 def value_to_string(self, obj): 

2211 val = self.value_from_object(obj) 

2212 return "" if val is None else val.isoformat() 

2213 

2214 

2215class URLField(CharField): 

2216 default_validators = [validators.URLValidator()] 

2217 description = "URL" 

2218 

2219 def __init__(self, name=None, **kwargs): 

2220 kwargs.setdefault("max_length", 200) 

2221 super().__init__(name, **kwargs) 

2222 

2223 def deconstruct(self): 

2224 name, path, args, kwargs = super().deconstruct() 

2225 if kwargs.get("max_length") == 200: 

2226 del kwargs["max_length"] 

2227 return name, path, args, kwargs 

2228 

2229 

2230class BinaryField(Field): 

2231 description = "Raw binary data" 

2232 empty_values = [None, b""] 

2233 

2234 def __init__(self, *args, **kwargs): 

2235 kwargs.setdefault("editable", False) 

2236 super().__init__(*args, **kwargs) 

2237 if self.max_length is not None: 

2238 self.validators.append(validators.MaxLengthValidator(self.max_length)) 

2239 

2240 def check(self, **kwargs): 

2241 return [*super().check(**kwargs), *self._check_str_default_value()] 

2242 

2243 def _check_str_default_value(self): 

2244 if self.has_default() and isinstance(self.default, str): 

2245 return [ 

2246 preflight.Error( 

2247 "BinaryField's default cannot be a string. Use bytes " 

2248 "content instead.", 

2249 obj=self, 

2250 id="fields.E170", 

2251 ) 

2252 ] 

2253 return [] 

2254 

2255 def deconstruct(self): 

2256 name, path, args, kwargs = super().deconstruct() 

2257 if self.editable: 

2258 kwargs["editable"] = True 

2259 else: 

2260 del kwargs["editable"] 

2261 return name, path, args, kwargs 

2262 

2263 def get_internal_type(self): 

2264 return "BinaryField" 

2265 

2266 def get_placeholder(self, value, compiler, connection): 

2267 return connection.ops.binary_placeholder_sql(value) 

2268 

2269 def get_default(self): 

2270 if self.has_default() and not callable(self.default): 

2271 return self.default 

2272 default = super().get_default() 

2273 if default == "": 

2274 return b"" 

2275 return default 

2276 

2277 def get_db_prep_value(self, value, connection, prepared=False): 

2278 value = super().get_db_prep_value(value, connection, prepared) 

2279 if value is not None: 

2280 return connection.Database.Binary(value) 

2281 return value 

2282 

2283 def value_to_string(self, obj): 

2284 """Binary data is serialized as base64""" 

2285 return b64encode(self.value_from_object(obj)).decode("ascii") 

2286 

2287 def to_python(self, value): 

2288 # If it's a string, it should be base64-encoded data 

2289 if isinstance(value, str): 

2290 return memoryview(b64decode(value.encode("ascii"))) 

2291 return value 

2292 

2293 

2294class UUIDField(Field): 

2295 default_error_messages = { 

2296 "invalid": "“%(value)s” is not a valid UUID.", 

2297 } 

2298 description = "Universally unique identifier" 

2299 empty_strings_allowed = False 

2300 

2301 def __init__(self, **kwargs): 

2302 kwargs["max_length"] = 32 

2303 super().__init__(**kwargs) 

2304 

2305 def deconstruct(self): 

2306 name, path, args, kwargs = super().deconstruct() 

2307 del kwargs["max_length"] 

2308 return name, path, args, kwargs 

2309 

2310 def get_internal_type(self): 

2311 return "UUIDField" 

2312 

2313 def get_prep_value(self, value): 

2314 value = super().get_prep_value(value) 

2315 return self.to_python(value) 

2316 

2317 def get_db_prep_value(self, value, connection, prepared=False): 

2318 if value is None: 

2319 return None 

2320 if not isinstance(value, uuid.UUID): 

2321 value = self.to_python(value) 

2322 

2323 if connection.features.has_native_uuid_field: 

2324 return value 

2325 return value.hex 

2326 

2327 def to_python(self, value): 

2328 if value is not None and not isinstance(value, uuid.UUID): 

2329 input_form = "int" if isinstance(value, int) else "hex" 

2330 try: 

2331 return uuid.UUID(**{input_form: value}) 

2332 except (AttributeError, ValueError): 

2333 raise exceptions.ValidationError( 

2334 self.error_messages["invalid"], 

2335 code="invalid", 

2336 params={"value": value}, 

2337 ) 

2338 return value 

2339 

2340 

2341class AutoFieldMixin: 

2342 db_returning = True 

2343 

2344 def __init__(self, *args, **kwargs): 

2345 kwargs["blank"] = True 

2346 super().__init__(*args, **kwargs) 

2347 

2348 def check(self, **kwargs): 

2349 return [ 

2350 *super().check(**kwargs), 

2351 *self._check_primary_key(), 

2352 ] 

2353 

2354 def _check_primary_key(self): 

2355 if not self.primary_key: 

2356 return [ 

2357 preflight.Error( 

2358 "AutoFields must set primary_key=True.", 

2359 obj=self, 

2360 id="fields.E100", 

2361 ), 

2362 ] 

2363 else: 

2364 return [] 

2365 

2366 def deconstruct(self): 

2367 name, path, args, kwargs = super().deconstruct() 

2368 del kwargs["blank"] 

2369 kwargs["primary_key"] = True 

2370 return name, path, args, kwargs 

2371 

2372 def validate(self, value, model_instance): 

2373 pass 

2374 

2375 def get_db_prep_value(self, value, connection, prepared=False): 

2376 if not prepared: 

2377 value = self.get_prep_value(value) 

2378 value = connection.ops.validate_autopk_value(value) 

2379 return value 

2380 

2381 def contribute_to_class(self, cls, name, **kwargs): 

2382 if cls._meta.auto_field: 

2383 raise ValueError( 

2384 f"Model {cls._meta.label} can't have more than one auto-generated field." 

2385 ) 

2386 super().contribute_to_class(cls, name, **kwargs) 

2387 cls._meta.auto_field = self 

2388 

2389 

2390class AutoFieldMeta(type): 

2391 """ 

2392 Metaclass to maintain backward inheritance compatibility for AutoField. 

2393 

2394 It is intended that AutoFieldMixin become public API when it is possible to 

2395 create a non-integer automatically-generated field using column defaults 

2396 stored in the database. 

2397 

2398 In many areas Plain also relies on using isinstance() to check for an 

2399 automatically-generated field as a subclass of AutoField. A new flag needs 

2400 to be implemented on Field to be used instead. 

2401 

2402 When these issues have been addressed, this metaclass could be used to 

2403 deprecate inheritance from AutoField and use of isinstance() with AutoField 

2404 for detecting automatically-generated fields. 

2405 """ 

2406 

2407 @property 

2408 def _subclasses(self): 

2409 return (BigAutoField, SmallAutoField) 

2410 

2411 def __instancecheck__(self, instance): 

2412 return isinstance(instance, self._subclasses) or super().__instancecheck__( 

2413 instance 

2414 ) 

2415 

2416 def __subclasscheck__(self, subclass): 

2417 return issubclass(subclass, self._subclasses) or super().__subclasscheck__( 

2418 subclass 

2419 ) 

2420 

2421 

2422class AutoField(AutoFieldMixin, IntegerField, metaclass=AutoFieldMeta): 

2423 def get_internal_type(self): 

2424 return "AutoField" 

2425 

2426 def rel_db_type(self, connection): 

2427 return IntegerField().db_type(connection=connection) 

2428 

2429 

2430class BigAutoField(AutoFieldMixin, BigIntegerField): 

2431 def get_internal_type(self): 

2432 return "BigAutoField" 

2433 

2434 def rel_db_type(self, connection): 

2435 return BigIntegerField().db_type(connection=connection) 

2436 

2437 

2438class SmallAutoField(AutoFieldMixin, SmallIntegerField): 

2439 def get_internal_type(self): 

2440 return "SmallAutoField" 

2441 

2442 def rel_db_type(self, connection): 

2443 return SmallIntegerField().db_type(connection=connection)