Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions netbox_custom_objects/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from django.conf import settings

from netbox.plugins import PluginConfig


Expand Down
146 changes: 84 additions & 62 deletions netbox_custom_objects/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,79 @@
from django.contrib.contenttypes.models import ContentType
from django.db.models import Model, QuerySet
from extras.choices import CustomFieldTypeChoices
from netbox.api.serializers import NetBoxModelSerializer
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from rest_framework.reverse import reverse

from extras.choices import CustomFieldTypeChoices
from extras.graphql.types import CustomFieldType
from netbox.api.serializers import NetBoxModelSerializer
# from netbox_service_mappings.choices import MappingFieldTypeChoices
from netbox_custom_objects.models import CustomObject, CustomObjectType, CustomObjectTypeField
from utilities.api import get_serializer_for_model
from netbox_custom_objects.models import (CustomObject, CustomObjectType,
CustomObjectTypeField)

__all__ = (
'CustomObjectTypeSerializer',
'CustomObjectSerializer',
"CustomObjectTypeSerializer",
"CustomObjectSerializer",
)


class ContentTypeSerializer(NetBoxModelSerializer):
class Meta:
model = ContentType
fields = ('id', 'app_label', 'model',)
fields = (
"id",
"app_label",
"model",
)


class CustomObjectTypeFieldSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_custom_objects-api:customobjecttypefield-detail'
view_name="plugins-api:netbox_custom_objects-api:customobjecttypefield-detail"
)
# content_type = serializers.SerializerMethodField()
app_label = serializers.CharField(required=False)
model = serializers.CharField(required=False)

class Meta:
model = CustomObjectTypeField
fields = (
# 'id', 'url', 'name', 'label', 'custom_object_type', 'field_type', 'content_type', 'many', 'options',
'id', 'name', 'label', 'custom_object_type', 'type', 'primary', 'default', 'choice_set',
'validation_regex', 'validation_minimum', 'validation_maximum',
'related_object_type', 'app_label', 'model',
"id",
"name",
"label",
"custom_object_type",
"type",
"primary",
"default",
"choice_set",
"validation_regex",
"validation_minimum",
"validation_maximum",
"related_object_type",
"app_label",
"model",
)

def validate(self, attrs):
app_label = attrs.pop('app_label', None)
model = attrs.pop('model', None)
if attrs['type'] in [CustomFieldTypeChoices.TYPE_OBJECT, CustomFieldTypeChoices.TYPE_MULTIOBJECT]:
app_label = attrs.pop("app_label", None)
model = attrs.pop("model", None)
if attrs["type"] in [
CustomFieldTypeChoices.TYPE_OBJECT,
CustomFieldTypeChoices.TYPE_MULTIOBJECT,
]:
try:
attrs['related_object_type'] = ContentType.objects.get(app_label=app_label, model=model)
attrs["related_object_type"] = ContentType.objects.get(
app_label=app_label, model=model
)
except ContentType.DoesNotExist:
raise ValidationError('Must provide valid app_label and model for object field type.')
if attrs['type'] in [CustomFieldTypeChoices.TYPE_SELECT, CustomFieldTypeChoices.TYPE_MULTISELECT]:
if not attrs.get('choice_set', None):
raise ValidationError('Must provide choice_set with valid PK for select field type.')
raise ValidationError(
"Must provide valid app_label and model for object field type."
)
if attrs["type"] in [
CustomFieldTypeChoices.TYPE_SELECT,
CustomFieldTypeChoices.TYPE_MULTISELECT,
]:
if not attrs.get("choice_set", None):
raise ValidationError(
"Must provide choice_set with valid PK for select field type."
)
return super().validate(attrs)

def create(self, validated_data):
Expand All @@ -70,7 +93,7 @@ def get_related_object_type(self, obj):

class CustomObjectTypeSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_custom_objects-api:customobjecttype-detail'
view_name="plugins-api:netbox_custom_objects-api:customobjecttype-detail"
)
fields = CustomObjectTypeFieldSerializer(
nested=True,
Expand All @@ -81,9 +104,16 @@ class CustomObjectTypeSerializer(NetBoxModelSerializer):
class Meta:
model = CustomObjectType
fields = [
'id', 'url', 'name', 'description', 'tags', 'created', 'last_updated', 'fields',
"id",
"url",
"name",
"description",
"tags",
"created",
"last_updated",
"fields",
]
brief_fields = ('id', 'url', 'name', 'description')
brief_fields = ("id", "url", "name", "description")

def create(self, validated_data):
return super().create(validated_data)
Expand All @@ -92,39 +122,43 @@ def create(self, validated_data):
class CustomObjectSerializer(NetBoxModelSerializer):
relation_fields = None

# url = serializers.HyperlinkedIdentityField(
# view_name='plugins-api:netbox_custom_objects-api:custom-object-detail', kwargs={'custom_object_type': 1}
# )
url = serializers.SerializerMethodField()
field_data = serializers.SerializerMethodField()
custom_object_type = CustomObjectTypeSerializer(nested=True)

class Meta:
model = CustomObject
fields = [
'id', 'url', 'name', 'display', 'custom_object_type', 'tags', 'created', 'last_updated', 'data', 'field_data',
"id",
"url",
"name",
"display",
"custom_object_type",
"tags",
"created",
"last_updated",
"data",
"field_data",
]
brief_fields = ('id', 'url', 'name', 'custom_object_type',)
brief_fields = (
"id",
"url",
"name",
"custom_object_type",
)

def get_display(self, obj):
return f'{obj.custom_object_type}: {obj.name}'
return f"{obj.custom_object_type}: {obj.name}"

def validate(self, attrs):
# self.relation_fields = {}
# object_field_types = [CustomFieldTypeChoices.TYPE_OBJECT, CustomFieldTypeChoices.TYPE_MULTIOBJECT]
# for field in attrs['custom_object_type'].fields.filter(type__in=object_field_types):
# self.relation_fields[field.name] = attrs['data'].pop(field.name, None)
return super().validate(attrs)

def update_relation_fields(self, instance):
# TODO: Implement this
pass

def create(self, validated_data):
# instance = super().create(validated_data)
# self.update_relation_fields(instance)

model = validated_data['custom_object_type'].get_model()
model = validated_data["custom_object_type"].get_model()
instance = model.objects.create(**validated_data)

return instance
Expand All @@ -142,31 +176,21 @@ def get_url(self, obj):
attributes are not configured to correctly match the URL conf.
"""
# Unsaved objects will not yet have a valid URL.
if hasattr(obj, 'pk') and obj.pk in (None, ''):
if hasattr(obj, "pk") and obj.pk in (None, ""):
return None

view_name = 'plugins-api:netbox_custom_objects-api:custom-object-detail'
lookup_value = getattr(obj, 'pk')
kwargs = {'pk': lookup_value, 'custom_object_type': obj.custom_object_type.name.lower()}
request = self.context['request']
format = self.context.get('format')
view_name = "plugins-api:netbox_custom_objects-api:custom-object-detail"
lookup_value = getattr(obj, "pk")
kwargs = {
"pk": lookup_value,
"custom_object_type": obj.custom_object_type.name.lower(),
}
request = self.context["request"]
format = self.context.get("format")
return reverse(view_name, kwargs=kwargs, request=request, format=format)

def get_field_data(self, obj):
result = {}
# for field_name, value in obj.fields.items():
# if isinstance(value, Model) or isinstance(value, QuerySet):
# # serializer = get_serializer_for_model(field.model_class)
# if isinstance(value, QuerySet):
# serializer = get_serializer_for_model(value.model)
# many = True
# else:
# serializer = get_serializer_for_model(value._meta.model)
# many = False
# context = {'request': self.context['request']}
# result[field_name] = serializer(value, nested=True, context=context, many=many).data
# continue
# result[field_name] = obj.data.get(field_name)
return result


Expand All @@ -187,9 +211,7 @@ def get_serializer_class(model):

serializer = type(
f"{model._meta.object_name}Serializer",
(
serializers.ModelSerializer,
),
(serializers.ModelSerializer,),
attrs,
)

Expand Down
41 changes: 17 additions & 24 deletions netbox_custom_objects/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,26 @@
from rest_framework.urlpatterns import format_suffix_patterns
from django.urls import path, include

from django.urls import include, path
from netbox.api.routers import NetBoxRouter
from . import views

from . import views

custom_object_list = views.CustomObjectViewSet.as_view({
'get': 'list',
'post': 'create'
})
custom_object_detail = views.CustomObjectViewSet.as_view({
'get': 'retrieve',
'put': 'update',
'patch': 'partial_update',
'delete': 'destroy'
})
custom_object_list = views.CustomObjectViewSet.as_view(
{"get": "list", "post": "create"}
)
custom_object_detail = views.CustomObjectViewSet.as_view(
{"get": "retrieve", "put": "update", "patch": "partial_update", "delete": "destroy"}
)

router = NetBoxRouter()
router.APIRootView = views.RootView
router.register('custom-object-types', views.CustomObjectTypeViewSet)
# router.register('custom-objects', views.CustomObjectViewSet)
router.register('custom-object-type-fields', views.CustomObjectTypeFieldViewSet)
# router.register('mapping-relations', views.MappingRelationViewSet)

# urlpatterns = router.urls
router.register("custom-object-types", views.CustomObjectTypeViewSet)
router.register("custom-object-type-fields", views.CustomObjectTypeFieldViewSet)

urlpatterns = [
path('', include(router.urls)),
path('<str:custom_object_type>/', custom_object_list, name='customobject-list'),
path('<str:custom_object_type>/<int:pk>/', custom_object_detail, name='customobject-detail'),
path("", include(router.urls)),
path("<str:custom_object_type>/", custom_object_list, name="customobject-list"),
path(
"<str:custom_object_type>/<int:pk>/",
custom_object_detail,
name="customobject-detail",
),
]
# urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html'])
18 changes: 7 additions & 11 deletions netbox_custom_objects/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,35 @@
from rest_framework.routers import APIRootView
from rest_framework.viewsets import ModelViewSet

from netbox_custom_objects import filtersets
from netbox_custom_objects.models import CustomObject, CustomObjectType, CustomObjectTypeField
from netbox_custom_objects.models import (CustomObject, CustomObjectType,
CustomObjectTypeField)

from . import serializers
from ..views import CustomObjectTypeView


class RootView(APIRootView):
def get_view_name(self):
return 'CustomObjects'
return "CustomObjects"


class CustomObjectTypeViewSet(ModelViewSet):
queryset = CustomObjectType.objects.all()
serializer_class = serializers.CustomObjectTypeSerializer
# filterset_class = filtersets.BranchFilterSet


class CustomObjectViewSet(ModelViewSet):
queryset = CustomObject.objects.all()
serializer_class = serializers.CustomObjectSerializer
# filterset_class = filtersets.CustomObjectFilterSet
model = None

# def get_view_name(self):
# custom_object_type = CustomObjectType.objects.get(name__iexact=self.kwargs['custom_object_type'])
# return custom_object_type.name

def get_serializer_class(self):
return serializers.get_serializer_class(self.model)

def get_queryset(self):
try:
custom_object_type = CustomObjectType.objects.get(name__iexact=self.kwargs['custom_object_type'])
custom_object_type = CustomObjectType.objects.get(
name__iexact=self.kwargs["custom_object_type"]
)
except CustomObjectType.DoesNotExist:
raise Http404
self.model = custom_object_type.get_model()
Expand Down
25 changes: 12 additions & 13 deletions netbox_custom_objects/choices.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
from django.utils.translation import gettext_lazy as _

from utilities.choices import ChoiceSet


class MappingFieldTypeChoices(ChoiceSet):
CHAR = 'char'
INTEGER = 'integer'
BOOLEAN = 'boolean'
DATE = 'date'
DATETIME = 'datetime'
OBJECT = 'object'
CHAR = "char"
INTEGER = "integer"
BOOLEAN = "boolean"
DATE = "date"
DATETIME = "datetime"
OBJECT = "object"

CHOICES = (
(CHAR, _('String'), 'cyan'),
(INTEGER, _('Integer'), 'orange'),
(BOOLEAN, _('Boolean'), 'green'),
(DATE, _('Date'), 'red'),
(DATETIME, _('DateTime'), 'blue'),
(OBJECT, _('Object'), 'orange'),
(CHAR, _("String"), "cyan"),
(INTEGER, _("Integer"), "orange"),
(BOOLEAN, _("Boolean"), "green"),
(DATE, _("Date"), "red"),
(DATETIME, _("DateTime"), "blue"),
(OBJECT, _("Object"), "orange"),
)
6 changes: 3 additions & 3 deletions netbox_custom_objects/constants.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Models which do not support change logging, but whose database tables
# must be replicated for each branch to ensure proper functionality
INCLUDE_MODELS = (
'dcim.cablepath',
'extras.cachedvalue',
"dcim.cablepath",
"extras.cachedvalue",
)

APP_LABEL = 'netbox_custom_objects'
APP_LABEL = "netbox_custom_objects"
Loading