Skip to content

Commit

Permalink
Merge pull request #66 from Kani999/65-nested-serializers-are-being-d…
Browse files Browse the repository at this point in the history
…eprecaded-from-netbox-4

BugFix: Nested serializers are being deprecaded from netbox 4
  • Loading branch information
Kani999 authored Jul 17, 2024
2 parents 818ce2d + 5635e08 commit 2221264
Show file tree
Hide file tree
Showing 20 changed files with 353 additions and 253 deletions.
2 changes: 1 addition & 1 deletion netbox_attachments/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from netbox.plugins import PluginConfig
from .version import __version__
from netbox_attachments.version import __version__


class NetBoxAttachmentsConfig(PluginConfig):
Expand Down
41 changes: 25 additions & 16 deletions netbox_attachments/api/serializers.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,48 @@
from django.contrib.contenttypes.models import ContentType
from core.models.contenttypes import ObjectType
from django.core.exceptions import ObjectDoesNotExist
# from drf_yasg.utils import swagger_serializer_method
from netbox.api.fields import ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer
from netbox.constants import NESTED_SERIALIZER_PREFIX
from rest_framework import serializers
from utilities.api import get_serializer_for_model

from ..models import NetBoxAttachment
from netbox_attachments.models import NetBoxAttachment


class NetBoxAttachmentSerializer(NetBoxModelSerializer):
url = serializers.HyperlinkedIdentityField(
view_name='plugins-api:netbox_attachments-api:netboxattachment-detail')
content_type = ContentTypeField(
queryset=ContentType.objects.all()
view_name="plugins-api:netbox_attachments-api:netboxattachment-detail"
)
object_type = ContentTypeField(queryset=ObjectType.objects.all())
parent = serializers.SerializerMethodField(read_only=True)

class Meta:
model = NetBoxAttachment
fields = [
'id', 'url', 'display', 'content_type', 'object_id', 'parent', 'name', 'description', 'file', 'created', 'last_updated', 'comments',
"id",
"url",
"display",
"object_type",
"object_id",
"parent",
"name",
"description",
"file",
"created",
"last_updated",
"comments",
]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'file')
brief_fields = ("id", "url", "display", "name", "description", "file")

def validate(self, data):
# Validate that the parent object exists
try:
if 'content_type' in data and 'object_id' in data:
data['content_type'].get_object_for_this_type(
id=data['object_id'])
if "object_type" in data and "object_id" in data:
data["object_type"].get_object_for_this_type(id=data["object_id"])
except ObjectDoesNotExist:
raise serializers.ValidationError(
"Invalid parent object: {} ID {}".format(
data['content_type'], data['object_id'])
data["object_type"], data["object_id"]
)
)

# Enforce model validation
Expand All @@ -45,8 +53,9 @@ def validate(self, data):
# @swagger_serializer_method(serializer_or_field=serializers.JSONField)
def get_parent(self, obj):
if obj.parent:
serializer = get_serializer_for_model(
obj.parent, prefix=NESTED_SERIALIZER_PREFIX)
return serializer(obj.parent, context={'request': self.context['request']}).data
serializer = get_serializer_for_model(obj.parent)
return serializer(
obj.parent, nested=True, context={"request": self.context["request"]}
).data
else:
return None
6 changes: 3 additions & 3 deletions netbox_attachments/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
from netbox.api.routers import NetBoxRouter

from . import views
from netbox_attachments.api import views

app_name = 'netbox_attachments'
app_name = "netbox_attachments"
router = NetBoxRouter()
router.register('netbox-attachments', views.NetBoxAttachmentViewSet)
router.register("netbox-attachments", views.NetBoxAttachmentViewSet)

urlpatterns = router.urls
4 changes: 2 additions & 2 deletions netbox_attachments/api/views.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from netbox.api.metadata import ContentTypeMetadata
from netbox.api.viewsets import NetBoxModelViewSet

from .. import filtersets, models
from .serializers import NetBoxAttachmentSerializer
from netbox_attachments import filtersets, models
from netbox_attachments.api.serializers import NetBoxAttachmentSerializer


