mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05: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 |         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 |     @classmethod | ||||||
|     def get_setting_definition(cls, key, **kwargs): |     def get_setting_definition(cls, key, **kwargs): | ||||||
|         """ |         """ | ||||||
| @@ -319,11 +332,11 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|             value = setting.value |             value = setting.value | ||||||
|  |  | ||||||
|             # Cast to boolean if necessary |             # Cast to boolean if necessary | ||||||
|             if setting.is_bool(**kwargs): |             if setting.is_bool(): | ||||||
|                 value = InvenTree.helpers.str2bool(value) |                 value = InvenTree.helpers.str2bool(value) | ||||||
|  |  | ||||||
|             # Cast to integer if necessary |             # Cast to integer if necessary | ||||||
|             if setting.is_int(**kwargs): |             if setting.is_int(): | ||||||
|                 try: |                 try: | ||||||
|                     value = int(value) |                     value = int(value) | ||||||
|                 except (ValueError, TypeError): |                 except (ValueError, TypeError): | ||||||
| @@ -390,19 +403,19 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def name(self): |     def name(self): | ||||||
|         return self.__class__.get_setting_name(self.key) |         return self.__class__.get_setting_name(self.key, **self.get_kwargs()) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def default_value(self): |     def default_value(self): | ||||||
|         return self.__class__.get_setting_default(self.key) |         return self.__class__.get_setting_default(self.key, **self.get_kwargs()) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def description(self): |     def description(self): | ||||||
|         return self.__class__.get_setting_description(self.key) |         return self.__class__.get_setting_description(self.key, **self.get_kwargs()) | ||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def units(self): |     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): |     def clean(self, **kwargs): | ||||||
|         """ |         """ | ||||||
| @@ -512,12 +525,12 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|         except self.DoesNotExist: |         except self.DoesNotExist: | ||||||
|             pass |             pass | ||||||
|  |  | ||||||
|     def choices(self, **kwargs): |     def choices(self): | ||||||
|         """ |         """ | ||||||
|         Return the available choices for this setting (or None if no choices are defined) |         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): |     def valid_options(self): | ||||||
|         """ |         """ | ||||||
| @@ -531,14 +544,14 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|  |  | ||||||
|         return [opt[0] for opt in choices] |         return [opt[0] for opt in choices] | ||||||
|  |  | ||||||
|     def is_choice(self, **kwargs): |     def is_choice(self): | ||||||
|         """ |         """ | ||||||
|         Check if this setting is a "choice" field |         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, |         Render this setting as the "display" value of a choice field, | ||||||
|         e.g. if the choices are: |         e.g. if the choices are: | ||||||
| @@ -547,7 +560,7 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|         then display 'A4 paper' |         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: |         if not choices: | ||||||
|             return self.value |             return self.value | ||||||
| @@ -558,12 +571,28 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|  |  | ||||||
|         return self.value |         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 |         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) |         return self.__class__.validator_is_bool(validator) | ||||||
|  |  | ||||||
| @@ -576,17 +605,20 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|  |  | ||||||
|         return InvenTree.helpers.str2bool(self.value) |         return InvenTree.helpers.str2bool(self.value) | ||||||
|  |  | ||||||
|     def setting_type(self, **kwargs): |     def setting_type(self): | ||||||
|         """ |         """ | ||||||
|         Return the field type identifier for this setting object |         Return the field type identifier for this setting object | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|         if self.is_bool(**kwargs): |         if self.is_bool(): | ||||||
|             return 'boolean' |             return 'boolean' | ||||||
|  |  | ||||||
|         elif self.is_int(**kwargs): |         elif self.is_int(): | ||||||
|             return 'integer' |             return 'integer' | ||||||
|  |  | ||||||
|  |         elif self.is_model(): | ||||||
|  |             return 'model' | ||||||
|  |  | ||||||
|         else: |         else: | ||||||
|             return 'string' |             return 'string' | ||||||
|  |  | ||||||
| @@ -603,12 +635,12 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|  |  | ||||||
|         return False |         return False | ||||||
|  |  | ||||||
|     def is_int(self, **kwargs): |     def is_int(self,): | ||||||
|         """ |         """ | ||||||
|         Check if the setting is required to be an integer value: |         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) |         return self.__class__.validator_is_int(validator) | ||||||
|  |  | ||||||
| @@ -651,88 +683,7 @@ class BaseInvenTreeSetting(models.Model): | |||||||
|  |  | ||||||
|     @property |     @property | ||||||
|     def protected(self): |     def protected(self): | ||||||
|         return self.__class__.is_protected(self.key) |         return self.__class__.is_protected(self.key, **self.get_kwargs()) | ||||||
|  |  | ||||||
|  |  | ||||||
| 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()) |  | ||||||
|  |  | ||||||
|  |  | ||||||
| def settings_group_options(): | def settings_group_options(): | ||||||
| @@ -1558,6 +1509,16 @@ class InvenTreeUserSetting(BaseInvenTreeSetting): | |||||||
|  |  | ||||||
|         return self.__class__.get_setting(self.key, user=self.user) |         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): | class PriceBreak(models.Model): | ||||||
|     """ |     """ | ||||||
|   | |||||||
| @@ -28,6 +28,8 @@ class SettingsSerializer(InvenTreeModelSerializer): | |||||||
|  |  | ||||||
|     choices = serializers.SerializerMethodField() |     choices = serializers.SerializerMethodField() | ||||||
|  |  | ||||||
|  |     model_name = serializers.CharField(read_only=True) | ||||||
|  |  | ||||||
|     def get_choices(self, obj): |     def get_choices(self, obj): | ||||||
|         """ |         """ | ||||||
|         Returns the choices available for a given item |         Returns the choices available for a given item | ||||||
| @@ -75,6 +77,7 @@ class GlobalSettingsSerializer(SettingsSerializer): | |||||||
|             'description', |             'description', | ||||||
|             'type', |             'type', | ||||||
|             'choices', |             'choices', | ||||||
|  |             'model_name', | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -96,6 +99,7 @@ class UserSettingsSerializer(SettingsSerializer): | |||||||
|             'user', |             'user', | ||||||
|             'type', |             'type', | ||||||
|             'choices', |             'choices', | ||||||
|  |             'model_name', | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -124,6 +128,7 @@ class GenericReferencedSettingSerializer(SettingsSerializer): | |||||||
|                 'description', |                 'description', | ||||||
|                 'type', |                 'type', | ||||||
|                 'choices', |                 'choices', | ||||||
|  |                 'model_name', | ||||||
|             ] |             ] | ||||||
|  |  | ||||||
|         # set Meta class |         # set Meta class | ||||||
|   | |||||||
| @@ -102,7 +102,7 @@ class PluginConfig(models.Model): | |||||||
|         return ret |         return ret | ||||||
|  |  | ||||||
|  |  | ||||||
| class PluginSetting(common.models.GenericReferencedSettingClass, common.models.BaseInvenTreeSetting): | class PluginSetting(common.models.BaseInvenTreeSetting): | ||||||
|     """ |     """ | ||||||
|     This model represents settings for individual plugins |     This model represents settings for individual plugins | ||||||
|     """ |     """ | ||||||
| @@ -112,7 +112,13 @@ class PluginSetting(common.models.GenericReferencedSettingClass, common.models.B | |||||||
|             ('plugin', 'key'), |             ('plugin', 'key'), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|     REFERENCE_NAME = 'plugin' |     plugin = models.ForeignKey( | ||||||
|  |         PluginConfig, | ||||||
|  |         related_name='settings', | ||||||
|  |         null=False, | ||||||
|  |         verbose_name=_('Plugin'), | ||||||
|  |         on_delete=models.CASCADE, | ||||||
|  |     ) | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def get_setting_definition(cls, key, **kwargs): |     def get_setting_definition(cls, key, **kwargs): | ||||||
| @@ -131,7 +137,7 @@ class PluginSetting(common.models.GenericReferencedSettingClass, common.models.B | |||||||
|  |  | ||||||
|         if 'settings' not in kwargs: |         if 'settings' not in kwargs: | ||||||
|  |  | ||||||
|             plugin = kwargs.pop('plugin', None) |             plugin = kwargs.pop('plugin') | ||||||
|  |  | ||||||
|             if plugin: |             if plugin: | ||||||
|  |  | ||||||
| @@ -142,16 +148,18 @@ class PluginSetting(common.models.GenericReferencedSettingClass, common.models.B | |||||||
|  |  | ||||||
|         return super().get_setting_definition(key, **kwargs) |         return super().get_setting_definition(key, **kwargs) | ||||||
|  |  | ||||||
|     plugin = models.ForeignKey( |     def get_kwargs(self): | ||||||
|         PluginConfig, |         """ | ||||||
|         related_name='settings', |         Explicit kwargs required to uniquely identify a particular setting object, | ||||||
|         null=False, |         in addition to the 'key' parameter | ||||||
|         verbose_name=_('Plugin'), |         """ | ||||||
|         on_delete=models.CASCADE, |  | ||||||
|     ) |         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 |     This model represents notification settings for a user | ||||||
|     """ |     """ | ||||||
| @@ -161,8 +169,6 @@ class NotificationUserSetting(common.models.GenericReferencedSettingClass, commo | |||||||
|             ('method', 'user', 'key'), |             ('method', 'user', 'key'), | ||||||
|         ] |         ] | ||||||
|  |  | ||||||
|     REFERENCE_NAME = 'method' |  | ||||||
|  |  | ||||||
|     @classmethod |     @classmethod | ||||||
|     def get_setting_definition(cls, key, **kwargs): |     def get_setting_definition(cls, key, **kwargs): | ||||||
|         from common.notifications import storage |         from common.notifications import storage | ||||||
| @@ -171,6 +177,17 @@ class NotificationUserSetting(common.models.GenericReferencedSettingClass, commo | |||||||
|  |  | ||||||
|         return super().get_setting_definition(key, **kwargs) |         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( |     method = models.CharField( | ||||||
|         max_length=255, |         max_length=255, | ||||||
|         verbose_name=_('Method'), |         verbose_name=_('Method'), | ||||||
|   | |||||||
| @@ -65,6 +65,11 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi | |||||||
|             ], |             ], | ||||||
|             'default': 'A', |             'default': 'A', | ||||||
|         }, |         }, | ||||||
|  |         'SELECT_COMPANY': { | ||||||
|  |             'name': 'Company', | ||||||
|  |             'description': 'Select a company object from the database', | ||||||
|  |             'model': 'company.Company', | ||||||
|  |         }, | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     NAVIGATION = [ |     NAVIGATION = [ | ||||||
|   | |||||||
| @@ -22,6 +22,9 @@ | |||||||
|         {{ setting.description }} |         {{ setting.description }} | ||||||
|     </td> |     </td> | ||||||
|     <td> |     <td> | ||||||
|  |         {% if setting.model_name %} | ||||||
|  |         <b>Model name: {{ setting.model_name }}</b> | ||||||
|  |         {% endif %} | ||||||
|         {% if setting.is_bool %} |         {% if setting.is_bool %} | ||||||
|         <div class='form-check form-switch'> |         <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 %}> |             <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