diff --git a/docs/api/overview.md b/docs/api/overview.md index ba7e11bbf..85d972008 100644 --- a/docs/api/overview.md +++ b/docs/api/overview.md @@ -206,3 +206,28 @@ The maximum number of objects that can be returned is limited by the [`MAX_PAGE_ !!! warning Disabling the page size limit introduces a potential for very resource-intensive requests, since one API request can effectively retrieve an entire table from the database. + +# Filtering + +A list of objects retrieved via the API can be filtered by passing one or more query parameters. The same parameters used by the web UI work for the API as well. For example, to return only prefixes with a status of "Active" (`1`): + +``` +GET /api/ipam/prefixes/?status=1 +``` + +The same filter can be incldued multiple times. These will effect a logical OR and return objects matching any of the given values. For example, the following will return all active and reserved prefixes: + +``` +GET /api/ipam/prefixes/?status=1&status=2 +``` + +## Custom Fields + +To filter on a custom field, prepend `cf_` to the field name. For example, the following query will return only sites where a custom field named `foo` is equal to 123: + +``` +GET /api/dcim/sites/?cf_foo=123 +``` + +!!! note + Full versus partial matching when filtering is configurable per custom field. Filtering can be toggled (or disabled) for a custom field in the admin UI. diff --git a/docs/data-model/dcim.md b/docs/data-model/dcim.md index 3cb3ed13e..5c9097569 100644 --- a/docs/data-model/dcim.md +++ b/docs/data-model/dcim.md @@ -42,6 +42,8 @@ A device type represents a particular hardware model that exists in the real wor Device types are instantiated as devices installed within racks. For example, you might define a device type to represent a Juniper EX4300-48T network switch with 48 Ethernet interfaces. You can then create multiple devices of this type named "switch1," "switch2," and so on. Each device will inherit the components (such as interfaces) of its device type. +A device type can be a parent, child, or neither. Parent devices house child devices in device bays. This relationship is used to model things like blade servers, where child devices function independently but share physical resources like rack space and power. Note that this is **not** intended to model chassis-based devices, wherein child members share a common control plane. + ### Manufacturers Each device type belongs to one manufacturer; e.g. Cisco, Opengear, or APC. The model number of a device type must be unique to its manufacturer. diff --git a/docs/installation/ldap.md b/docs/installation/ldap.md index 8eb4acc4d..8f4501d57 100644 --- a/docs/installation/ldap.md +++ b/docs/installation/ldap.md @@ -81,7 +81,7 @@ AUTH_LDAP_USER_ATTR_MAP = { # User Groups for Permissions !!! info - When using Microsoft Active Directory, support for nested groups can be activated by using `NestedGroupOfNamesType()` instead of `GroupOfNamesType()` for `AUTH_LDAP_GROUP_TYPE`. + When using Microsoft Active Directory, support for nested groups can be activated by using `NestedGroupOfNamesType()` instead of `GroupOfNamesType()` for `AUTH_LDAP_GROUP_TYPE`. You will also need to modify the import line to use `NestedGroupOfNamesType` instead of `GroupOfNamesType` . ```python from django_auth_ldap.config import LDAPSearch, GroupOfNamesType diff --git a/docs/miscellaneous/reports.md b/docs/miscellaneous/reports.md index daffa72ae..234766639 100644 --- a/docs/miscellaneous/reports.md +++ b/docs/miscellaneous/reports.md @@ -32,7 +32,7 @@ class DeviceIPsReport(Report): Within each report class, we'll create a number of test methods to execute our report's logic. In DeviceConnectionsReport, for instance, we want to ensure that every live device has a console connection, an out-of-band management connection, and two power connections. ``` -from dcim.constants import CONNECTION_STATUS_PLANNED, STATUS_ACTIVE +from dcim.constants import CONNECTION_STATUS_PLANNED, DEVICE_STATUS_ACTIVE from dcim.models import ConsolePort, Device, PowerPort from extras.reports import Report @@ -43,7 +43,7 @@ class DeviceConnectionsReport(Report): def test_console_connection(self): # Check that every console port for every active device has a connection defined. - for console_port in ConsolePort.objects.select_related('device').filter(device__status=STATUS_ACTIVE): + for console_port in ConsolePort.objects.select_related('device').filter(device__status=DEVICE_STATUS_ACTIVE): if console_port.cs_port is None: self.log_failure( console_port.device, @@ -60,7 +60,7 @@ class DeviceConnectionsReport(Report): def test_power_connections(self): # Check that every active device has at least two connected power supplies. - for device in Device.objects.filter(status=STATUS_ACTIVE): + for device in Device.objects.filter(status=DEVICE_STATUS_ACTIVE): connected_ports = 0 for power_port in PowerPort.objects.filter(device=device): if power_port.power_outlet is not None: diff --git a/netbox/dcim/forms.py b/netbox/dcim/forms.py index a159e19e4..0ff58918b 100644 --- a/netbox/dcim/forms.py +++ b/netbox/dcim/forms.py @@ -1812,8 +1812,9 @@ class InterfaceAssignVLANsForm(BootstrapMixin, forms.ModelForm): if parent is not None: # Add site VLANs - site_vlans = VLAN.objects.filter(site=parent.site, group=None).exclude(pk__in=assigned_vlans) - vlan_choices.append((parent.site.name, [(vlan.pk, vlan) for vlan in site_vlans])) + if parent.site: + site_vlans = VLAN.objects.filter(site=parent.site, group=None).exclude(pk__in=assigned_vlans) + vlan_choices.append((parent.site.name, [(vlan.pk, vlan) for vlan in site_vlans])) # Add grouped site VLANs for group in VLANGroup.objects.filter(site=parent.site): diff --git a/netbox/dcim/views.py b/netbox/dcim/views.py index 737a33977..4cd302084 100644 --- a/netbox/dcim/views.py +++ b/netbox/dcim/views.py @@ -2101,7 +2101,7 @@ class InventoryItemBulkDeleteView(PermissionRequiredMixin, BulkDeleteView): # class VirtualChassisListView(ObjectListView): - queryset = VirtualChassis.objects.annotate(member_count=Count('members')) + queryset = VirtualChassis.objects.select_related('master').annotate(member_count=Count('members')) table = tables.VirtualChassisTable filter = filters.VirtualChassisFilter filter_form = forms.VirtualChassisFilterForm diff --git a/netbox/netbox/forms.py b/netbox/netbox/forms.py index caa074e18..5611f49f9 100644 --- a/netbox/netbox/forms.py +++ b/netbox/netbox/forms.py @@ -15,6 +15,7 @@ OBJ_TYPE_CHOICES = ( ('rack', 'Racks'), ('devicetype', 'Device types'), ('device', 'Devices'), + ('virtualchassis', 'Virtual Chassis'), )), ('IPAM', ( ('vrf', 'VRFs'), diff --git a/netbox/netbox/views.py b/netbox/netbox/views.py index 48b72050a..1e3433016 100644 --- a/netbox/netbox/views.py +++ b/netbox/netbox/views.py @@ -12,9 +12,9 @@ from rest_framework.views import APIView from circuits.filters import CircuitFilter, ProviderFilter from circuits.models import Circuit, Provider from circuits.tables import CircuitTable, ProviderTable -from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter -from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site -from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable +from dcim.filters import DeviceFilter, DeviceTypeFilter, RackFilter, SiteFilter, VirtualChassisFilter +from dcim.models import ConsolePort, Device, DeviceType, InterfaceConnection, PowerPort, Rack, Site, VirtualChassis +from dcim.tables import DeviceDetailTable, DeviceTypeTable, RackTable, SiteTable, VirtualChassisTable from extras.models import ObjectChange, ReportResult, TopologyMap from ipam.filters import AggregateFilter, IPAddressFilter, PrefixFilter, VLANFilter, VRFFilter from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF @@ -72,6 +72,12 @@ SEARCH_TYPES = OrderedDict(( 'table': DeviceDetailTable, 'url': 'dcim:device_list', }), + ('virtualchassis', { + 'queryset': VirtualChassis.objects.select_related('master').annotate(member_count=Count('members')), + 'filter': VirtualChassisFilter, + 'table': VirtualChassisTable, + 'url': 'dcim:virtualchassis_list', + }), # IPAM ('vrf', { 'queryset': VRF.objects.select_related('tenant'), diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index d0751f363..348fc9ef2 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -459,6 +459,7 @@ {% endif %} Name + Status Installed Device diff --git a/netbox/templates/dcim/inc/devicebay.html b/netbox/templates/dcim/inc/devicebay.html index 4e17e3d36..656116c89 100644 --- a/netbox/templates/dcim/inc/devicebay.html +++ b/netbox/templates/dcim/inc/devicebay.html @@ -8,6 +8,9 @@ {{ devicebay.name }} {% if devicebay.installed_device %} + + {{ devicebay.installed_device.get_status_display }} + {{ devicebay.installed_device }} @@ -15,6 +18,7 @@ {{ devicebay.installed_device.device_type.full_name }} {% else %} + Vacant diff --git a/requirements.txt b/requirements.txt index 6a4e3e7b3..f50f96e33 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,7 @@ Django>=1.11 django-cors-headers>=2.1.0 django-debug-toolbar>=1.9.0 -django-filter>=1.1.0 +django-filter==1.1.0 django-mptt>=0.9.0 django-tables2>=1.19.0 django-taggit>=0.22.2