class NetBoxAttachmentViewSet(NetBoxModelViewSet):
Expand Down
10 changes: 5 additions & 5 deletions netbox_attachments/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,24 @@
from netbox.filtersets import NetBoxModelFilterSet
from utilities.filters import ContentTypeFilter

from .models import NetBoxAttachment
from netbox_attachments.models import NetBoxAttachment


class NetBoxAttachmentFilterSet(NetBoxModelFilterSet):
q = django_filters.CharFilter(method='search', label='Search')
q = django_filters.CharFilter(method="search", label="Search")
created = django_filters.DateTimeFilter()
content_type = ContentTypeFilter()
object_type = ContentTypeFilter()
name = django_filters.CharFilter(lookup_expr="icontains")
description = django_filters.CharFilter(lookup_expr="icontains")
tag = TagFilter()

class Meta:
model = NetBoxAttachment
fields = ['id', 'content_type_id', 'object_id', 'name', 'description']
fields = ["id", "object_type_id", "object_id", "name", "description"]

def search(self, queryset, name, value):
if not value.strip():
return queryset

filters = Q(name__icontains=value) | Q(description__icontains=value)
return queryset.filter(filters)
return queryset.filter(filters)
26 changes: 17 additions & 9 deletions netbox_attachments/forms.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from core.models.contenttypes import ObjectType
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _
from netbox.forms import NetBoxModelFilterSetForm, NetBoxModelForm
from utilities.forms.fields import (
CommentField,
DynamicModelMultipleChoiceField,
TagFilterField,
)
from utilities.forms.widgets.apiselect import APISelectMultiple
from utilities.forms.fields import DynamicModelMultipleChoiceField, TagFilterField, CommentField

from .models import NetBoxAttachment
from netbox_attachments.models import NetBoxAttachment


class NetBoxAttachmentForm(NetBoxModelForm):
Expand All @@ -14,20 +18,24 @@ class NetBoxAttachmentForm(NetBoxModelForm):
class Meta:
model = NetBoxAttachment
fields = [
'name', 'description', 'file', 'comments', 'tags',
"name",
"description",
"file",
"comments",
"tags",
]


class NetBoxAttachmentFilterForm(NetBoxModelFilterSetForm):
model = NetBoxAttachment
name = forms.CharField(required=False)
description = forms.CharField(required=False)
content_type_id = DynamicModelMultipleChoiceField(
queryset=ContentType.objects.all(),
object_type_id = DynamicModelMultipleChoiceField(
queryset=ObjectType.objects.all(),
required=False,
label=_('Object Type'),
label=_("Object Type"),
widget=APISelectMultiple(
api_url='/api/extras/content-types/',
)
api_url="/api/extras/object-types/",
),
)
tag = TagFilterField(model)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Generated by Django 5.0.6 on 2024-07-16 12:19

from django.db import migrations


class Migration(migrations.Migration):
dependencies = [
("netbox_attachments", "0005_netboxattachment_description"),
]

operations = [
migrations.RenameField(
model_name="netboxattachment",
old_name="content_type",
new_name="object_type",
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Generated by Django 5.0.6 on 2024-07-16 12:57

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
("core", "0010_gfk_indexes"),
("netbox_attachments", "0006_rename_content_type_netboxattachment_object_type"),
]

operations = [
migrations.AlterField(
model_name="netboxattachment",
name="object_type",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE, to="core.objecttype"
),
),
]
58 changes: 25 additions & 33 deletions netbox_attachments/models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import numbers
import os

from django.contrib.contenttypes.models import ContentType
from core.models.contenttypes import ObjectType
from django.core.exceptions import ObjectDoesNotExist
from django.db import models
from django.db.models.signals import pre_delete
Expand All @@ -9,19 +10,16 @@
from django.utils.translation import gettext_lazy as _
from netbox.models import NetBoxModel
from utilities.querysets import RestrictedQuerySet
import numbers

from .utils import attachment_upload
from netbox_attachments.utils import attachment_upload


class NetBoxAttachment(NetBoxModel):
"""
An uploaded attachment which is associated with an object.
"""
content_type = models.ForeignKey(
to=ContentType,
on_delete=models.CASCADE
)

