Skip to content

Commit 6d4f0f4

Browse files
committed
NPL-286 merge other branch changes
1 parent effc1ab commit 6d4f0f4

File tree

4 files changed

+86
-41
lines changed

4 files changed

+86
-41
lines changed

netbox_custom_objects/templates/netbox_custom_objects/customobject.html

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,12 @@
7373
<li class="nav-item">
7474
<a class="nav-link{% if not tab %} active{% endif %}" href="{{ object.get_absolute_url }}">{{ object.custom_object_type.get_verbose_name }}</a>
7575
</li>
76-
77-
{# Include tabs for registered model views #}
78-
{% model_view_tabs object %}
76+
<li class="nav-item">
77+
<a class="nav-link{% if tab == 'journal' %} active{% endif %}" href="{% url 'plugins:netbox_custom_objects:customobject_journal' object.custom_object_type.name object.pk %}">{% trans "Journal" %}</a>
78+
</li>
79+
<li class="nav-item">
80+
<a class="nav-link{% if tab == 'changelog' %} active{% endif %}" href="{% url 'plugins:netbox_custom_objects:customobject_changelog' object.custom_object_type.name object.pk %}">{% trans "Changelog" %}</a>
81+
</li>
7982
</ul>
8083
{% endblock tabs %}
8184

@@ -145,4 +148,4 @@ <h2 class="card-header">{{ field }}</h2>
145148
{% plugin_full_width_page object %}
146149
</div>
147150
</div>
148-
{% endblock %}
151+
{% endblock %}

netbox_custom_objects/templates/netbox_custom_objects/object_journal.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,4 @@ <h2 class="card-header">{% trans "New Journal Entry" %}</h2>
3131
</div>
3232
</div>
3333
{% endif %}
34-
{% endblock %}
34+
{% endblock %}

netbox_custom_objects/urls.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,4 +64,14 @@
6464
views.CustomObjectDeleteView.as_view(),
6565
name="customobject_delete",
6666
),
67+
path(
68+
"custom_object/<int:pk>/journal/",
69+
views.CustomObjectJournalView.as_view(),
70+
name="customobject_journal",
71+
),
72+
path(
73+
"<str:custom_object_type>/<int:pk>/changelog/",
74+
views.CustomObjectChangeLogView.as_view(),
75+
name="customobject_changelog",
76+
),
6777
]

netbox_custom_objects/views.py

Lines changed: 68 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,25 @@
11
import django_filters
2+
from core.models import ObjectChange
3+
from core.tables import ObjectChangeTable
4+
from django.contrib.contenttypes.models import ContentType
25
from django.contrib.postgres.fields import ArrayField
3-
from django.db.models import JSONField
6+
from django.db.models import JSONField, Q
47
from django.shortcuts import get_object_or_404, render
58
from django.urls import reverse
9+
from django.utils.translation import gettext_lazy as _
10+
from django.views.generic import View
611
from extras.choices import CustomFieldUIVisibleChoices
12+
from extras.forms import JournalEntryForm
13+
from extras.models import JournalEntry
14+
from extras.tables import JournalEntryTable
715
from netbox.filtersets import BaseFilterSet
816
from netbox.forms import NetBoxModelBulkEditForm, NetBoxModelFilterSetForm
917
from netbox.views import generic
1018
from netbox.views.generic.mixins import TableMixin
1119
from utilities.forms import ConfirmationForm
1220
from utilities.htmx import htmx_partial
13-
from utilities.views import get_viewname, register_model_view
21+
from utilities.views import (ConditionalLoginRequiredMixin, ViewTab,
22+
get_viewname, register_model_view)
1423

1524
from netbox_custom_objects.tables import CustomObjectTable
1625

@@ -120,7 +129,7 @@ def get_table(self, data, request, bulk_actions=True):
120129
#
121130

122131

123-
@register_model_view(CustomObjectType, 'list', path='', detail=False)
132+
@register_model_view(CustomObjectType, "list", path="", detail=False)
124133
class CustomObjectTypeListView(generic.ObjectListView):
125134
queryset = CustomObjectType.objects.all()
126135
filterset = filtersets.CustomObjectTypeFilterSet
@@ -146,7 +155,7 @@ def get_extra_context(self, request, instance):
146155
}
147156

148157

