mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Use strings to specify prerequisite models
This commit is contained in:
@ -104,6 +104,10 @@ class Circuit(PrimaryModel):
|
||||
clone_fields = (
|
||||
'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate', 'description',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'circuits.CircuitType',
|
||||
'circuits.Provider',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['provider', 'cid']
|
||||
@ -117,10 +121,6 @@ class Circuit(PrimaryModel):
|
||||
def __str__(self):
|
||||
return self.cid
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [apps.get_model('circuits.Provider'), CircuitType]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('circuits:circuit', args=[self.pk])
|
||||
|
||||
|
@ -124,6 +124,9 @@ class DeviceType(PrimaryModel, WeightMixin):
|
||||
clone_fields = (
|
||||
'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit'
|
||||
)
|
||||
prerequisite_models = (
|
||||
'dcim.Manufacturer',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['manufacturer', 'model']
|
||||
@ -151,10 +154,6 @@ class DeviceType(PrimaryModel, WeightMixin):
|
||||
self._original_front_image = self.front_image
|
||||
self._original_rear_image = self.rear_image
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [Manufacturer, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dcim:devicetype', args=[self.pk])
|
||||
|
||||
@ -325,6 +324,9 @@ class ModuleType(PrimaryModel, WeightMixin):
|
||||
)
|
||||
|
||||
clone_fields = ('manufacturer', 'weight', 'weight_unit',)
|
||||
prerequisite_models = (
|
||||
'dcim.Manufacturer',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('manufacturer', 'model')
|
||||
@ -338,10 +340,6 @@ class ModuleType(PrimaryModel, WeightMixin):
|
||||
def __str__(self):
|
||||
return self.model
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [Manufacturer, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dcim:moduletype', args=[self.pk])
|
||||
|
||||
@ -599,6 +597,11 @@ class Device(PrimaryModel, ConfigContextModel):
|
||||
'device_type', 'device_role', 'tenant', 'platform', 'site', 'location', 'rack', 'face', 'status', 'airflow',
|
||||
'cluster', 'virtual_chassis',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'dcim.Site',
|
||||
'dcim.DeviceRole',
|
||||
'dcim.DeviceType',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('_name', 'pk') # Name may be null
|
||||
@ -638,10 +641,6 @@ class Device(PrimaryModel, ConfigContextModel):
|
||||
return f'{self.device_type.manufacturer} {self.device_type.model} ({self.pk})'
|
||||
return super().__str__()
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [apps.get_model('dcim.Site'), DeviceRole, DeviceType, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dcim:device', args=[self.pk])
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
from django.apps import apps
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
@ -48,6 +47,10 @@ class PowerPanel(PrimaryModel):
|
||||
to='extras.ImageAttachment'
|
||||
)
|
||||
|
||||
prerequisite_models = (
|
||||
'dcim.Site',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['site', 'name']
|
||||
constraints = (
|
||||
@ -60,10 +63,6 @@ class PowerPanel(PrimaryModel):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [apps.get_model('dcim.Site'), ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dcim:powerpanel', args=[self.pk])
|
||||
|
||||
@ -137,6 +136,9 @@ class PowerFeed(PrimaryModel, PathEndpoint, CabledObjectModel):
|
||||
'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',
|
||||
'max_utilization',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'dcim.PowerPanel',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['power_panel', 'name']
|
||||
@ -150,10 +152,6 @@ class PowerFeed(PrimaryModel, PathEndpoint, CabledObjectModel):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [PowerPanel, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dcim:powerfeed', args=[self.pk])
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
import decimal
|
||||
from functools import cached_property
|
||||
|
||||
from django.apps import apps
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.contrib.postgres.fields import ArrayField
|
||||
@ -177,6 +176,9 @@ class Rack(PrimaryModel, WeightMixin):
|
||||
'site', 'location', 'tenant', 'status', 'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
|
||||
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'weight_unit',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'dcim.Site',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('site', 'location', '_name', 'pk') # (site, location, name) may be non-unique
|
||||
@ -197,10 +199,6 @@ class Rack(PrimaryModel, WeightMixin):
|
||||
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])
|
||||
|
||||
@ -488,16 +486,16 @@ class RackReservation(PrimaryModel):
|
||||
max_length=200
|
||||
)
|
||||
|
||||
prerequisite_models = (
|
||||
'dcim.Rack',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['created', 'pk']
|
||||
|
||||
def __str__(self):
|
||||
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):
|
||||
return reverse('dcim:rackreservation', args=[self.pk])
|
||||
|
||||
|
@ -286,6 +286,9 @@ class Location(NestedGroupModel):
|
||||
)
|
||||
|
||||
clone_fields = ('site', 'parent', 'status', 'tenant', 'description')
|
||||
prerequisite_models = (
|
||||
'dcim.Site',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['site', 'name']
|
||||
@ -312,10 +315,6 @@ class Location(NestedGroupModel):
|
||||
),
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [Site, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('dcim:location', args=[self.pk])
|
||||
|
||||
|
@ -10,7 +10,6 @@ from django.utils.translation import gettext as _
|
||||
|
||||
from dcim.fields import ASNField
|
||||
from dcim.models import Device
|
||||
from netbox.models import OrganizationalModel, PrimaryModel
|
||||
from ipam.choices import *
|
||||
from ipam.constants import *
|
||||
from ipam.fields import IPNetworkField, IPAddressField
|
||||
@ -18,9 +17,9 @@ from ipam.managers import IPAddressManager
|
||||
from ipam.querysets import PrefixQuerySet
|
||||
from ipam.validators import DNSValidator
|
||||
from netbox.config import get_config
|
||||
from netbox.models import OrganizationalModel, PrimaryModel
|
||||
from virtualization.models import VirtualMachine
|
||||
|
||||
|
||||
__all__ = (
|
||||
'Aggregate',
|
||||
'ASN',
|
||||
@ -101,6 +100,10 @@ class ASN(PrimaryModel):
|
||||
null=True
|
||||
)
|
||||
|
||||
prerequisite_models = (
|
||||
'ipam.RIR',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['asn']
|
||||
verbose_name = 'ASN'
|
||||
@ -109,10 +112,6 @@ class ASN(PrimaryModel):
|
||||
def __str__(self):
|
||||
return f'AS{self.asn_with_asdot}'
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [RIR, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('ipam:asn', args=[self.pk])
|
||||
|
||||
@ -163,6 +162,9 @@ class Aggregate(GetAvailablePrefixesMixin, PrimaryModel):
|
||||
clone_fields = (
|
||||
'rir', 'tenant', 'date_added', 'description',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'ipam.RIR',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('prefix', 'pk') # prefix may be non-unique
|
||||
@ -170,10 +172,6 @@ class Aggregate(GetAvailablePrefixesMixin, PrimaryModel):
|
||||
def __str__(self):
|
||||
return str(self.prefix)
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [RIR, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('ipam:aggregate', args=[self.pk])
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
from django.apps import apps
|
||||
from django.contrib.contenttypes.fields import GenericRelation, GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import ValidationError
|
||||
@ -95,6 +94,9 @@ class L2VPNTermination(NetBoxModel):
|
||||
)
|
||||
|
||||
clone_fields = ('l2vpn',)
|
||||
prerequisite_models = (
|
||||
'ipam.L2VPN',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('l2vpn',)
|
||||
@ -111,10 +113,6 @@ class L2VPNTermination(NetBoxModel):
|
||||
return f'{self.assigned_object} <> {self.l2vpn}'
|
||||
return super().__str__()
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [apps.get_model('ipam.L2VPN'), ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('ipam:l2vpntermination', args=[self.pk])
|
||||
|
||||
|
@ -3,9 +3,9 @@ from django.core.validators import ValidationError
|
||||
from django.db import models
|
||||
from mptt.models import MPTTModel, TreeForeignKey
|
||||
|
||||
from netbox.models.features import *
|
||||
from utilities.mptt import TreeManager
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from netbox.models.features import *
|
||||
|
||||
__all__ = (
|
||||
'ChangeLoggedModel',
|
||||
@ -33,14 +33,6 @@ class NetBoxFeatureSet(
|
||||
def docs_url(self):
|
||||
return f'{settings.STATIC_URL}docs/models/{self._meta.app_label}/{self._meta.model_name}/'
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
"""
|
||||
Return a list of model types that are required to create this model or empty list if none. This is used for
|
||||
showing prerequisite warnings in the UI on the list and detail views.
|
||||
"""
|
||||
return []
|
||||
|
||||
|
||||
#
|
||||
# Base model classes
|
||||
|
@ -1,12 +1,13 @@
|
||||
from django.apps import apps
|
||||
|
||||
|
||||
def get_prerequisite_model(queryset):
|
||||
model = queryset.model
|
||||
|
||||
"""
|
||||
Return any prerequisite model that must be created prior to creating
|
||||
an instance of the current model.
|
||||
"""
|
||||
if not queryset.exists():
|
||||
if hasattr(model, 'get_prerequisite_models'):
|
||||
prerequisites = model.get_prerequisite_models()
|
||||
if prerequisites:
|
||||
for prereq in prerequisites:
|
||||
if not prereq.objects.exists():
|
||||
return prereq
|
||||
|
||||
return None
|
||||
for prereq in getattr(queryset.model, 'prerequisite_models', []):
|
||||
model = apps.get_model(prereq)
|
||||
if not model.objects.exists():
|
||||
return model
|
||||
|
@ -94,6 +94,9 @@ class Cluster(PrimaryModel):
|
||||
clone_fields = (
|
||||
'type', 'group', 'status', 'tenant', 'site',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'virtualization.ClusterType',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ['name']
|
||||
@ -111,10 +114,6 @@ class Cluster(PrimaryModel):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [ClusterType, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('virtualization:cluster', args=[self.pk])
|
||||
|
||||
|
@ -15,7 +15,6 @@ from utilities.fields import NaturalOrderingField
|
||||
from utilities.ordering import naturalize_interface
|
||||
from utilities.query_functions import CollateAsChar
|
||||
from virtualization.choices import *
|
||||
from .clusters import Cluster
|
||||
|
||||
__all__ = (
|
||||
'VirtualMachine',
|
||||
@ -131,6 +130,9 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
clone_fields = (
|
||||
'site', 'cluster', 'device', 'tenant', 'platform', 'status', 'role', 'vcpus', 'memory', 'disk',
|
||||
)
|
||||
prerequisite_models = (
|
||||
'virtualization.Cluster',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('_name', 'pk') # Name may be non-unique
|
||||
@ -150,10 +152,6 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [Cluster, ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('virtualization:virtualmachine', args=[self.pk])
|
||||
|
||||
|
@ -1,4 +1,3 @@
|
||||
from django.apps import apps
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
@ -193,10 +192,6 @@ class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
|
||||
def __str__(self):
|
||||
return f'#{self.pk}'
|
||||
|
||||
@classmethod
|
||||
def get_prerequisite_models(cls):
|
||||
return [apps.get_model('dcim.Interface'), ]
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('wireless:wirelesslink', args=[self.pk])
|
||||
|
||||
|
Reference in New Issue
Block a user