1from typing import Any
2
3from plain import exceptions
4
5from .base import DefaultableField
6
7
8class BooleanField[T: (bool, bool | None) = bool](DefaultableField[T]):
9 db_type_sql = "boolean"
10 empty_strings_allowed = False
11
12 def to_python(self, value: Any) -> bool | None:
13 if self.allow_null and value in self.empty_values:
14 return None
15 if value in (True, False):
16 # 1/0 are equal to True/False. bool() converts former to latter.
17 return bool(value)
18 if value in ("t", "True", "1"):
19 return True
20 if value in ("f", "False", "0"):
21 return False
22 if self.allow_null:
23 message = '"%(value)s" value must be either True, False, or None.'
24 else:
25 message = '"%(value)s" value must be either True or False.'
26 raise exceptions.ValidationError(
27 message,
28 code="invalid",
29 params={"value": value},
30 )
31
32 def get_prep_value(self, value: Any) -> Any:
33 value = super().get_prep_value(value)
34 if value is None:
35 return None
36 return self.to_python(value)