mirror of
https://github.com/inventree/InvenTree.git
synced 2025-12-16 09:18:10 +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 django.conf import settings
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||
from django.db import models
|
||||
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 InvenTree.fields import InvenTreeRestURLField, InvenTreeURLField
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.helpers_model import getModelChoicesWithMixin
|
||||
from InvenTree.helpers_model import getModelsWithMixin
|
||||
|
||||
from .setting.storages import StorageBackends
|
||||
|
||||
@@ -719,7 +720,7 @@ class RemoteImageMixin(metaclass=serializers.SerializerMetaclass):
|
||||
return url
|
||||
|
||||
|
||||
class ContentTypeField(serializers.Field):
|
||||
class ContentTypeField(serializers.ChoiceField):
|
||||
"""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.
|
||||
@@ -736,13 +737,26 @@ class ContentTypeField(serializers.Field):
|
||||
mixin_class: Optional mixin class to restrict valid content types.
|
||||
"""
|
||||
self.mixin_class = mixin_class
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Override the 'choices' field, to limit to the appropriate models
|
||||
if self.mixin_class is not None:
|
||||
self.choices = getModelChoicesWithMixin(
|
||||
self.mixin_class, allow_null=kwargs.get('allow_null', False)
|
||||
)
|
||||
models = getModelsWithMixin(self.mixin_class)
|
||||
|
||||
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):
|
||||
"""Convert ContentType instance to string representation."""
|
||||
|
||||
@@ -2386,11 +2386,6 @@ class ParameterTemplate(
|
||||
verbose_name = _('Parameter Template')
|
||||
verbose_name_plural = _('Parameter Templates')
|
||||
|
||||
class ModelChoices(RenderChoices):
|
||||
"""Model choices for parameter templates."""
|
||||
|
||||
choice_fnc = common.validators.parameter_template_model_options
|
||||
|
||||
@staticmethod
|
||||
def get_api_url() -> str:
|
||||
"""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_model import construct_absolute_url
|
||||
from InvenTree.mixins import DataImportExportSerializerMixin
|
||||
from InvenTree.models import InvenTreeParameterMixin
|
||||
from InvenTree.serializers import (
|
||||
ContentTypeField,
|
||||
FilterableSerializerMixin,
|
||||
InvenTreeAttachmentSerializerField,
|
||||
InvenTreeImageSerializerField,
|
||||
@@ -721,22 +723,12 @@ class ParameterTemplateSerializer(
|
||||
'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
|
||||
model_type = serializers.ChoiceField(
|
||||
model_type = ContentTypeField(
|
||||
mixin_class=InvenTreeParameterMixin,
|
||||
label=_('Model Type'),
|
||||
default='',
|
||||
choices=common.validators.parameter_template_model_options(),
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
@@ -767,15 +759,6 @@ class ParameterSerializer(
|
||||
|
||||
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):
|
||||
"""Save the Parameter instance."""
|
||||
from InvenTree.models import InvenTreeParameterMixin
|
||||
@@ -813,13 +796,11 @@ class ParameterSerializer(
|
||||
return instance
|
||||
|
||||
# Note: The choices are overridden at run-time on class initialization
|
||||
model_type = serializers.ChoiceField(
|
||||
model_type = ContentTypeField(
|
||||
mixin_class=InvenTreeParameterMixin,
|
||||
label=_('Model Type'),
|
||||
default='',
|
||||
choices=common.validators.parameter_model_options(),
|
||||
required=False,
|
||||
allow_blank=True,
|
||||
allow_null=True,
|
||||
)
|
||||
|
||||
updated_by_detail = enable_filter(
|
||||
|
||||
@@ -9,67 +9,6 @@ import common.icons
|
||||
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():
|
||||
"""Return a list of valid attachment model choices."""
|
||||
import InvenTree.models
|
||||
|
||||
Reference in New Issue
Block a user