149-
@register_model_view(CustomObjectType, 'add', detail=False)
158+
@register_model_view(CustomObjectType, "add", detail=False)
150159
@register_model_view(CustomObjectType, "edit")
151160
class CustomObjectTypeEditView(generic.ObjectEditView):
152161
queryset = CustomObjectType.objects.all()
@@ -164,6 +173,7 @@ def _get_dependent_objects(self, obj):
164173
dependent_objects[model] = list(model.objects.all())
165174
return dependent_objects
166175

176+
167177
#
168178
# Custom Object Type Fields
169179
#
@@ -177,7 +187,7 @@ class CustomObjectTypeFieldEditView(generic.ObjectEditView):
177187

178188
@register_model_view(CustomObjectTypeField, "delete")
179189
class CustomObjectTypeFieldDeleteView(generic.ObjectDeleteView):
180-
template_name = 'netbox_custom_objects/field_delete.html'
190+
template_name = "netbox_custom_objects/field_delete.html"
181191
queryset = CustomObjectTypeField.objects.all()
182192

183193
def get_return_url(self, request, obj=None):
@@ -195,56 +205,64 @@ def get(self, request, *args, **kwargs):
195205

196206
model = obj.custom_object_type.get_model()
197207
kwargs = {
198-
f'{obj.name}__isnull': False,
208+
f"{obj.name}__isnull": False,
199209
}
200210
num_dependent_objects = model.objects.filter(**kwargs).count()
201211

202212
# If this is an HTMX request, return only the rendered deletion form as modal content
203213
if htmx_partial(request):
204-
viewname = get_viewname(self.queryset.model, action='delete')
205-
form_url = reverse(viewname, kwargs={'pk': obj.pk})
206-
return render(request, 'htmx/delete_form.html', {
207-
'object': obj,
208-
'object_type': self.queryset.model._meta.verbose_name,
209-
'form': form,
210-
'form_url': form_url,
211-
'num_dependent_objects': num_dependent_objects,
212-
**self.get_extra_context(request, obj),
213-
})
214+
viewname = get_viewname(self.queryset.model, action="delete")
215+
form_url = reverse(viewname, kwargs={"pk": obj.pk})
216+
return render(
217+
request,
218+
"htmx/delete_form.html",
219+
{
220+
"object": obj,
221+
"object_type": self.queryset.model._meta.verbose_name,
222+
"form": form,
223+
"form_url": form_url,
224+
"num_dependent_objects": num_dependent_objects,
225+
**self.get_extra_context(request, obj),
226+
},
227+
)
214228

215-
return render(request, self.template_name, {
216-
'object': obj,
217-
'form': form,
218-
'return_url': self.get_return_url(request, obj),
219-
'num_dependent_objects': num_dependent_objects,
220-
**self.get_extra_context(request, obj),
221-
})
229+
return render(
230+
request,
231+
self.template_name,
232+
{
233+
"object": obj,
234+
"form": form,
235+
"return_url": self.get_return_url(request, obj),
236+
"num_dependent_objects": num_dependent_objects,
237+
**self.get_extra_context(request, obj),
238+
},
239+
)
222240

223241
def _get_dependent_objects(self, obj):
224242
dependent_objects = super()._get_dependent_objects(obj)
225243
model = obj.custom_object_type.get_model()
226244
kwargs = {
227-
f'{obj.name}__isnull': False,
245+
f"{obj.name}__isnull": False,
228246
}
229247
dependent_objects[model] = list(model.objects.filter(**kwargs))
230248
return dependent_objects
231249

232250

233-
@register_model_view(CustomObjectType, 'bulk_import', path='import', detail=False)
251+
@register_model_view(CustomObjectType, "bulk_import", path="import", detail=False)
234252
class CustomObjectTypeBulkImportView(generic.BulkImportView):
235253
queryset = CustomObjectType.objects.all()
236254
model_form = forms.CustomObjectTypeImportForm
237255

238256

239-
@register_model_view(CustomObjectType, 'bulk_edit', path='edit', detail=False)
257+
@register_model_view(CustomObjectType, "bulk_edit", path="edit", detail=False)
240258
class CustomObjectTypeBulkEditView(generic.BulkEditView):
241259
queryset = CustomObjectType.objects.all()
242260
filterset = filtersets.CustomObjectTypeFilterSet
243261
table = tables.CustomObjectTypeTable
244262
form = forms.CustomObjectTypeBulkEditForm
245263

