mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Add REST API endpoint for custom fields
This commit is contained in:
@ -6,6 +6,7 @@ from users.api.nested_serializers import NestedUserSerializer
|
||||
|
||||
__all__ = [
|
||||
'NestedConfigContextSerializer',
|
||||
'NestedCustomFieldSerializer',
|
||||
'NestedExportTemplateSerializer',
|
||||
'NestedImageAttachmentSerializer',
|
||||
'NestedJobResultSerializer',
|
||||
@ -13,6 +14,14 @@ __all__ = [
|
||||
]
|
||||
|
||||
|
||||
class NestedCustomFieldSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfield-detail')
|
||||
|
||||
class Meta:
|
||||
model = models.CustomField
|
||||
fields = ['id', 'url', 'name']
|
||||
|
||||
|
||||
class NestedConfigContextSerializer(WritableNestedSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:configcontext-detail')
|
||||
|
||||
|
@ -10,7 +10,7 @@ from dcim.api.nested_serializers import (
|
||||
from dcim.models import Device, DeviceRole, Platform, Rack, Region, Site
|
||||
from extras.choices import *
|
||||
from extras.models import (
|
||||
ConfigContext, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag,
|
||||
ConfigContext, CustomField, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag,
|
||||
)
|
||||
from extras.utils import FeatureQuery
|
||||
from netbox.api import ChoiceField, ContentTypeField, SerializedPKRelatedField, ValidatedModelSerializer
|
||||
@ -24,6 +24,27 @@ from virtualization.models import Cluster, ClusterGroup
|
||||
from .nested_serializers import *
|
||||
|
||||
|
||||
#
|
||||
# Custom fields
|
||||
#
|
||||
|
||||
class CustomFieldSerializer(ValidatedModelSerializer):
|
||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:customfield-detail')
|
||||
content_types = ContentTypeField(
|
||||
queryset=ContentType.objects.filter(FeatureQuery('export_templates').get_query()),
|
||||
many=True
|
||||
)
|
||||
type = ChoiceField(choices=CustomFieldTypeChoices)
|
||||
filter_logic = ChoiceField(choices=CustomFieldFilterLogicChoices, required=False)
|
||||
|
||||
class Meta:
|
||||
model = CustomField
|
||||
fields = [
|
||||
'id', 'url', 'content_types', 'type', 'name', 'label', 'description', 'required', 'filter_logic',
|
||||
'default', 'weight', 'validation_minimum', 'validation_maximum', 'validation_regex', 'choices',
|
||||
]
|
||||
|
||||
|
||||
#
|
||||
# Export templates
|
||||
#
|
||||
|
@ -5,6 +5,9 @@ from . import views
|
||||
router = OrderedDefaultRouter()
|
||||
router.APIRootView = views.ExtrasRootView
|
||||
|
||||
# Custom fields
|
||||
router.register('custom-fields', views.CustomFieldViewSet)
|
||||
|
||||
# Export templates
|
||||
router.register('export-templates', views.ExportTemplateViewSet)
|
||||
|
||||
|
@ -12,17 +12,26 @@ from rq import Worker
|
||||
|
||||
from extras import filters
|
||||
from extras.choices import JobResultStatusChoices
|
||||
from extras.models import ConfigContext, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag
|
||||
from extras.models import ConfigContext, CustomField, ExportTemplate, ImageAttachment, ObjectChange, JobResult, Tag
|
||||
from extras.reports import get_report, get_reports, run_report
|
||||
from extras.scripts import get_script, get_scripts, run_script
|
||||
from netbox.api.views import ModelViewSet
|
||||
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
|
||||
from netbox.api.metadata import ContentTypeMetadata
|
||||
from utilities.exceptions import RQWorkerNotRunningException
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from utilities.utils import copy_safe_request
|
||||
from . import serializers
|
||||
|
||||
|
||||
class ExtrasRootView(APIRootView):
|
||||
"""
|
||||
Extras API root view
|
||||
"""
|
||||
def get_view_name(self):
|
||||
return 'Extras'
|
||||
|
||||
|
||||
class ConfigContextQuerySetMixin:
|
||||
"""
|
||||
Used by views that work with config context models (device and virtual machine).
|
||||
@ -46,18 +55,17 @@ class ConfigContextQuerySetMixin:
|
||||
return self.queryset.annotate_config_context_data()
|
||||
|
||||
|
||||
class ExtrasRootView(APIRootView):
|
||||
"""
|
||||
Extras API root view
|
||||
"""
|
||||
def get_view_name(self):
|
||||
return 'Extras'
|
||||
|
||||
|
||||
#
|
||||
# Custom fields
|
||||
#
|
||||
|
||||
class CustomFieldViewSet(ModelViewSet):
|
||||
metadata_class = ContentTypeMetadata
|
||||
queryset = CustomField.objects.all()
|
||||
serializer_class = serializers.CustomFieldSerializer
|
||||
filterset_class = filters.CustomFieldFilterSet
|
||||
|
||||
|
||||
class CustomFieldModelViewSet(ModelViewSet):
|
||||
"""
|
||||
Include the applicable set of CustomFields in the ModelViewSet context.
|
||||
|
@ -74,6 +74,13 @@ class CustomFieldModelFilterSet(django_filters.FilterSet):
|
||||
self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(field_name=cf.name, custom_field=cf)
|
||||
|
||||
|
||||
class CustomFieldFilterSet(django_filters.FilterSet):
|
||||
|
||||
class Meta:
|
||||
model = CustomField
|
||||
fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'default', 'weight']
|
||||
|
||||
|
||||
class ExportTemplateFilterSet(BaseFilterSet):
|
||||
|
||||
class Meta:
|
||||
|
@ -13,6 +13,7 @@ from django.utils.safestring import mark_safe
|
||||
from extras.choices import *
|
||||
from extras.utils import FeatureQuery
|
||||
from utilities.forms import CSVChoiceField, DatePicker, LaxURLField, StaticSelect2, add_blank_choice
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from utilities.validators import validate_regex
|
||||
|
||||
|
||||
@ -63,7 +64,7 @@ class CustomFieldModel(models.Model):
|
||||
raise ValidationError(f"Missing required custom field '{cf.name}'.")
|
||||
|
||||
|
||||
class CustomFieldManager(models.Manager):
|
||||
class CustomFieldManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
||||
use_in_migrations = True
|
||||
|
||||
def get_for_model(self, model):
|
||||
@ -193,7 +194,7 @@ class CustomField(models.Model):
|
||||
})
|
||||
|
||||
# A selection field must have at least two choices defined
|
||||
if self.type == CustomFieldTypeChoices.TYPE_SELECT and len(self.choices) < 2:
|
||||
if self.type == CustomFieldTypeChoices.TYPE_SELECT and self.choices and len(self.choices) < 2:
|
||||
raise ValidationError({
|
||||
'choices': "Selection fields must specify at least two choices."
|
||||
})
|
||||
|
Reference in New Issue
Block a user