mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-29 12:06:44 +00:00
abstracting Settings model
This commit is contained in:
parent
af68ea23c3
commit
ec53099872
@ -11,6 +11,7 @@ import decimal
|
|||||||
import math
|
import math
|
||||||
|
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.contrib.auth.models import User
|
||||||
from django.db.utils import IntegrityError, OperationalError
|
from django.db.utils import IntegrityError, OperationalError
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
@ -28,7 +29,394 @@ import InvenTree.helpers
|
|||||||
import InvenTree.fields
|
import InvenTree.fields
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeSetting(models.Model):
|
class BaseInvenTreeSetting(models.Model):
|
||||||
|
"""
|
||||||
|
An base InvenTreeSetting object is a key:value pair used for storing
|
||||||
|
single values (e.g. one-off settings values).
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
GLOBAL_SETTINGS = {}
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_name(cls, key):
|
||||||
|
"""
|
||||||
|
Return the name of a particular setting.
|
||||||
|
|
||||||
|
If it does not exist, return an empty string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
if key in cls.GLOBAL_SETTINGS:
|
||||||
|
setting = cls.GLOBAL_SETTINGS[key]
|
||||||
|
return setting.get('name', '')
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_description(cls, key):
|
||||||
|
"""
|
||||||
|
Return the description for a particular setting.
|
||||||
|
|
||||||
|
If it does not exist, return an empty string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
if key in cls.GLOBAL_SETTINGS:
|
||||||
|
setting = cls.GLOBAL_SETTINGS[key]
|
||||||
|
return setting.get('description', '')
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_units(cls, key):
|
||||||
|
"""
|
||||||
|
Return the units for a particular setting.
|
||||||
|
|
||||||
|
If it does not exist, return an empty string.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
if key in cls.GLOBAL_SETTINGS:
|
||||||
|
setting = cls.GLOBAL_SETTINGS[key]
|
||||||
|
return setting.get('units', '')
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_validator(cls, key):
|
||||||
|
"""
|
||||||
|
Return the validator for a particular setting.
|
||||||
|
|
||||||
|
If it does not exist, return None
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
if key in cls.GLOBAL_SETTINGS:
|
||||||
|
setting = cls.GLOBAL_SETTINGS[key]
|
||||||
|
return setting.get('validator', None)
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_default(cls, key):
|
||||||
|
"""
|
||||||
|
Return the default value for a particular setting.
|
||||||
|
|
||||||
|
If it does not exist, return an empty string
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
if key in cls.GLOBAL_SETTINGS:
|
||||||
|
setting = cls.GLOBAL_SETTINGS[key]
|
||||||
|
return setting.get('default', '')
|
||||||
|
else:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_choices(cls, key):
|
||||||
|
"""
|
||||||
|
Return the validator choices available for a particular setting.
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
if key in cls.GLOBAL_SETTINGS:
|
||||||
|
setting = cls.GLOBAL_SETTINGS[key]
|
||||||
|
choices = setting.get('choices', None)
|
||||||
|
else:
|
||||||
|
choices = None
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO:
|
||||||
|
if type(choices) is function:
|
||||||
|
# Evaluate the function (we expect it will return a list of tuples...)
|
||||||
|
return choices()
|
||||||
|
"""
|
||||||
|
|
||||||
|
return choices
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_object(cls, key):
|
||||||
|
"""
|
||||||
|
Return an InvenTreeSetting object matching the given key.
|
||||||
|
|
||||||
|
- Key is case-insensitive
|
||||||
|
- Returns None if no match is made
|
||||||
|
"""
|
||||||
|
|
||||||
|
key = str(key).strip().upper()
|
||||||
|
|
||||||
|
try:
|
||||||
|
setting = cls.objects.filter(key__iexact=key).first()
|
||||||
|
except (ValueError, cls.DoesNotExist):
|
||||||
|
setting = None
|
||||||
|
except (IntegrityError, OperationalError):
|
||||||
|
setting = None
|
||||||
|
|
||||||
|
# Setting does not exist! (Try to create it)
|
||||||
|
if not setting:
|
||||||
|
|
||||||
|
setting = cls(key=key, value=cls.get_setting_default(key))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Wrap this statement in "atomic", so it can be rolled back if it fails
|
||||||
|
with transaction.atomic():
|
||||||
|
setting.save()
|
||||||
|
except (IntegrityError, OperationalError):
|
||||||
|
# It might be the case that the database isn't created yet
|
||||||
|
pass
|
||||||
|
|
||||||
|
return setting
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting_pk(cls, key):
|
||||||
|
"""
|
||||||
|
Return the primary-key value for a given setting.
|
||||||
|
|
||||||
|
If the setting does not exist, return None
|
||||||
|
"""
|
||||||
|
|
||||||
|
setting = cls.get_setting_object(cls)
|
||||||
|
|
||||||
|
if setting:
|
||||||
|
return setting.pk
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_setting(cls, key, backup_value=None):
|
||||||
|
"""
|
||||||
|
Get the value of a particular setting.
|
||||||
|
If it does not exist, return the backup value (default = None)
|
||||||
|
"""
|
||||||
|
|
||||||
|
# If no backup value is specified, atttempt to retrieve a "default" value
|
||||||
|
if backup_value is None:
|
||||||
|
backup_value = cls.get_setting_default(key)
|
||||||
|
|
||||||
|
setting = cls.get_setting_object(key)
|
||||||
|
|
||||||
|
if setting:
|
||||||
|
value = setting.value
|
||||||
|
|
||||||
|
# If the particular setting is defined as a boolean, cast the value to a boolean
|
||||||
|
if setting.is_bool():
|
||||||
|
value = InvenTree.helpers.str2bool(value)
|
||||||
|
|
||||||
|
if setting.is_int():
|
||||||
|
try:
|
||||||
|
value = int(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
value = backup_value
|
||||||
|
|
||||||
|
else:
|
||||||
|
value = backup_value
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set_setting(cls, key, value, user, create=True):
|
||||||
|
"""
|
||||||
|
Set the value of a particular setting.
|
||||||
|
If it does not exist, option to create it.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
key: settings key
|
||||||
|
value: New value
|
||||||
|
user: User object (must be staff member to update a core setting)
|
||||||
|
create: If True, create a new setting if the specified key does not exist.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if user is not None and not user.is_staff:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
setting = cls.objects.get(key__iexact=key)
|
||||||
|
except cls.DoesNotExist:
|
||||||
|
|
||||||
|
if create:
|
||||||
|
setting = cls(key=key)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Enforce standard boolean representation
|
||||||
|
if setting.is_bool():
|
||||||
|
value = InvenTree.helpers.str2bool(value)
|
||||||
|
|
||||||
|
setting.value = str(value)
|
||||||
|
setting.save()
|
||||||
|
|
||||||
|
key = models.CharField(max_length=50, blank=False, unique=True, help_text=_('Settings key (must be unique - case insensitive'))
|
||||||
|
|
||||||
|
value = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings value'))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return self.__class__.get_setting_name(self.key)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def default_value(self):
|
||||||
|
return self.__class__.get_setting_default(self.key)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def description(self):
|
||||||
|
return self.__class__.get_setting_description(self.key)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def units(self):
|
||||||
|
return self.__class__.get_setting_units(self.key)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
"""
|
||||||
|
If a validator (or multiple validators) are defined for a particular setting key,
|
||||||
|
run them against the 'value' field.
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
validator = self.__class__.get_setting_validator(self.key)
|
||||||
|
|
||||||
|
if self.is_bool():
|
||||||
|
self.value = InvenTree.helpers.str2bool(self.value)
|
||||||
|
|
||||||
|
if self.is_int():
|
||||||
|
try:
|
||||||
|
self.value = int(self.value)
|
||||||
|
except (ValueError):
|
||||||
|
raise ValidationError(_('Must be an integer value'))
|
||||||
|
|
||||||
|
if validator is not None:
|
||||||
|
self.run_validator(validator)
|
||||||
|
|
||||||
|
def run_validator(self, validator):
|
||||||
|
"""
|
||||||
|
Run a validator against the 'value' field for this InvenTreeSetting object.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if validator is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
value = self.value
|
||||||
|
|
||||||
|
# Boolean validator
|
||||||
|
if self.is_bool():
|
||||||
|
# Value must "look like" a boolean value
|
||||||
|
if InvenTree.helpers.is_bool(value):
|
||||||
|
# Coerce into either "True" or "False"
|
||||||
|
value = InvenTree.helpers.str2bool(value)
|
||||||
|
else:
|
||||||
|
raise ValidationError({
|
||||||
|
'value': _('Value must be a boolean value')
|
||||||
|
})
|
||||||
|
|
||||||
|
# Integer validator
|
||||||
|
if self.is_int():
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Coerce into an integer value
|
||||||
|
value = int(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
raise ValidationError({
|
||||||
|
'value': _('Value must be an integer value'),
|
||||||
|
})
|
||||||
|
|
||||||
|
# If a list of validators is supplied, iterate through each one
|
||||||
|
if type(validator) in [list, tuple]:
|
||||||
|
for v in validator:
|
||||||
|
self.run_validator(v)
|
||||||
|
|
||||||
|
if callable(validator):
|
||||||
|
# We can accept function validators with a single argument
|
||||||
|
validator(self.value)
|
||||||
|
|
||||||
|
def validate_unique(self, exclude=None):
|
||||||
|
""" Ensure that the key:value pair is unique.
|
||||||
|
In addition to the base validators, this ensures that the 'key'
|
||||||
|
is unique, using a case-insensitive comparison.
|
||||||
|
"""
|
||||||
|
|
||||||
|
super().validate_unique(exclude)
|
||||||
|
|
||||||
|
try:
|
||||||
|
setting = self.__class__.objects.exclude(id=self.id).filter(key__iexact=self.key)
|
||||||
|
if setting.exists():
|
||||||
|
raise ValidationError({'key': _('Key string must be unique')})
|
||||||
|
except self.DoesNotExist:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def choices(self):
|
||||||
|
"""
|
||||||
|
Return the available choices for this setting (or None if no choices are defined)
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.__class__.get_setting_choices(self.key)
|
||||||
|
|
||||||
|
def is_bool(self):
|
||||||
|
"""
|
||||||
|
Check if this setting is required to be a boolean value
|
||||||
|
"""
|
||||||
|
|
||||||
|
validator = self.__class__.get_setting_validator(self.key)
|
||||||
|
|
||||||
|
if validator == bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if type(validator) in [list, tuple]:
|
||||||
|
for v in validator:
|
||||||
|
if v == bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def as_bool(self):
|
||||||
|
"""
|
||||||
|
Return the value of this setting converted to a boolean value.
|
||||||
|
|
||||||
|
Warning: Only use on values where is_bool evaluates to true!
|
||||||
|
"""
|
||||||
|
|
||||||
|
return InvenTree.helpers.str2bool(self.value)
|
||||||
|
|
||||||
|
def is_int(self):
|
||||||
|
"""
|
||||||
|
Check if the setting is required to be an integer value:
|
||||||
|
"""
|
||||||
|
|
||||||
|
validator = self.__class__.get_setting_validator(self.key)
|
||||||
|
|
||||||
|
if validator == int:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if type(validator) in [list, tuple]:
|
||||||
|
for v in validator:
|
||||||
|
if v == int:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def as_int(self):
|
||||||
|
"""
|
||||||
|
Return the value of this setting converted to a boolean value.
|
||||||
|
|
||||||
|
If an error occurs, return the default value
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
value = int(self.value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
value = self.default_value()
|
||||||
|
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class InvenTreeSetting(BaseInvenTreeSetting):
|
||||||
"""
|
"""
|
||||||
An InvenTreeSetting object is a key:value pair used for storing
|
An InvenTreeSetting object is a key:value pair used for storing
|
||||||
single values (e.g. one-off settings values).
|
single values (e.g. one-off settings values).
|
||||||
@ -357,380 +745,6 @@ class InvenTreeSetting(models.Model):
|
|||||||
verbose_name = "InvenTree Setting"
|
verbose_name = "InvenTree Setting"
|
||||||
verbose_name_plural = "InvenTree Settings"
|
verbose_name_plural = "InvenTree Settings"
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_name(cls, key):
|
|
||||||
"""
|
|
||||||
Return the name of a particular setting.
|
|
||||||
|
|
||||||
If it does not exist, return an empty string.
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
if key in cls.GLOBAL_SETTINGS:
|
|
||||||
setting = cls.GLOBAL_SETTINGS[key]
|
|
||||||
return setting.get('name', '')
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_description(cls, key):
|
|
||||||
"""
|
|
||||||
Return the description for a particular setting.
|
|
||||||
|
|
||||||
If it does not exist, return an empty string.
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
if key in cls.GLOBAL_SETTINGS:
|
|
||||||
setting = cls.GLOBAL_SETTINGS[key]
|
|
||||||
return setting.get('description', '')
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_units(cls, key):
|
|
||||||
"""
|
|
||||||
Return the units for a particular setting.
|
|
||||||
|
|
||||||
If it does not exist, return an empty string.
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
if key in cls.GLOBAL_SETTINGS:
|
|
||||||
setting = cls.GLOBAL_SETTINGS[key]
|
|
||||||
return setting.get('units', '')
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_validator(cls, key):
|
|
||||||
"""
|
|
||||||
Return the validator for a particular setting.
|
|
||||||
|
|
||||||
If it does not exist, return None
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
if key in cls.GLOBAL_SETTINGS:
|
|
||||||
setting = cls.GLOBAL_SETTINGS[key]
|
|
||||||
return setting.get('validator', None)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_default(cls, key):
|
|
||||||
"""
|
|
||||||
Return the default value for a particular setting.
|
|
||||||
|
|
||||||
If it does not exist, return an empty string
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
if key in cls.GLOBAL_SETTINGS:
|
|
||||||
setting = cls.GLOBAL_SETTINGS[key]
|
|
||||||
return setting.get('default', '')
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_choices(cls, key):
|
|
||||||
"""
|
|
||||||
Return the validator choices available for a particular setting.
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
if key in cls.GLOBAL_SETTINGS:
|
|
||||||
setting = cls.GLOBAL_SETTINGS[key]
|
|
||||||
choices = setting.get('choices', None)
|
|
||||||
else:
|
|
||||||
choices = None
|
|
||||||
|
|
||||||
"""
|
|
||||||
TODO:
|
|
||||||
if type(choices) is function:
|
|
||||||
# Evaluate the function (we expect it will return a list of tuples...)
|
|
||||||
return choices()
|
|
||||||
"""
|
|
||||||
|
|
||||||
return choices
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_object(cls, key):
|
|
||||||
"""
|
|
||||||
Return an InvenTreeSetting object matching the given key.
|
|
||||||
|
|
||||||
- Key is case-insensitive
|
|
||||||
- Returns None if no match is made
|
|
||||||
"""
|
|
||||||
|
|
||||||
key = str(key).strip().upper()
|
|
||||||
|
|
||||||
try:
|
|
||||||
setting = InvenTreeSetting.objects.filter(key__iexact=key).first()
|
|
||||||
except (ValueError, InvenTreeSetting.DoesNotExist):
|
|
||||||
setting = None
|
|
||||||
except (IntegrityError, OperationalError):
|
|
||||||
setting = None
|
|
||||||
|
|
||||||
# Setting does not exist! (Try to create it)
|
|
||||||
if not setting:
|
|
||||||
|
|
||||||
setting = InvenTreeSetting(key=key, value=InvenTreeSetting.get_setting_default(key))
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Wrap this statement in "atomic", so it can be rolled back if it fails
|
|
||||||
with transaction.atomic():
|
|
||||||
setting.save()
|
|
||||||
except (IntegrityError, OperationalError):
|
|
||||||
# It might be the case that the database isn't created yet
|
|
||||||
pass
|
|
||||||
|
|
||||||
return setting
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting_pk(cls, key):
|
|
||||||
"""
|
|
||||||
Return the primary-key value for a given setting.
|
|
||||||
|
|
||||||
If the setting does not exist, return None
|
|
||||||
"""
|
|
||||||
|
|
||||||
setting = InvenTreeSetting.get_setting_object(cls)
|
|
||||||
|
|
||||||
if setting:
|
|
||||||
return setting.pk
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def get_setting(cls, key, backup_value=None):
|
|
||||||
"""
|
|
||||||
Get the value of a particular setting.
|
|
||||||
If it does not exist, return the backup value (default = None)
|
|
||||||
"""
|
|
||||||
|
|
||||||
# If no backup value is specified, atttempt to retrieve a "default" value
|
|
||||||
if backup_value is None:
|
|
||||||
backup_value = cls.get_setting_default(key)
|
|
||||||
|
|
||||||
setting = InvenTreeSetting.get_setting_object(key)
|
|
||||||
|
|
||||||
if setting:
|
|
||||||
value = setting.value
|
|
||||||
|
|
||||||
# If the particular setting is defined as a boolean, cast the value to a boolean
|
|
||||||
if setting.is_bool():
|
|
||||||
value = InvenTree.helpers.str2bool(value)
|
|
||||||
|
|
||||||
if setting.is_int():
|
|
||||||
try:
|
|
||||||
value = int(value)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
value = backup_value
|
|
||||||
|
|
||||||
else:
|
|
||||||
value = backup_value
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def set_setting(cls, key, value, user, create=True):
|
|
||||||
"""
|
|
||||||
Set the value of a particular setting.
|
|
||||||
If it does not exist, option to create it.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
key: settings key
|
|
||||||
value: New value
|
|
||||||
user: User object (must be staff member to update a core setting)
|
|
||||||
create: If True, create a new setting if the specified key does not exist.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if user is not None and not user.is_staff:
|
|
||||||
return
|
|
||||||
|
|
||||||
try:
|
|
||||||
setting = InvenTreeSetting.objects.get(key__iexact=key)
|
|
||||||
except InvenTreeSetting.DoesNotExist:
|
|
||||||
|
|
||||||
if create:
|
|
||||||
setting = InvenTreeSetting(key=key)
|
|
||||||
else:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Enforce standard boolean representation
|
|
||||||
if setting.is_bool():
|
|
||||||
value = InvenTree.helpers.str2bool(value)
|
|
||||||
|
|
||||||
setting.value = str(value)
|
|
||||||
setting.save()
|
|
||||||
|
|
||||||
key = models.CharField(max_length=50, blank=False, unique=True, help_text=_('Settings key (must be unique - case insensitive'))
|
|
||||||
|
|
||||||
value = models.CharField(max_length=200, blank=True, unique=False, help_text=_('Settings value'))
|
|
||||||
|
|
||||||
@property
|
|
||||||
def name(self):
|
|
||||||
return InvenTreeSetting.get_setting_name(self.key)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def default_value(self):
|
|
||||||
return InvenTreeSetting.get_setting_default(self.key)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def description(self):
|
|
||||||
return InvenTreeSetting.get_setting_description(self.key)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def units(self):
|
|
||||||
return InvenTreeSetting.get_setting_units(self.key)
|
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
"""
|
|
||||||
If a validator (or multiple validators) are defined for a particular setting key,
|
|
||||||
run them against the 'value' field.
|
|
||||||
"""
|
|
||||||
|
|
||||||
super().clean()
|
|
||||||
|
|
||||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
|
||||||
|
|
||||||
if self.is_bool():
|
|
||||||
self.value = InvenTree.helpers.str2bool(self.value)
|
|
||||||
|
|
||||||
if self.is_int():
|
|
||||||
try:
|
|
||||||
self.value = int(self.value)
|
|
||||||
except (ValueError):
|
|
||||||
raise ValidationError(_('Must be an integer value'))
|
|
||||||
|
|
||||||
if validator is not None:
|
|
||||||
self.run_validator(validator)
|
|
||||||
|
|
||||||
def run_validator(self, validator):
|
|
||||||
"""
|
|
||||||
Run a validator against the 'value' field for this InvenTreeSetting object.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if validator is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
value = self.value
|
|
||||||
|
|
||||||
# Boolean validator
|
|
||||||
if self.is_bool():
|
|
||||||
# Value must "look like" a boolean value
|
|
||||||
if InvenTree.helpers.is_bool(value):
|
|
||||||
# Coerce into either "True" or "False"
|
|
||||||
value = InvenTree.helpers.str2bool(value)
|
|
||||||
else:
|
|
||||||
raise ValidationError({
|
|
||||||
'value': _('Value must be a boolean value')
|
|
||||||
})
|
|
||||||
|
|
||||||
# Integer validator
|
|
||||||
if self.is_int():
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Coerce into an integer value
|
|
||||||
value = int(value)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
raise ValidationError({
|
|
||||||
'value': _('Value must be an integer value'),
|
|
||||||
})
|
|
||||||
|
|
||||||
# If a list of validators is supplied, iterate through each one
|
|
||||||
if type(validator) in [list, tuple]:
|
|
||||||
for v in validator:
|
|
||||||
self.run_validator(v)
|
|
||||||
|
|
||||||
if callable(validator):
|
|
||||||
# We can accept function validators with a single argument
|
|
||||||
validator(self.value)
|
|
||||||
|
|
||||||
def validate_unique(self, exclude=None):
|
|
||||||
""" Ensure that the key:value pair is unique.
|
|
||||||
In addition to the base validators, this ensures that the 'key'
|
|
||||||
is unique, using a case-insensitive comparison.
|
|
||||||
"""
|
|
||||||
|
|
||||||
super().validate_unique(exclude)
|
|
||||||
|
|
||||||
try:
|
|
||||||
setting = InvenTreeSetting.objects.exclude(id=self.id).filter(key__iexact=self.key)
|
|
||||||
if setting.exists():
|
|
||||||
raise ValidationError({'key': _('Key string must be unique')})
|
|
||||||
except InvenTreeSetting.DoesNotExist:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def choices(self):
|
|
||||||
"""
|
|
||||||
Return the available choices for this setting (or None if no choices are defined)
|
|
||||||
"""
|
|
||||||
|
|
||||||
return InvenTreeSetting.get_setting_choices(self.key)
|
|
||||||
|
|
||||||
def is_bool(self):
|
|
||||||
"""
|
|
||||||
Check if this setting is required to be a boolean value
|
|
||||||
"""
|
|
||||||
|
|
||||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
|
||||||
|
|
||||||
if validator == bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if type(validator) in [list, tuple]:
|
|
||||||
for v in validator:
|
|
||||||
if v == bool:
|
|
||||||
return True
|
|
||||||
|
|
||||||
def as_bool(self):
|
|
||||||
"""
|
|
||||||
Return the value of this setting converted to a boolean value.
|
|
||||||
|
|
||||||
Warning: Only use on values where is_bool evaluates to true!
|
|
||||||
"""
|
|
||||||
|
|
||||||
return InvenTree.helpers.str2bool(self.value)
|
|
||||||
|
|
||||||
def is_int(self):
|
|
||||||
"""
|
|
||||||
Check if the setting is required to be an integer value:
|
|
||||||
"""
|
|
||||||
|
|
||||||
validator = InvenTreeSetting.get_setting_validator(self.key)
|
|
||||||
|
|
||||||
if validator == int:
|
|
||||||
return True
|
|
||||||
|
|
||||||
if type(validator) in [list, tuple]:
|
|
||||||
for v in validator:
|
|
||||||
if v == int:
|
|
||||||
return True
|
|
||||||
|
|
||||||
return False
|
|
||||||
|
|
||||||
def as_int(self):
|
|
||||||
"""
|
|
||||||
Return the value of this setting converted to a boolean value.
|
|
||||||
|
|
||||||
If an error occurs, return the default value
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
value = int(self.value)
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
value = self.default_value()
|
|
||||||
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class PriceBreak(models.Model):
|
class PriceBreak(models.Model):
|
||||||
"""
|
"""
|
||||||
|
Loading…
x
Reference in New Issue
Block a user