246264

247-
@register_model_view(CustomObjectType, 'bulk_delete', path='delete', detail=False)
265+
@register_model_view(CustomObjectType, "bulk_delete", path="delete", detail=False)
248266
class CustomObjectTypeBulkDeleteView(generic.BulkDeleteView):
249267
queryset = CustomObjectType.objects.all()
250268
filterset = filtersets.CustomObjectTypeFilterSet
@@ -271,8 +289,8 @@ def get_queryset(self, request):
271289
if self.queryset:
272290
return self.queryset
273291
custom_object_type = self.kwargs.get("custom_object_type", None)
274-
self.custom_object_type = get_object_or_404(CustomObjectType,
275-
name__iexact=custom_object_type
292+
self.custom_object_type = get_object_or_404(
293+
CustomObjectType, name__iexact=custom_object_type
276294
)
277295
model = self.custom_object_type.get_model()
278296
return model.objects.all()
@@ -354,16 +372,22 @@ class CustomObjectView(generic.ObjectView):
354372

355373
def get_queryset(self, request):
356374
custom_object_type = self.kwargs.get("custom_object_type", None)
357-
object_type = get_object_or_404(CustomObjectType, name__iexact=custom_object_type)
375+
object_type = get_object_or_404(
376+
CustomObjectType, name__iexact=custom_object_type
377+
)
358378
model = object_type.get_model()
359379
return model.objects.all()
360380

361381
def get_object(self, **kwargs):
362382
custom_object_type = self.kwargs.get("custom_object_type", None)
363-
object_type = get_object_or_404(CustomObjectType, name__iexact=custom_object_type)
383+
object_type = get_object_or_404(
384+
CustomObjectType, name__iexact=custom_object_type
385+
)
364386
model = object_type.get_model()
365387
# Filter out custom_object_type from kwargs for the object lookup
366-
lookup_kwargs = {k: v for k, v in self.kwargs.items() if k != "custom_object_type"}
388+
lookup_kwargs = {
389+
k: v for k, v in self.kwargs.items() if k != "custom_object_type"
390+
}
367391
return get_object_or_404(model.objects.all(), **lookup_kwargs)
368392

369393
def get_extra_context(self, request, instance):
@@ -394,7 +418,9 @@ def get_object(self, **kwargs):
394418
if self.object:
395419
return self.object
396420
custom_object_type = self.kwargs.pop("custom_object_type", None)
397-
object_type = get_object_or_404(CustomObjectType, name__iexact=custom_object_type)
421+
object_type = get_object_or_404(
422+
CustomObjectType, name__iexact=custom_object_type
423+
)
398424
model = object_type.get_model()
399425
if not self.kwargs.get("pk", None):
400426
# We're creating a new object
@@ -420,7 +446,9 @@ def get_form(self, model):
420446
}
421447

422448
# Process custom object type fields (with grouping)
423-
for field in self.object.custom_object_type.fields.all().order_by('group_name', 'weight', 'name'):
449+
for field in self.object.custom_object_type.fields.all().order_by(
450+
"group_name", "weight", "name"
451+
):
424452
field_type = field_types.FIELD_TYPE_CLASS[field.type]()
425453
try:
426454
field_name = field.name
@@ -454,7 +482,9 @@ def custom_init(self, *args, **kwargs):
454482
forms.NetBoxModelForm.__init__(self, *args, **kwargs)
455483
# Set the grouping info as instance attributes from the outer scope
456484
self.custom_object_type_fields = attrs["custom_object_type_fields"]
457-
self.custom_object_type_field_groups = attrs["custom_object_type_field_groups"]
485+
self.custom_object_type_field_groups = attrs[
486+
"custom_object_type_field_groups"
487+
]
458488

459489
form_class.__init__ = custom_init
460490

@@ -479,7 +509,9 @@ def get_object(self, **kwargs):
479509
if self.object:
480510
return self.object
481511
custom_object_type = self.kwargs.pop("custom_object_type", None)
482-
object_type = get_object_or_404(CustomObjectType, name__iexact=custom_object_type)
512+
object_type = get_object_or_404(
513+
CustomObjectType, name__iexact=custom_object_type
514+
)
483515
model = object_type.get_model()
484516
return get_object_or_404(model.objects.all(), **self.kwargs)
485517

0 commit comments

Comments
 (0)