Arthur 3 лет назад
Родитель
Сommit
eb3d3dcbc4

+ 5 - 0
netbox/dcim/models/racks.py

@@ -1,5 +1,6 @@
 from collections import OrderedDict
 
+from django.apps import apps
 from django.contrib.auth.models import User
 from django.contrib.contenttypes.fields import GenericRelation
 from django.contrib.contenttypes.models import ContentType
@@ -202,6 +203,10 @@ class Rack(NetBoxModel):
             return f'{self.name} ({self.facility_id})'
         return self.name
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [apps.get_model('dcim.Site'), ]
+
     def get_absolute_url(self):
         return reverse('dcim:rack', args=[self.pk])
 

+ 1 - 0
netbox/dcim/views.py

@@ -560,6 +560,7 @@ class RackRoleBulkDeleteView(generic.BulkDeleteView):
 #
 
 class RackListView(generic.ObjectListView):
+    required_prerequisites = [Site]
     queryset = Rack.objects.prefetch_related('devices__device_type').annotate(
         device_count=count_related(Device, 'rack')
     )

+ 4 - 0
netbox/netbox/models/__init__.py

@@ -52,6 +52,10 @@ class NetBoxModel(NetBoxFeatureSet, models.Model):
     class Meta:
         abstract = True
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return []
+
 
 class NestedGroupModel(NetBoxFeatureSet, MPTTModel):
     """

+ 15 - 0
netbox/netbox/views/generic/bulk_views.py

@@ -25,6 +25,7 @@ from utilities.htmx import is_htmx
 from utilities.permissions import get_permission_for_model
 from utilities.views import GetReturnURLMixin
 from .base import BaseMultiObjectView
+from .utils import get_prerequisite_model
 
 __all__ = (
     'BulkComponentCreateView',
@@ -143,6 +144,7 @@ class ObjectListView(BaseMultiObjectView):
         """
         model = self.queryset.model
         content_type = ContentType.objects.get_for_model(model)
+        requirement = get_prerequisite_model(self.queryset)
 
         if self.filterset:
             self.queryset = self.filterset(request.GET, self.queryset).qs
@@ -198,6 +200,8 @@ class ObjectListView(BaseMultiObjectView):
             'filter_form': self.filterset_form(request.GET, label_suffix='') if self.filterset_form else None,
             **self.get_extra_context(request),
         }
+        if requirement:
+            context['required_model'] = requirement
 
         return render(request, self.template_name, context)
 
@@ -256,6 +260,17 @@ class BulkCreateView(GetReturnURLMixin, BaseMultiObjectView):
         form = self.form()
         model_form = self.model_form(initial=initial)
 
+        context = {
+            'obj_type': self.model_form._meta.model._meta.verbose_name,
+            'form': form,
+            'model_form': model_form,
+            'return_url': self.get_return_url(request),
+            **self.get_extra_context(request),
+        }
+
+        if requirement:
+            context['required_model'] = requirement
+
         return render(request, self.template_name, {
             'obj_type': self.model_form._meta.model._meta.verbose_name,
             'form': form,

+ 10 - 2
netbox/netbox/views/generic/object_views.py

@@ -20,6 +20,7 @@ from utilities.permissions import get_permission_for_model
 from utilities.utils import get_viewname, normalize_querydict, prepare_cloned_fields
 from utilities.views import GetReturnURLMixin
 from .base import BaseObjectView
+from .utils import get_prerequisite_model
 
 __all__ = (
     'ComponentCreateView',
@@ -342,12 +343,19 @@ class ObjectEditView(GetReturnURLMixin, BaseObjectView):
         form = self.form(instance=obj, initial=initial_data)
         restrict_form_fields(form, request.user)
 
-        return render(request, self.template_name, {
+        context = {
             'object': obj,
             'form': form,
             'return_url': self.get_return_url(request, obj),
             **self.get_extra_context(request, obj),
-        })
+        }
+
+        requirement = get_prerequisite_model(self.queryset)
+        if requirement:
+            context['required_model'] = requirement
+            context['model'] = self.queryset.model
+
+        return render(request, self.template_name, context)
 
     def post(self, request, *args, **kwargs):
         """

+ 12 - 0
netbox/netbox/views/generic/utils.py

@@ -0,0 +1,12 @@
+def get_prerequisite_model(queryset):
+    requirement = None
+    model = queryset.model
+
+    if not queryset.count():
+        prerequisites = model.get_prerequisite_models()
+        if prerequisites:
+            for prereq in prerequisites:
+                if not prereq.objects.count():
+                    requirement = prereq
+
+    return requirement

+ 4 - 0
netbox/templates/generic/object_edit.html

@@ -40,6 +40,10 @@ Context:
         </div>
       {% endif %}
 
+      {% if required_model %}
+        {% include 'inc/missing_prerequisites.html' %}
+      {% endif %}
+
       <form action="" method="post" enctype="multipart/form-data" class="form-object-edit mt-5">
         {% csrf_token %}
 

+ 6 - 0
netbox/templates/generic/object_list.html

@@ -100,6 +100,12 @@ Context:
         <input type="hidden" name="return_url" value="{% if return_url %}{{ return_url }}{% else %}{{ request.path }}{% if request.GET %}?{{ request.GET.urlencode }}{% endif %}{% endif %}" />
 
         {# Object table #}
+
+            {% if required_model %}
+              {% include 'inc/missing_prerequisites.html' %}
+            {% endif %}
+
+
         <div class="card">
           <div class="card-body" id="object_list">
             {% include 'htmx/table.html' %}

+ 5 - 0
netbox/templates/inc/missing_prerequisites.html

@@ -0,0 +1,5 @@
+{% load buttons %}
+
+<div class="alert alert-warning" role="alert">
+  <i class="mdi mdi-alert"></i> <strong>Note:</strong> Before you can add a {{ model|meta:"verbose_name" }} you must first add a {{ required_model|meta:"verbose_name" }} here {% add_button required_model %}
+</div>