mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-31 06:33:20 +02:00
feat(dcim): Add device, module and rack count filters
Introduces `device_count`, `module_count` and `rack_count` filters to enable queries based on the existence and count of the associated device, module or rack instances. Updates forms, filtersets, and GraphQL schema to support these filters, along with tests for validation. Fixes #19523
This commit is contained in:
committed by
Jeremy Stretch
parent
01cbdbb968
commit
cee2a5e0ed
@@ -185,6 +185,10 @@ class DeviceType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
|
||||
to_model='dcim.InventoryItemTemplate',
|
||||
to_field='device_type'
|
||||
)
|
||||
device_count = CounterCacheField(
|
||||
to_model='dcim.Device',
|
||||
to_field='device_type'
|
||||
)
|
||||
|
||||
clone_fields = (
|
||||
'manufacturer', 'default_platform', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight',
|
||||
|
||||
@@ -13,8 +13,10 @@ from extras.models import ConfigContextModel, CustomField
|
||||
from netbox.models import PrimaryModel
|
||||
from netbox.models.features import ImageAttachmentsMixin
|
||||
from netbox.models.mixins import WeightMixin
|
||||
from utilities.fields import CounterCacheField
|
||||
from utilities.jsonschema import validate_schema
|
||||
from utilities.string import title
|
||||
from utilities.tracking import TrackingModelMixin
|
||||
from .device_components import *
|
||||
|
||||
__all__ = (
|
||||
@@ -92,6 +94,10 @@ class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
|
||||
null=True,
|
||||
verbose_name=_('attributes')
|
||||
)
|
||||
module_count = CounterCacheField(
|
||||
to_model='dcim.Module',
|
||||
to_field='module_type'
|
||||
)
|
||||
|
||||
clone_fields = ('profile', 'manufacturer', 'weight', 'weight_unit', 'airflow')
|
||||
prerequisite_models = (
|
||||
@@ -186,7 +192,7 @@ class ModuleType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
|
||||
return yaml.dump(dict(data), sort_keys=False)
|
||||
|
||||
|
||||
class Module(PrimaryModel, ConfigContextModel):
|
||||
class Module(TrackingModelMixin, PrimaryModel, ConfigContextModel):
|
||||
"""
|
||||
A Module represents a field-installable component within a Device which may itself hold multiple device components
|
||||
(for example, a line card within a chassis switch). Modules are instantiated from ModuleTypes.
|
||||
|
||||
@@ -19,9 +19,11 @@ from netbox.models.mixins import WeightMixin
|
||||
from netbox.models.features import ContactsMixin, ImageAttachmentsMixin
|
||||
from utilities.conversion import to_grams
|
||||
from utilities.data import array_to_string, drange
|
||||
from utilities.fields import ColorField
|
||||
from utilities.fields import ColorField, CounterCacheField
|
||||
from utilities.tracking import TrackingModelMixin
|
||||
from .device_components import PowerPort
|
||||
from .devices import Device, Module
|
||||
from .devices import Device
|
||||
from .modules import Module
|
||||
from .power import PowerFeed
|
||||
|
||||
__all__ = (
|
||||
@@ -144,6 +146,10 @@ class RackType(RackBase):
|
||||
max_length=100,
|
||||
unique=True
|
||||
)
|
||||
rack_count = CounterCacheField(
|
||||
to_model='dcim.Rack',
|
||||
to_field='rack_type'
|
||||
)
|
||||
|
||||
clone_fields = (
|
||||
'manufacturer', 'form_factor', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth',
|
||||
@@ -234,7 +240,7 @@ class RackRole(OrganizationalModel):
|
||||
verbose_name_plural = _('rack roles')
|
||||
|
||||
|
||||
class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
|
||||
class Rack(ContactsMixin, ImageAttachmentsMixin, TrackingModelMixin, RackBase):
|
||||
"""
|
||||
Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face.
|
||||
Each Rack is assigned to a Site and (optionally) a Location.
|
||||
@@ -509,7 +515,7 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
|
||||
|
||||
return [u for u in elevation.values()]
|
||||
|
||||
def get_available_units(self, u_height=1, rack_face=None, exclude=None, ignore_excluded_devices=False):
|
||||
def get_available_units(self, u_height=1.0, rack_face=None, exclude=None, ignore_excluded_devices=False):
|
||||
"""
|
||||
Return a list of units within the rack available to accommodate a device of a given U height (default 1).
|
||||
Optionally exclude one or more devices when calculating empty units (needed when moving a device from one
|
||||
@@ -581,9 +587,10 @@ class Rack(ContactsMixin, ImageAttachmentsMixin, RackBase):
|
||||
:param unit_height: Height of each rack unit for the rendered drawing. Note this is not the total
|
||||
height of the elevation
|
||||
:param legend_width: Width of the unit legend, in pixels
|
||||
:param margin_width: Width of the rigth-hand margin, in pixels
|
||||
:param margin_width: Width of the right-hand margin, in pixels
|
||||
:param include_images: Embed front/rear device images where available
|
||||
:param base_url: Base URL for links and images. If none, URLs will be relative.
|
||||
:param highlight_params: Dictionary of parameters to be passed to the RackElevationSVG.render_highlight() method
|
||||
"""
|
||||
elevation = RackElevationSVG(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user