mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-17 01:38:19 +00:00
Adds ContentTypeField
- Handles representation of content type - Provides human-readable options
This commit is contained in:
@@ -7,6 +7,7 @@ from decimal import Decimal
|
|||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@@ -28,7 +29,7 @@ import InvenTree.ready
|
|||||||
from common.currency import currency_code_default, currency_code_mappings
|
from common.currency import currency_code_default, currency_code_mappings
|
||||||
from InvenTree.fields import InvenTreeRestURLField, InvenTreeURLField
|
from InvenTree.fields import InvenTreeRestURLField, InvenTreeURLField
|
||||||
from InvenTree.helpers import str2bool
|
from InvenTree.helpers import str2bool
|
||||||
from InvenTree.helpers_model import getModelChoicesWithMixin
|
from InvenTree.helpers_model import getModelsWithMixin
|
||||||
|
|
||||||
from .setting.storages import StorageBackends
|
from .setting.storages import StorageBackends
|
||||||
|
|
||||||
@@ -719,7 +720,7 @@ class RemoteImageMixin(metaclass=serializers.SerializerMetaclass):
|
|||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
class ContentTypeField(serializers.Field):
|
class ContentTypeField(serializers.ChoiceField):
|
||||||
"""Serializer field which represents a ContentType as 'app_label.model_name'.
|
"""Serializer field which represents a ContentType as 'app_label.model_name'.
|
||||||
|
|
||||||
This field converts a ContentType instance to a string representation in the format 'app_label.model_name' during serialization, and vice versa during deserialization.
|
This field converts a ContentType instance to a string representation in the format 'app_label.model_name' during serialization, and vice versa during deserialization.
|
||||||
@@ -736,13 +737,26 @@ class ContentTypeField(serializers.Field):
|
|||||||
mixin_class: Optional mixin class to restrict valid content types.
|
mixin_class: Optional mixin class to restrict valid content types.
|
||||||
"""
|
"""
|
||||||
self.mixin_class = mixin_class
|
self.mixin_class = mixin_class
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# Override the 'choices' field, to limit to the appropriate models
|
# Override the 'choices' field, to limit to the appropriate models
|
||||||
if self.mixin_class is not None:
|
if self.mixin_class is not None:
|
||||||
self.choices = getModelChoicesWithMixin(
|
models = getModelsWithMixin(self.mixin_class)
|
||||||
self.mixin_class, allow_null=kwargs.get('allow_null', False)
|
|
||||||
)
|
kwargs['choices'] = [
|
||||||
|
(
|
||||||
|
f'{model._meta.app_label}.{model._meta.model_name}',
|
||||||
|
model._meta.verbose_name,
|
||||||
|
)
|
||||||
|
for model in models
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
content_types = ContentType.objects.all()
|
||||||
|
|
||||||
|
kwargs['choices'] = [
|
||||||
|
(f'{ct.app_label}.{ct.model}', str(ct)) for ct in content_types
|
||||||
|
]
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
"""Convert ContentType instance to string representation."""
|
"""Convert ContentType instance to string representation."""
|
||||||
|
|||||||
@@ -2386,11 +2386,6 @@ class ParameterTemplate(
|
|||||||
verbose_name = _('Parameter Template')
|
verbose_name = _('Parameter Template')
|
||||||
verbose_name_plural = _('Parameter Templates')
|
verbose_name_plural = _('Parameter Templates')
|
||||||
|
|
||||||
class ModelChoices(RenderChoices):
|
|
||||||
"""Model choices for parameter templates."""
|
|
||||||
|
|
||||||
choice_fnc = common.validators.parameter_template_model_options
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_api_url() -> str:
|
def get_api_url() -> str:
|
||||||
"""Return the API URL associated with the ParameterTemplate model."""
|
"""Return the API URL associated with the ParameterTemplate model."""
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ from importer.registry import register_importer
|
|||||||
from InvenTree.helpers import get_objectreference
|
from InvenTree.helpers import get_objectreference
|
||||||
from InvenTree.helpers_model import construct_absolute_url
|
from InvenTree.helpers_model import construct_absolute_url
|
||||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||||
|
from InvenTree.models import InvenTreeParameterMixin
|
||||||
from InvenTree.serializers import (
|
from InvenTree.serializers import (
|
||||||
|
ContentTypeField,
|
||||||
FilterableSerializerMixin,
|
FilterableSerializerMixin,
|
||||||
InvenTreeAttachmentSerializerField,
|
InvenTreeAttachmentSerializerField,
|
||||||
InvenTreeImageSerializerField,
|
InvenTreeImageSerializerField,
|
||||||
@@ -721,22 +723,12 @@ class ParameterTemplateSerializer(
|
|||||||
'enabled',
|
'enabled',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Override the model_type field to provide dynamic choices."""
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if len(self.fields['model_type'].choices) == 0:
|
|
||||||
self.fields[
|
|
||||||
'model_type'
|
|
||||||
].choices = common.validators.parameter_template_model_options()
|
|
||||||
|
|
||||||
# Note: The choices are overridden at run-time on class initialization
|
# Note: The choices are overridden at run-time on class initialization
|
||||||
model_type = serializers.ChoiceField(
|
model_type = ContentTypeField(
|
||||||
|
mixin_class=InvenTreeParameterMixin,
|
||||||
label=_('Model Type'),
|
label=_('Model Type'),
|
||||||
default='',
|
default='',
|
||||||
choices=common.validators.parameter_template_model_options(),
|
|
||||||
required=False,
|
required=False,
|
||||||
allow_blank=True,
|
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -767,15 +759,6 @@ class ParameterSerializer(
|
|||||||
|
|
||||||
read_only_fields = ['updated', 'updated_by']
|
read_only_fields = ['updated', 'updated_by']
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
"""Override the model_type field to provide dynamic choices."""
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
if len(self.fields['model_type'].choices) == 0:
|
|
||||||
self.fields[
|
|
||||||
'model_type'
|
|
||||||
].choices = common.validators.parameter_model_options()
|
|
||||||
|
|
||||||
def save(self, **kwargs):
|
def save(self, **kwargs):
|
||||||
"""Save the Parameter instance."""
|
"""Save the Parameter instance."""
|
||||||
from InvenTree.models import InvenTreeParameterMixin
|
from InvenTree.models import InvenTreeParameterMixin
|
||||||
@@ -813,13 +796,11 @@ class ParameterSerializer(
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
# Note: The choices are overridden at run-time on class initialization
|
# Note: The choices are overridden at run-time on class initialization
|
||||||
model_type = serializers.ChoiceField(
|
model_type = ContentTypeField(
|
||||||
|
mixin_class=InvenTreeParameterMixin,
|
||||||
label=_('Model Type'),
|
label=_('Model Type'),
|
||||||
default='',
|
default='',
|
||||||
choices=common.validators.parameter_model_options(),
|
|
||||||
required=False,
|
required=False,
|
||||||
allow_blank=True,
|
|
||||||
allow_null=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
updated_by_detail = enable_filter(
|
updated_by_detail = enable_filter(
|
||||||
|
|||||||
@@ -9,67 +9,6 @@ import common.icons
|
|||||||
from common.settings import get_global_setting
|
from common.settings import get_global_setting
|
||||||
|
|
||||||
|
|
||||||
def parameter_model_types():
|
|
||||||
"""Return a list of valid parameter model choices."""
|
|
||||||
import InvenTree.models
|
|
||||||
|
|
||||||
return list(
|
|
||||||
InvenTree.helpers_model.getModelsWithMixin(
|
|
||||||
InvenTree.models.InvenTreeParameterMixin
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parameter_model_options():
|
|
||||||
"""Return a list of options for models which support parameters."""
|
|
||||||
return [
|
|
||||||
(model.__name__.lower(), model._meta.verbose_name)
|
|
||||||
for model in parameter_model_types()
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def parameter_template_model_options():
|
|
||||||
"""Return a list of options for models which support parameter templates.
|
|
||||||
|
|
||||||
Note: This includes a blank option at the start, since ParameterTemplate.model_type may be blank.
|
|
||||||
"""
|
|
||||||
return [('', _('Any model type')), *parameter_model_options()]
|
|
||||||
|
|
||||||
|
|
||||||
def parameter_model_class_from_label(label: str):
|
|
||||||
"""Return the model class for the given label."""
|
|
||||||
if not label:
|
|
||||||
raise ValidationError(_('No parameter model type provided'))
|
|
||||||
|
|
||||||
for model in parameter_model_types():
|
|
||||||
if model.__name__.lower() == label.lower():
|
|
||||||
return model
|
|
||||||
|
|
||||||
raise ValidationError(_('Invalid parameter model type') + f": '{label}'")
|
|
||||||
|
|
||||||
|
|
||||||
def validate_parameter_model_type(value: str):
|
|
||||||
"""Ensure that the provided parameter model is valid."""
|
|
||||||
model_names = [el[0] for el in parameter_model_options()]
|
|
||||||
if value not in model_names:
|
|
||||||
raise ValidationError('Model type does not support parameters')
|
|
||||||
|
|
||||||
|
|
||||||
def validate_parameter_template_model_type(value: str):
|
|
||||||
"""Ensure that the provided model type is valid.
|
|
||||||
|
|
||||||
Note: A ParameterTemplate may have a blank model type.
|
|
||||||
"""
|
|
||||||
value = str(value).strip()
|
|
||||||
|
|
||||||
if not value:
|
|
||||||
# Empty values are allowed
|
|
||||||
return
|
|
||||||
|
|
||||||
# Pass any other value to the Parameter model type validator
|
|
||||||
validate_parameter_model_type(value)
|
|
||||||
|
|
||||||
|
|
||||||
def attachment_model_types():
|
def attachment_model_types():
|
||||||
"""Return a list of valid attachment model choices."""
|
"""Return a list of valid attachment model choices."""
|
||||||
import InvenTree.models
|
import InvenTree.models
|
||||||
|
|||||||
Reference in New Issue
Block a user