object_type = models.ForeignKey(to=ObjectType, on_delete=models.CASCADE)
object_id = models.PositiveBigIntegerField()
file = models.FileField(
upload_to=attachment_upload,
Expand All @@ -30,27 +28,20 @@ class NetBoxAttachment(NetBoxModel):
editable=False,
null=True,
blank=True,
help_text='Size of the file in bytes',
)
name = models.CharField(
max_length=254,
blank=True
help_text="Size of the file in bytes",
)
name = models.CharField(max_length=254, blank=True)
description = models.CharField(
verbose_name=_('description'),
max_length=200,
blank=True
)
comments = models.TextField(
blank=True
verbose_name=_("description"), max_length=200, blank=True
)
comments = models.TextField(blank=True)

objects = RestrictedQuerySet.as_manager()

clone_fields = ('content_type', 'object_id')
clone_fields = ("object_type", "object_id")

class Meta:
ordering = ('name', 'pk') # name may be non-unique
ordering = ("name", "pk") # name may be non-unique
verbose_name_plural = "NetBox Attachments"
verbose_name = "NetBox Attachment"

Expand All @@ -66,22 +57,20 @@ def filename(self):

@property
def parent(self):
if self.content_type.model_class() is None:
if self.object_type.model_class() is None:
# Model for the content type does not exists
# Model was probably deleted or uninstalled -> parent object cannot be found
return None

try:
return self.content_type.get_object_for_this_type(id=self.object_id)
return self.object_type.get_object_for_this_type(id=self.object_id)
except ObjectDoesNotExist:
# Object for the content type Model does not exists
return None

def get_absolute_url(self):
return reverse('plugins:netbox_attachments:netboxattachment', args=[self.pk])
return reverse("plugins:netbox_attachments:netboxattachment", args=[self.pk])

def delete(self, *args, **kwargs):

_name = self.file.name

super().delete(*args, **kwargs)
Expand All @@ -100,10 +89,10 @@ def save(self, *args, **kwargs):
return super().save(*args, **kwargs)

if not self.name:
if self._state.adding == True:
self.name = self.file.name.rsplit('/', 1)[-1]
if self._state.adding:
self.name = self.file.name.rsplit("/", 1)[-1]
else:
self.name = self.filename.split('_', 2)[2]
self.name = self.filename.split("_", 2)[2]

super().save(*args, **kwargs)

Expand All @@ -117,10 +106,13 @@ def pre_delete_receiver(sender, instance, **kwargs):
# code that delete the related objects
# As you don't have generic relation you should manually
# find related actitities

# Workaround: only run signals on Models where PK is Integral
# https://github.com/Kani999/netbox-attachments/issues/44
# https://github.com/Kani999/netbox-attachments/issues/44
if isinstance(instance.pk, numbers.Integral):
ctype = ContentType.objects.get_for_model(instance)
NetBoxAttachment.objects.filter(
content_type=ctype, object_id=instance.pk).delete()
object_type = ObjectType.objects.get_for_model(instance)
attachments = NetBoxAttachment.objects.filter(
object_type_id=object_type.id, object_id=instance.pk
)
if attachments:
attachments.delete()
17 changes: 10 additions & 7 deletions netbox_attachments/navigation.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from netbox.plugins import PluginMenu, PluginMenuItem

menu = PluginMenu(
label='Attachments',
label="Attachments",
icon_class="mdi mdi-paperclip",
groups=(
("", (
PluginMenuItem(
link="plugins:netbox_attachments:netboxattachment_list",
link_text="NetBox Attachments",
permissions=['netbox_attachments.view_netboxattachment']
(
"",
(
PluginMenuItem(
link="plugins:netbox_attachments:netboxattachment_list",
link_text="NetBox Attachments",
permissions=["netbox_attachments.view_netboxattachment"],
),
),
)),
),
),
)
9 changes: 5 additions & 4 deletions netbox_attachments/search.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from netbox.search import SearchIndex, register_search
from .models import NetBoxAttachment

from netbox_attachments.models import NetBoxAttachment


@register_search
class NetBoxAttachmentIndex(SearchIndex):
model = NetBoxAttachment
fields = (
('name', 100),
('description', 200),
('comments', 5000),
("name", 100),
("description", 200),
("comments", 5000),
)
Loading

0 comments on commit 2221264

Please sign in to comment.