Files
outbo-2-stgclone/evg-outbo-api/outbo/apps/core/fields.py
T
2024-11-27 13:18:16 +01:00

123 lines
3.6 KiB
Python
Executable File

from functools import partial
from django import forms
from django.db import models
from django_extensions.db.fields import (
CreationDateTimeField as BaseCreationDateTimeField,
ModificationDateTimeField as BaseModificationDateTimeField,
)
from django_fsm import FSMFieldMixin
from outbo.apps.core.forms import EnumChoiceField
class CreationDateTimeField(BaseCreationDateTimeField):
"""
CreationDateTimeField
By default, sets editable=False, blank=True, auto_now_add=True
"""
class ModificationDateTimeField(BaseModificationDateTimeField):
"""
ModificationDateTimeField
By default, sets editable=False, blank=True, auto_now=True
Sets value to now every time the object is saved.
"""
class RemovalDateTimeField(models.DateTimeField):
"""
RemovalDateTimeField
By default, sets editable=False, blank=True, null=True
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault("editable", False)
kwargs.setdefault("blank", True)
kwargs.setdefault("null", True)
models.DateTimeField.__init__(self, *args, **kwargs)
def get_internal_type(self):
return "DateTimeField"
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
if self.editable is not False:
kwargs["editable"] = True
if self.blank is not True:
kwargs["blank"] = False
if self.null is not True:
kwargs["null"] = False
return name, path, args, kwargs
class FSMKeyField(FSMFieldMixin, models.ForeignKey):
def get_state(self, instance):
return instance.__dict__[self.attname]
def set_state(self, instance, state):
instance.__dict__[self.attname] = self.to_python(state)
class EnumCharField(models.CharField):
def __init__(self, *args, **kwargs):
enum = kwargs.pop("enum", None)
if enum is not None:
if kwargs.get("choices", None) is not None:
raise ValueError("Cannot provide choices for EnumCharField")
kwargs["choices"] = [(item, item.value) for item in enum]
super().__init__(*args, **kwargs)
self.validators.pop() # lengthvalidator not necessary on this one
self.enum = enum
def get_internal_type(self):
return "CharField"
def formfield(self, **kwargs):
enum_form_class = partial(EnumChoiceField, enum=self.enum)
defaults = {
"widget": forms.Select,
"form_class": enum_form_class,
"choices": [(str(item), item.value) for item in self.enum],
}
defaults.update(kwargs)
return super().formfield(**defaults)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
kwargs["enum"] = self.enum
if "choices" in kwargs:
del kwargs["choices"]
return name, path, args, kwargs
def to_python(self, value):
value = super().to_python(value)
if value is not None:
if not isinstance(value, self.enum):
enum_name, enum_value = value.split(".", 1)
if enum_name == self.enum.__name__:
return self.enum[enum_value]
return value
def get_prep_value(self, value):
value = super().get_prep_value(value)
if value is None:
return value
if isinstance(value, self.enum):
return str(value)
return value
def from_db_value(self, value, *args):
if value is not None:
enum_name, enum_value = value.split(".", 1)
if enum_name == self.enum.__name__:
return self.enum[enum_value]
return value