mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Model introspection
- Find the class registered to the model (or log an error) - Pass the api_url through to the frontend
This commit is contained in:
parent
e112d555d4
commit
a81ea01e8e
@ -17,15 +17,16 @@ import base64
|
|||||||
from secrets import compare_digest
|
from secrets import compare_digest
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.db.utils import IntegrityError, OperationalError
|
||||||
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User, Group
|
from django.contrib.auth.models import User, Group
|
||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db.utils import IntegrityError, OperationalError
|
from django.contrib.humanize.templatetags.humanize import naturaltime
|
||||||
from django.conf import settings
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
from django.contrib.humanize.templatetags.humanize import naturaltime
|
|
||||||
|
|
||||||
from djmoney.settings import CURRENCY_CHOICES
|
from djmoney.settings import CURRENCY_CHOICES
|
||||||
from djmoney.contrib.exchange.models import convert_money
|
from djmoney.contrib.exchange.models import convert_money
|
||||||
@ -587,6 +588,58 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
|
|
||||||
return setting.get('model', None)
|
return setting.get('model', None)
|
||||||
|
|
||||||
|
def model_class(self):
|
||||||
|
"""
|
||||||
|
Return the model class associated with this setting, if (and only if):
|
||||||
|
|
||||||
|
- It has a defined 'model' parameter
|
||||||
|
- The 'model' parameter is of the form app.model
|
||||||
|
- The 'model' parameter has matches a known app model
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_name = self.model_name()
|
||||||
|
|
||||||
|
if not model_name:
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
(app, mdl) = model_name.strip().split('.')
|
||||||
|
except ValueError:
|
||||||
|
logger.error(f"Invalid 'model' parameter for setting {self.key} : '{model_name}'")
|
||||||
|
return None
|
||||||
|
|
||||||
|
app_models = apps.all_models.get(app, None)
|
||||||
|
|
||||||
|
if app_models is None:
|
||||||
|
logger.error(f"Error retrieving model class '{model_name}' for setting '{self.key}' - no app named '{app}'")
|
||||||
|
return None
|
||||||
|
|
||||||
|
model = app_models.get(mdl, None)
|
||||||
|
|
||||||
|
if model is None:
|
||||||
|
logger.error(f"Error retrieving model class '{model_name}' for setting '{self.key}' - no model named '{mdl}'")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# Looks like we have found a model!
|
||||||
|
return model
|
||||||
|
|
||||||
|
def api_url(self):
|
||||||
|
"""
|
||||||
|
Return the API url associated with the linked model,
|
||||||
|
if provided, and valid!
|
||||||
|
"""
|
||||||
|
|
||||||
|
model_class = self.model_class()
|
||||||
|
|
||||||
|
if model_class:
|
||||||
|
# If a valid class has been found, see if it has registered an API URL
|
||||||
|
try:
|
||||||
|
return model_class.get_api_url()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def is_bool(self):
|
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
|
||||||
@ -617,7 +670,7 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
return 'integer'
|
return 'integer'
|
||||||
|
|
||||||
elif self.is_model():
|
elif self.is_model():
|
||||||
return 'model'
|
return 'related field'
|
||||||
|
|
||||||
else:
|
else:
|
||||||
return 'string'
|
return 'string'
|
||||||
|
@ -30,6 +30,8 @@ class SettingsSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
model_name = serializers.CharField(read_only=True)
|
model_name = serializers.CharField(read_only=True)
|
||||||
|
|
||||||
|
api_url = 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
|
||||||
@ -78,6 +80,7 @@ class GlobalSettingsSerializer(SettingsSerializer):
|
|||||||
'type',
|
'type',
|
||||||
'choices',
|
'choices',
|
||||||
'model_name',
|
'model_name',
|
||||||
|
'api_url',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -100,6 +103,7 @@ class UserSettingsSerializer(SettingsSerializer):
|
|||||||
'type',
|
'type',
|
||||||
'choices',
|
'choices',
|
||||||
'model_name',
|
'model_name',
|
||||||
|
'api_url',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -129,6 +133,7 @@ class GenericReferencedSettingSerializer(SettingsSerializer):
|
|||||||
'type',
|
'type',
|
||||||
'choices',
|
'choices',
|
||||||
'model_name',
|
'model_name',
|
||||||
|
'api_url',
|
||||||
]
|
]
|
||||||
|
|
||||||
# set Meta class
|
# set Meta class
|
||||||
|
@ -137,7 +137,7 @@ class PluginSetting(common.models.BaseInvenTreeSetting):
|
|||||||
|
|
||||||
if 'settings' not in kwargs:
|
if 'settings' not in kwargs:
|
||||||
|
|
||||||
plugin = kwargs.pop('plugin')
|
plugin = kwargs.pop('plugin', None)
|
||||||
|
|
||||||
if plugin:
|
if plugin:
|
||||||
|
|
||||||
|
@ -68,7 +68,12 @@ class SampleIntegrationPlugin(AppMixin, SettingsMixin, UrlsMixin, NavigationMixi
|
|||||||
'SELECT_COMPANY': {
|
'SELECT_COMPANY': {
|
||||||
'name': 'Company',
|
'name': 'Company',
|
||||||
'description': 'Select a company object from the database',
|
'description': 'Select a company object from the database',
|
||||||
'model': 'company.Company',
|
'model': 'company.company',
|
||||||
|
},
|
||||||
|
'SELECT_PART': {
|
||||||
|
'name': 'Part',
|
||||||
|
'description': 'Select a part object from the database',
|
||||||
|
'model': 'part.part',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,9 +22,6 @@
|
|||||||
{{ 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 %}>
|
||||||
|
@ -71,9 +71,24 @@ function editSetting(key, options={}) {
|
|||||||
help_text: response.description,
|
help_text: response.description,
|
||||||
type: response.type,
|
type: response.type,
|
||||||
choices: response.choices,
|
choices: response.choices,
|
||||||
|
value: response.value,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Foreign key lookup available!
|
||||||
|
if (response.type == 'related field') {
|
||||||
|
|
||||||
|
if (response.model_name && response.api_url) {
|
||||||
|
fields.value.type = 'related field';
|
||||||
|
fields.value.model = response.model_name.split('.').at(-1);
|
||||||
|
fields.value.api_url = response.api_url;
|
||||||
|
} else {
|
||||||
|
// Unknown / unsupported model type, default to 'text' field
|
||||||
|
fields.value.type = 'text';
|
||||||
|
console.warn(`Unsupported model type: '${response.model_name}' for setting '${response.key}'`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
constructChangeForm(fields, {
|
constructChangeForm(fields, {
|
||||||
url: url,
|
url: url,
|
||||||
method: 'PATCH',
|
method: 'PATCH',
|
||||||
|
Loading…
Reference in New Issue
Block a user