mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	Simplify the various settings objects, to improve retrieval of 'parameters' from the base class
- Remove the GenericReferencedSettingsClass mixin - Each subclass defines a very simple get_kwargs() method - Now, at object level *and* class level we can perform lookup of settings and actually get proper data back - Adds "model" option to setting (precursor of things to come)
This commit is contained in:
		| @@ -136,6 +136,19 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|         return settings | ||||
|  | ||||
|     def get_kwargs(self): | ||||
|         """ | ||||
|         Construct kwargs for doing class-based settings lookup, | ||||
|         depending on *which* class we are. | ||||
|  | ||||
|         This is necessary to abtract the settings object | ||||
|         from the implementing class (e.g plugins) | ||||
|          | ||||
|         Subclasses should override this function to ensure the kwargs are correctly set. | ||||
|         """ | ||||
|  | ||||
|         return {} | ||||
|  | ||||
|     @classmethod | ||||
|     def get_setting_definition(cls, key, **kwargs): | ||||
|         """ | ||||
| @@ -319,11 +332,11 @@ class BaseInvenTreeSetting(models.Model): | ||||
|             value = setting.value | ||||
|  | ||||
|             # Cast to boolean if necessary | ||||
|             if setting.is_bool(**kwargs): | ||||
|             if setting.is_bool(): | ||||
|                 value = InvenTree.helpers.str2bool(value) | ||||
|  | ||||
|             # Cast to integer if necessary | ||||
|             if setting.is_int(**kwargs): | ||||
|             if setting.is_int(): | ||||
|                 try: | ||||
|                     value = int(value) | ||||
|                 except (ValueError, TypeError): | ||||
| @@ -390,19 +403,19 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|     @property | ||||
|     def name(self): | ||||
|         return self.__class__.get_setting_name(self.key) | ||||
|         return self.__class__.get_setting_name(self.key, **self.get_kwargs()) | ||||
|  | ||||
|     @property | ||||
|     def default_value(self): | ||||
|         return self.__class__.get_setting_default(self.key) | ||||
|         return self.__class__.get_setting_default(self.key, **self.get_kwargs()) | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
|         return self.__class__.get_setting_description(self.key) | ||||
|         return self.__class__.get_setting_description(self.key, **self.get_kwargs()) | ||||
|  | ||||
|     @property | ||||
|     def units(self): | ||||
|         return self.__class__.get_setting_units(self.key) | ||||
|         return self.__class__.get_setting_units(self.key, **self.get_kwargs()) | ||||
|  | ||||
|     def clean(self, **kwargs): | ||||
|         """ | ||||
| @@ -512,12 +525,12 @@ class BaseInvenTreeSetting(models.Model): | ||||
|         except self.DoesNotExist: | ||||
|             pass | ||||
|  | ||||
|     def choices(self, **kwargs): | ||||
|     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, **kwargs) | ||||
|         return self.__class__.get_setting_choices(self.key, **self.get_kwargs()) | ||||
|  | ||||
|     def valid_options(self): | ||||
|         """ | ||||
| @@ -531,14 +544,14 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|         return [opt[0] for opt in choices] | ||||
|  | ||||
|     def is_choice(self, **kwargs): | ||||
|     def is_choice(self): | ||||
|         """ | ||||
|         Check if this setting is a "choice" field | ||||
|         """ | ||||
|  | ||||
|         return self.__class__.get_setting_choices(self.key, **kwargs) is not None | ||||
|         return self.__class__.get_setting_choices(self.key, **self.get_kwargs()) is not None | ||||
|  | ||||
|     def as_choice(self, **kwargs): | ||||
|     def as_choice(self): | ||||
|         """ | ||||
|         Render this setting as the "display" value of a choice field, | ||||
|         e.g. if the choices are: | ||||
| @@ -547,7 +560,7 @@ class BaseInvenTreeSetting(models.Model): | ||||
|         then display 'A4 paper' | ||||
|         """ | ||||
|  | ||||
|         choices = self.get_setting_choices(self.key, **kwargs) | ||||
|         choices = self.get_setting_choices(self.key, **self.get_kwargs()) | ||||
|  | ||||
|         if not choices: | ||||
|             return self.value | ||||
| @@ -558,12 +571,28 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|         return self.value | ||||
|  | ||||
|     def is_bool(self, **kwargs): | ||||
|     def is_model(self): | ||||
|         """ | ||||
|         Check if this setting references a model instance in the database | ||||
|         """ | ||||
|  | ||||
|         return self.model_name() is not None | ||||
|  | ||||
|     def model_name(self): | ||||
|         """ | ||||
|         Return the model name associated with this setting | ||||
|         """ | ||||
|  | ||||
|         setting = self.get_setting_definition(self.key, **self.get_kwargs()) | ||||
|  | ||||
|         return setting.get('model', None) | ||||
|  | ||||
|     def is_bool(self): | ||||
|         """ | ||||
|         Check if this setting is required to be a boolean value | ||||
|         """ | ||||
|  | ||||
|         validator = self.__class__.get_setting_validator(self.key, **kwargs) | ||||
|         validator = self.__class__.get_setting_validator(self.key, **self.get_kwargs()) | ||||
|  | ||||
|         return self.__class__.validator_is_bool(validator) | ||||
|  | ||||
| @@ -576,17 +605,20 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|         return InvenTree.helpers.str2bool(self.value) | ||||
|  | ||||
|     def setting_type(self, **kwargs): | ||||
|     def setting_type(self): | ||||
|         """ | ||||
|         Return the field type identifier for this setting object | ||||
|         """ | ||||
|  | ||||
|         if self.is_bool(**kwargs): | ||||
|         if self.is_bool(): | ||||
|             return 'boolean' | ||||
|  | ||||
|         elif self.is_int(**kwargs): | ||||
|         elif self.is_int(): | ||||
|             return 'integer' | ||||
|  | ||||
|         elif self.is_model(): | ||||
|             return 'model' | ||||
|  | ||||
|         else: | ||||
|             return 'string' | ||||
|  | ||||
| @@ -603,12 +635,12 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|         return False | ||||
|  | ||||
|     def is_int(self, **kwargs): | ||||
|     def is_int(self,): | ||||
|         """ | ||||
|         Check if the setting is required to be an integer value: | ||||
|         """ | ||||
|  | ||||
|         validator = self.__class__.get_setting_validator(self.key, **kwargs) | ||||
|         validator = self.__class__.get_setting_validator(self.key, **self.get_kwargs()) | ||||
|  | ||||
|         return self.__class__.validator_is_int(validator) | ||||
|  | ||||
| @@ -651,88 +683,7 @@ class BaseInvenTreeSetting(models.Model): | ||||
|  | ||||
|     @property | ||||
|     def protected(self): | ||||
|         return self.__class__.is_protected(self.key) | ||||
|  | ||||
|  | ||||
| class GenericReferencedSettingClass: | ||||
|     """ | ||||
|     This mixin can be used to add reference keys to static properties | ||||
|  | ||||
|     Sample: | ||||
|     ```python | ||||
|     class SampleSetting(GenericReferencedSettingClass, common.models.BaseInvenTreeSetting): | ||||
|         class Meta: | ||||
|             unique_together = [ | ||||
|                 ('sample', 'key'), | ||||
|             ] | ||||
|  | ||||
|         REFERENCE_NAME = 'sample' | ||||
|  | ||||
|         @classmethod | ||||
|         def get_setting_definition(cls, key, **kwargs): | ||||
|             # mysampledict contains the dict with all settings for this SettingClass - this could also be a dynamic lookup | ||||
|  | ||||
|             kwargs['settings'] = mysampledict | ||||
|             return super().get_setting_definition(key, **kwargs) | ||||
|  | ||||
|         sample = models.charKey(  # the name for this field is the additonal key and must be set in the Meta class an REFERENCE_NAME | ||||
|             max_length=256, | ||||
|             verbose_name=_('sample') | ||||
|         ) | ||||
|     ``` | ||||
|     """ | ||||
|  | ||||
|     REFERENCE_NAME = None | ||||
|  | ||||
|     def _get_reference(self): | ||||
|         """ | ||||
|         Returns dict that can be used as an argument for kwargs calls. | ||||
|         Helps to make overriden calls generic for simple reuse. | ||||
|  | ||||
|         Usage: | ||||
|         ```python | ||||
|         some_random_function(argument0, kwarg1=value1, **self._get_reference()) | ||||
|         ``` | ||||
|         """ | ||||
|         return { | ||||
|             self.REFERENCE_NAME: getattr(self, self.REFERENCE_NAME) | ||||
|         } | ||||
|  | ||||
|     """ | ||||
|     We override the following class methods, | ||||
|     so that we can pass the modified key instance as an additional argument | ||||
|     """ | ||||
|  | ||||
|     def clean(self, **kwargs): | ||||
|  | ||||
|         kwargs[self.REFERENCE_NAME] = getattr(self, self.REFERENCE_NAME) | ||||
|  | ||||
|         super().clean(**kwargs) | ||||
|  | ||||
|     def is_bool(self, **kwargs): | ||||
|  | ||||
|         kwargs[self.REFERENCE_NAME] = getattr(self, self.REFERENCE_NAME) | ||||
|  | ||||
|         return super().is_bool(**kwargs) | ||||
|  | ||||
|     @property | ||||
|     def name(self): | ||||
|         return self.__class__.get_setting_name(self.key, **self._get_reference()) | ||||
|  | ||||
|     @property | ||||
|     def default_value(self): | ||||
|         return self.__class__.get_setting_default(self.key, **self._get_reference()) | ||||
|  | ||||
|     @property | ||||
|     def description(self): | ||||
|         return self.__class__.get_setting_description(self.key, **self._get_reference()) | ||||
|  | ||||
|     @property | ||||
|     def units(self): | ||||
|         return self.__class__.get_setting_units(self.key, **self._get_reference()) | ||||
|  | ||||
|     def choices(self): | ||||
|         return self.__class__.get_setting_choices(self.key, **self._get_reference()) | ||||
|         return self.__class__.is_protected(self.key, **self.get_kwargs()) | ||||
|  | ||||
|  | ||||
| def settings_group_options(): | ||||
| @@ -1558,6 +1509,16 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): | ||||
|  | ||||
|         return self.__class__.get_setting(self.key, user=self.user) | ||||
|  | ||||
|     def get_kwargs(self): | ||||
|         """ | ||||
|         Explicit kwargs required to uniquely identify a particular setting object, | ||||
|         in addition to the 'key' parameter | ||||
|         """ | ||||
|  | ||||
|         return { | ||||
|             'user': self.user, | ||||
|         } | ||||
|  | ||||
|  | ||||
| class PriceBreak(models.Model): | ||||
|     """ | ||||
|   | ||||
| @@ -28,6 +28,8 @@ class SettingsSerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|     choices = serializers.SerializerMethodField() | ||||
|  | ||||
|     model_name = serializers.CharField(read_only=True) | ||||
|  | ||||
|     def get_choices(self, obj): | ||||
|         """ | ||||
|         Returns the choices available for a given item | ||||
| @@ -75,6 +77,7 @@ class GlobalSettingsSerializer(SettingsSerializer): | ||||
|             'description', | ||||
|             'type', | ||||
|             'choices', | ||||
|             'model_name', | ||||
|         ] | ||||
|  | ||||
|  | ||||
| @@ -96,6 +99,7 @@ class UserSettingsSerializer(SettingsSerializer): | ||||
|             'user', | ||||
|             'type', | ||||
|             'choices', | ||||
|             'model_name', | ||||
|         ] | ||||
|  | ||||
|  | ||||
| @@ -124,6 +128,7 @@ class GenericReferencedSettingSerializer(SettingsSerializer): | ||||
|                 'description', | ||||
|                 'type', | ||||
|                 'choices', | ||||
|                 'model_name', | ||||
|             ] | ||||
|  | ||||
|         # set Meta class | ||||
|   | ||||
| @@ -102,7 +102,7 @@ class PluginConfig(models.Model): | ||||
|         return ret | ||||
|  | ||||
|  | ||||
| class PluginSetting(common.models.GenericReferencedSettingClass, common.models.BaseInvenTreeSetting): | ||||
| class PluginSetting(common.models.BaseInvenTreeSetting): | ||||
|     """ | ||||
|     This model represents settings for individual plugins | ||||
|     """ | ||||
| @@ -112,7 +112,13 @@ class PluginSetting(common.models.GenericReferencedSettingClass, common.models.B | ||||
|             ('plugin', 'key'), | ||||
|         ] | ||||
|  | ||||
|     REFERENCE_NAME = 'plugin' | ||||
|     plugin = models.ForeignKey( | ||||
|         PluginConfig, | ||||
|         related_name='settings', | ||||
|         null=False, | ||||
|         verbose_name=_('Plugin'), | ||||
|         on_delete=models.CASCADE, | ||||
|     ) | ||||
|  | ||||
|     @classmethod | ||||
|     def get_setting_definition(cls, key, **kwargs): | ||||
| @@ -131,7 +137,7 @@ class PluginSetting(common.models.GenericReferencedSettingClass, common.models.B | ||||
|  | ||||
|         if 'settings' not in kwargs: | ||||
|  | ||||
|             plugin = kwargs.pop('plugin', None) | ||||
|             plugin = kwargs.pop('plugin') | ||||
|  | ||||
|             if plugin: | ||||
|  | ||||
| @@ -142,16 +148,18 @@ class PluginSetting(common.models.GenericReferencedSettingClass, common.models.B | ||||
|  | ||||
|         return super().get_setting_definition(key, **kwargs) | ||||
|  | ||||
|     plugin = models.ForeignKey( | ||||
|         PluginConfig, | ||||
|         related_name='settings', | ||||
|         null=False, | ||||
|         verbose_name=_('Plugin'), | ||||
|         on_delete=models.CASCADE, | ||||
|     ) | ||||
|     def get_kwargs(self): | ||||
|         """ | ||||
|         Explicit kwargs required to uniquely identify a particular setting object, | ||||
|         in addition to the 'key' parameter | ||||
|         """ | ||||
|  | ||||
|         return { | ||||
|             'plugin': self.plugin, | ||||
|         } | ||||
|  | ||||
|  | ||||
| class NotificationUserSetting(common.models.GenericReferencedSettingClass, common.models.BaseInvenTreeSetting): | ||||
| class NotificationUserSetting(common.models.BaseInvenTreeSetting): | ||||
|     """ | ||||
|     This model represents notification settings for a user | ||||
|     """ | ||||
| @@ -161,8 +169,6 @@ class NotificationUserSetting(common.models.GenericReferencedSettingClass, commo | ||||
|             ('method', 'user', 'key'), | ||||
|         ] | ||||
|  | ||||
|     REFERENCE_NAME = 'method' | ||||
|  | ||||
|     @classmethod | ||||
|     def get_setting_definition(cls, key, **kwargs): | ||||
|         from common.notifications import storage | ||||
| @@ -171,6 +177,17 @@ class NotificationUserSetting(common.models.GenericReferencedSettingClass, commo | ||||
|  | ||||
|         return super().get_setting_definition(key, **kwargs) | ||||
|  | ||||
|     def get_kwargs(self): | ||||
|         """ | ||||
|         Explicit kwargs required to uniquely identify a particular setting object, | ||||
|         in addition to the 'key' parameter | ||||
|         """ | ||||
|  | ||||
|         return { | ||||
|             'method': self.method, | ||||
|             'user': self.user, | ||||
|         } | ||||
|  | ||||
|     method = models.CharField( | ||||
|         max_length=255, | ||||
|         verbose_name=_('Method'), | ||||
|   | ||||
| @@ -65,6 +65,11 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi | ||||
|             ], | ||||
|             'default': 'A', | ||||
|         }, | ||||
|         'SELECT_COMPANY': { | ||||
|             'name': 'Company', | ||||
|             'description': 'Select a company object from the database', | ||||
|             'model': 'company.Company', | ||||
|         }, | ||||
|     } | ||||
|  | ||||
|     NAVIGATION = [ | ||||
|   | ||||
| @@ -22,6 +22,9 @@ | ||||
|         {{ setting.description }} | ||||
|     </td> | ||||
|     <td> | ||||
|         {% if setting.model_name %} | ||||
|         <b>Model name: {{ setting.model_name }}</b> | ||||
|         {% endif %} | ||||
|         {% if setting.is_bool %} | ||||
|         <div class='form-check form-switch'> | ||||
|             <input class='form-check-input boolean-setting' fieldname='{{ setting.key.upper }}' pk='{{ setting.pk }}' setting='{{ setting.key.upper }}' id='setting-value-{{ setting.key.upper }}' type='checkbox' {% if setting.as_bool %}checked=''{% endif %} {% if plugin %}plugin='{{ plugin.slug }}'{% endif %}{% if user_setting %}user='{{request.user.id}}'{% endif %}{% if notification_setting %}notification='{{request.user.id}}'{% endif %}> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user