Przeglądaj źródła

#6454 add prerequisite alert

Arthur 3 lat temu
rodzic
commit
928dff6b68

+ 5 - 0
netbox/circuits/models/circuits.py

@@ -1,3 +1,4 @@
+from django.apps import apps
 from django.contrib.contenttypes.fields import GenericRelation
 from django.contrib.contenttypes.fields import GenericRelation
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.db import models
@@ -129,6 +130,10 @@ class Circuit(NetBoxModel):
     def __str__(self):
     def __str__(self):
         return self.cid
         return self.cid
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [apps.get_model('circuits.Provider'), CircuitType]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('circuits:circuit', args=[self.pk])
         return reverse('circuits:circuit', args=[self.pk])
 
 

+ 14 - 0
netbox/dcim/models/devices.py

@@ -1,4 +1,6 @@
 import yaml
 import yaml
+
+from django.apps import apps
 from django.contrib.contenttypes.fields import GenericRelation
 from django.contrib.contenttypes.fields import GenericRelation
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.core.validators import MaxValueValidator, MinValueValidator
@@ -155,6 +157,10 @@ class DeviceType(NetBoxModel):
         self._original_front_image = self.front_image
         self._original_front_image = self.front_image
         self._original_rear_image = self.rear_image
         self._original_rear_image = self.rear_image
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [Manufacturer, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:devicetype', args=[self.pk])
         return reverse('dcim:devicetype', args=[self.pk])
 
 
@@ -328,6 +334,10 @@ class ModuleType(NetBoxModel):
     def __str__(self):
     def __str__(self):
         return self.model
         return self.model
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [Manufacturer, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:moduletype', args=[self.pk])
         return reverse('dcim:moduletype', args=[self.pk])
 
 
@@ -645,6 +655,10 @@ class Device(NetBoxModel, ConfigContextModel):
             return f'{self.device_type.manufacturer} {self.device_type.model} ({self.pk})'
             return f'{self.device_type.manufacturer} {self.device_type.model} ({self.pk})'
         return super().__str__()
         return super().__str__()
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [apps.get_model('dcim.Site'), DeviceRole, DeviceType, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:device', args=[self.pk])
         return reverse('dcim:device', args=[self.pk])
 
 

+ 9 - 0
netbox/dcim/models/power.py

@@ -1,3 +1,4 @@
+from django.apps import apps
 from django.contrib.contenttypes.fields import GenericRelation
 from django.contrib.contenttypes.fields import GenericRelation
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.core.validators import MaxValueValidator, MinValueValidator
 from django.core.validators import MaxValueValidator, MinValueValidator
@@ -54,6 +55,10 @@ class PowerPanel(NetBoxModel):
     def __str__(self):
     def __str__(self):
         return self.name
         return self.name
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [apps.get_model('dcim.Site'), ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:powerpanel', args=[self.pk])
         return reverse('dcim:powerpanel', args=[self.pk])
 
 
@@ -138,6 +143,10 @@ class PowerFeed(NetBoxModel, PathEndpoint, LinkTermination):
     def __str__(self):
     def __str__(self):
         return self.name
         return self.name
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [PowerPanel, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:powerfeed', args=[self.pk])
         return reverse('dcim:powerfeed', args=[self.pk])
 
 

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

@@ -473,6 +473,10 @@ class RackReservation(NetBoxModel):
     def __str__(self):
     def __str__(self):
         return "Reservation for rack {}".format(self.rack)
         return "Reservation for rack {}".format(self.rack)
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [apps.get_model('dcim.Site'), Rack, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:rackreservation', args=[self.pk])
         return reverse('dcim:rackreservation', args=[self.pk])
 
 

+ 4 - 0
netbox/dcim/models/sites.py

@@ -406,6 +406,10 @@ class Location(NestedGroupModel):
 
 
         super().validate_unique(exclude=exclude)
         super().validate_unique(exclude=exclude)
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [Site, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('dcim:location', args=[self.pk])
         return reverse('dcim:location', args=[self.pk])
 
 

+ 8 - 0
netbox/ipam/models/ip.py

@@ -124,6 +124,10 @@ class ASN(NetBoxModel):
     def __str__(self):
     def __str__(self):
         return f'AS{self.asn_with_asdot}'
         return f'AS{self.asn_with_asdot}'
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [RIR, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('ipam:asn', args=[self.pk])
         return reverse('ipam:asn', args=[self.pk])
 
 
@@ -185,6 +189,10 @@ class Aggregate(GetAvailablePrefixesMixin, NetBoxModel):
     def __str__(self):
     def __str__(self):
         return str(self.prefix)
         return str(self.prefix)
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [RIR, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('ipam:aggregate', args=[self.pk])
         return reverse('ipam:aggregate', args=[self.pk])
 
 

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

@@ -89,6 +89,10 @@ class NestedGroupModel(NetBoxFeatureSet, MPTTModel):
     def __str__(self):
     def __str__(self):
         return self.name
         return self.name
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return []
+
     def clean(self):
     def clean(self):
         super().clean()
         super().clean()
 
 
@@ -126,3 +130,7 @@ class OrganizationalModel(NetBoxFeatureSet, models.Model):
     class Meta:
     class Meta:
         abstract = True
         abstract = True
         ordering = ('name',)
         ordering = ('name',)
+
+    @classmethod
+    def get_prerequisite_models(cls):
+        return []

+ 7 - 7
netbox/netbox/views/generic/utils.py

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

+ 2 - 1
netbox/templates/inc/missing_prerequisites.html

@@ -1,5 +1,6 @@
 {% load buttons %}
 {% load buttons %}
 
 
 <div class="alert alert-warning" role="alert">
 <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 %}
+  <i class="mdi mdi-alert"></i> <strong>Note:</strong> Before you can add a {{ model|meta:"verbose_name" }} you must first create a
+    <strong>{{ required_model|meta:"verbose_name"|title }}</strong> which can be added here: {% add_button required_model %}
 </div>
 </div>

+ 8 - 0
netbox/virtualization/models.py

@@ -162,6 +162,10 @@ class Cluster(NetBoxModel):
     def __str__(self):
     def __str__(self):
         return self.name
         return self.name
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [ClusterType, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('virtualization:cluster', args=[self.pk])
         return reverse('virtualization:cluster', args=[self.pk])
 
 
@@ -288,6 +292,10 @@ class VirtualMachine(NetBoxModel, ConfigContextModel):
     def __str__(self):
     def __str__(self):
         return self.name
         return self.name
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [Cluster, ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('virtualization:virtualmachine', args=[self.pk])
         return reverse('virtualization:virtualmachine', args=[self.pk])
 
 

+ 5 - 0
netbox/wireless/models.py

@@ -1,3 +1,4 @@
+from django.apps import apps
 from django.core.exceptions import ValidationError
 from django.core.exceptions import ValidationError
 from django.db import models
 from django.db import models
 from django.urls import reverse
 from django.urls import reverse
@@ -174,6 +175,10 @@ class WirelessLink(WirelessAuthenticationBase, NetBoxModel):
     def __str__(self):
     def __str__(self):
         return f'#{self.pk}'
         return f'#{self.pk}'
 
 
+    @classmethod
+    def get_prerequisite_models(cls):
+        return [apps.get_model('dcim.Interface'), ]
+
     def get_absolute_url(self):
     def get_absolute_url(self):
         return reverse('wireless:wirelesslink', args=[self.pk])
         return reverse('wireless:wirelesslink', args=[self.pk])