|
2 | 2 | import functools
|
3 | 3 | import json
|
4 | 4 | from decimal import Decimal
|
| 5 | +from enum import Enum, IntEnum |
5 | 6 | from typing import TYPE_CHECKING, Any, Awaitable, Generic, Optional, Type, TypeVar, Union
|
6 | 7 | from uuid import UUID, uuid4
|
7 | 8 |
|
@@ -407,6 +408,100 @@ def to_python_value(self, value: Any) -> Optional[UUID]:
|
407 | 408 | return UUID(value)
|
408 | 409 |
|
409 | 410 |
|
| 411 | +class IntEnumField(SmallIntField): |
| 412 | + """ |
| 413 | + Enum Field |
| 414 | +
|
| 415 | + A field representing an integer enumeration. |
| 416 | +
|
| 417 | + The description of the field is set automatically if not specified to a multiline list of |
| 418 | + "name: value" pairs. |
| 419 | +
|
| 420 | + ``enum_type``: |
| 421 | + The enum class |
| 422 | + ``description``: |
| 423 | + The description of the field. It is set automatically if not specified to a multiline list |
| 424 | + of "name: value" pairs. |
| 425 | + """ |
| 426 | + |
| 427 | + __slots__ = ("enum_type",) |
| 428 | + |
| 429 | + def __init__( |
| 430 | + self, enum_type: Type[IntEnum], description: Optional[str] = None, **kwargs |
| 431 | + ) -> None: |
| 432 | + # Validate values |
| 433 | + for item in enum_type: |
| 434 | + try: |
| 435 | + value = int(item.value) |
| 436 | + except ValueError: |
| 437 | + raise ConfigurationError("IntEnumField only supports integer enums!") |
| 438 | + if not 0 <= value < 32768: |
| 439 | + raise ConfigurationError("The valid range of IntEnumField's values is 0..32767!") |
| 440 | + |
| 441 | + # Automatic description for the field if not specified by the user |
| 442 | + if description is None: |
| 443 | + description = "\n".join([f"{e.name}: {int(e.value)}" for e in enum_type])[:2048] |
| 444 | + |
| 445 | + super().__init__(description=description, **kwargs) |
| 446 | + self.enum_type = enum_type |
| 447 | + |
| 448 | + def to_python_value(self, value: Union[int, None]) -> Union[IntEnum, None]: |
| 449 | + return self.enum_type(value) if value is not None else None |
| 450 | + |
| 451 | + def to_db_value(self, value: Union[IntEnum, None], instance) -> Union[int, None]: |
| 452 | + return int(value.value) if value is not None else None |
| 453 | + |
| 454 | + |
| 455 | +class CharEnumField(CharField): |
| 456 | + """ |
| 457 | + Char Enum Field |
| 458 | +
|
| 459 | + A field representing a character enumeration. |
| 460 | +
|
| 461 | + **Warning**: If ``max_length`` is not specified or equals to zero, the size of represented |
| 462 | + char fields is automatically detected. So if later you update the enum, you need to update your |
| 463 | + table schema as well. |
| 464 | +
|
| 465 | + ``enum_type``: |
| 466 | + The enum class |
| 467 | + ``description``: |
| 468 | + The description of the field. It is set automatically if not specified to a multiline list |
| 469 | + of "name: value" pairs. |
| 470 | + ``max_length``: |
| 471 | + The length of the created CharField. If it is zero it is automatically detected from |
| 472 | + enum_type. |
| 473 | + """ |
| 474 | + |
| 475 | + __slots__ = ("enum_type",) |
| 476 | + |
| 477 | + def __init__( |
| 478 | + self, |
| 479 | + enum_type: Type[Enum], |
| 480 | + description: Optional[str] = None, |
| 481 | + max_length: int = 0, |
| 482 | + **kwargs, |
| 483 | + ) -> None: |
| 484 | + # Automatic description for the field if not specified by the user |
| 485 | + if description is None: |
| 486 | + description = "\n".join([f"{e.name}: {str(e.value)}" for e in enum_type])[:2048] |
| 487 | + |
| 488 | + # Automatic CharField max_length |
| 489 | + if max_length == 0: |
| 490 | + for item in enum_type: |
| 491 | + item_len = len(str(item.value)) |
| 492 | + if item_len > max_length: |
| 493 | + max_length = item_len |
| 494 | + |
| 495 | + super().__init__(description=description, max_length=max_length, **kwargs) |
| 496 | + self.enum_type = enum_type |
| 497 | + |
| 498 | + def to_python_value(self, value: Union[str, None]) -> Union[Enum, None]: |
| 499 | + return self.enum_type(value) if value is not None else None |
| 500 | + |
| 501 | + def to_db_value(self, value: Union[Enum, None], instance) -> Union[str, None]: |
| 502 | + return str(value.value) if value is not None else None |
| 503 | + |
| 504 | + |
410 | 505 | ForeignKeyNullableRelation = Union[Awaitable[Optional[MODEL]], Optional[MODEL]]
|
411 | 506 | """
|
412 | 507 | Type hint for the result of accessing the :class:`.ForeignKeyField` field in the model
|
|
0 commit comments