mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-25 08:46:10 -06:00
Merge branch 'feature' into 4347-json-import
This commit is contained in:
commit
d9306d827f
3
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
3
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v3.3.4
|
placeholder: v3.3.7
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
@ -25,6 +25,7 @@ body:
|
|||||||
- "3.8"
|
- "3.8"
|
||||||
- "3.9"
|
- "3.9"
|
||||||
- "3.10"
|
- "3.10"
|
||||||
|
- "3.11"
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: textarea
|
- type: textarea
|
||||||
|
14
.github/ISSUE_TEMPLATE/documentation_change.yaml
vendored
14
.github/ISSUE_TEMPLATE/documentation_change.yaml
vendored
@ -19,11 +19,15 @@ body:
|
|||||||
label: Area
|
label: Area
|
||||||
description: To what section of the documentation does this change primarily pertain?
|
description: To what section of the documentation does this change primarily pertain?
|
||||||
options:
|
options:
|
||||||
- Installation instructions
|
- Features
|
||||||
- Configuration parameters
|
- Installation/upgrade
|
||||||
- Functionality/features
|
- Getting started
|
||||||
- REST API
|
- Configuration
|
||||||
- Administration/development
|
- Customization
|
||||||
|
- Integrations/API
|
||||||
|
- Plugins
|
||||||
|
- Administration
|
||||||
|
- Development
|
||||||
- Other
|
- Other
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
|
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
2
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@ -14,7 +14,7 @@ body:
|
|||||||
attributes:
|
attributes:
|
||||||
label: NetBox version
|
label: NetBox version
|
||||||
description: What version of NetBox are you currently running?
|
description: What version of NetBox are you currently running?
|
||||||
placeholder: v3.3.4
|
placeholder: v3.3.7
|
||||||
validations:
|
validations:
|
||||||
required: true
|
required: true
|
||||||
- type: dropdown
|
- type: dropdown
|
||||||
|
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,13 +1,14 @@
|
|||||||
<!--
|
<!--
|
||||||
Thank you for your interest in contributing to NetBox! Please note that
|
Thank you for your interest in contributing to NetBox! Please note that
|
||||||
our contribution policy requires that a feature request or bug report be
|
our contribution policy requires that a feature request or bug report be
|
||||||
approved and assigned prior to filing a pull request. This helps avoid
|
approved and assigned prior to opening a pull request. This helps avoid
|
||||||
wasting time and effort on something that we might not be able to accept.
|
waste time and effort on a proposed change that we might not be able to
|
||||||
|
accept.
|
||||||
|
|
||||||
IF YOUR PULL REQUEST DOES NOT REFERENCE AN ISSUE WHICH HAS BEEN ASSIGNED
|
IF YOUR PULL REQUEST DOES NOT REFERENCE AN ISSUE WHICH HAS BEEN ASSIGNED
|
||||||
TO YOU, IT WE BE CLOSED AUTOMATICALLY.
|
TO YOU, IT WILL BE CLOSED AUTOMATICALLY.
|
||||||
|
|
||||||
Specify your assigned issue number on the line below.
|
Please specify your assigned issue number on the line below.
|
||||||
-->
|
-->
|
||||||
### Fixes: #1234
|
### Fixes: #1234
|
||||||
|
|
||||||
|
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -1,5 +1,7 @@
|
|||||||
name: CI
|
name: CI
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@ -7,7 +9,7 @@ jobs:
|
|||||||
NETBOX_CONFIGURATION: netbox.configuration_testing
|
NETBOX_CONFIGURATION: netbox.configuration_testing
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
python-version: ['3.8', '3.9', '3.10']
|
python-version: ['3.8', '3.9', '3.10', '3.11']
|
||||||
node-version: ['14.x']
|
node-version: ['14.x']
|
||||||
services:
|
services:
|
||||||
redis:
|
redis:
|
||||||
|
6
.github/workflows/lock.yml
vendored
6
.github/workflows/lock.yml
vendored
@ -4,6 +4,11 @@ name: 'Lock threads'
|
|||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 3 * * *'
|
- cron: '0 3 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lock:
|
lock:
|
||||||
@ -11,7 +16,6 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: dessant/lock-threads@v3
|
- uses: dessant/lock-threads@v3
|
||||||
with:
|
with:
|
||||||
github-token: ${{ github.token }}
|
|
||||||
issue-inactive-days: 90
|
issue-inactive-days: 90
|
||||||
pr-inactive-days: 30
|
pr-inactive-days: 30
|
||||||
issue-lock-reason: 'resolved'
|
issue-lock-reason: 'resolved'
|
||||||
|
9
.github/workflows/stale.yml
vendored
9
.github/workflows/stale.yml
vendored
@ -1,14 +1,21 @@
|
|||||||
# close-stale-issues (https://github.com/marketplace/actions/close-stale-issues)
|
# close-stale-issues (https://github.com/marketplace/actions/close-stale-issues)
|
||||||
name: 'Close stale issues/PRs'
|
name: 'Close stale issues/PRs'
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 4 * * *'
|
- cron: '0 4 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v5
|
- uses: actions/stale@v6
|
||||||
with:
|
with:
|
||||||
close-issue-message: >
|
close-issue-message: >
|
||||||
This issue has been automatically closed due to lack of activity. In an
|
This issue has been automatically closed due to lack of activity. In an
|
||||||
|
@ -68,7 +68,7 @@ drf-yasg[validation]
|
|||||||
|
|
||||||
# Django wrapper for Graphene (GraphQL support)
|
# Django wrapper for Graphene (GraphQL support)
|
||||||
# https://github.com/graphql-python/graphene-django
|
# https://github.com/graphql-python/graphene-django
|
||||||
graphene_django
|
graphene_django<3.0
|
||||||
|
|
||||||
# WSGI HTTP server
|
# WSGI HTTP server
|
||||||
# https://gunicorn.org/
|
# https://gunicorn.org/
|
||||||
@ -80,7 +80,8 @@ Jinja2
|
|||||||
|
|
||||||
# Simple markup language for rendering HTML
|
# Simple markup language for rendering HTML
|
||||||
# https://github.com/Python-Markdown/markdown
|
# https://github.com/Python-Markdown/markdown
|
||||||
Markdown
|
# mkdocs currently requires Markdown v3.3
|
||||||
|
Markdown<3.4
|
||||||
|
|
||||||
# File inclusion plugin for Python-Markdown
|
# File inclusion plugin for Python-Markdown
|
||||||
# https://github.com/cmacmackin/markdown-include
|
# https://github.com/cmacmackin/markdown-include
|
||||||
|
4
docs/_theme/main.html
vendored
4
docs/_theme/main.html
vendored
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
{% block site_meta %}
|
{% block site_meta %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
{# Disable search indexing unless we're building for ReadTheDocs #}
|
{# Disable search indexing unless we're building for ReadTheDocs (see #10496) #}
|
||||||
{% if not config.extra.readthedocs %}
|
{% if page.canonical_url != 'https://docs.netbox.dev/' %}
|
||||||
<meta name="robots" content="noindex">
|
<meta name="robots" content="noindex">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -1,5 +1,13 @@
|
|||||||
# Security & Authentication Parameters
|
# Security & Authentication Parameters
|
||||||
|
|
||||||
|
## ALLOW_TOKEN_RETRIEVAL
|
||||||
|
|
||||||
|
Default: True
|
||||||
|
|
||||||
|
If disabled, the values of API tokens will not be displayed after each token's initial creation. A user **must** record the value of a token immediately upon its creation, or it will be lost. Note that this affects _all_ users, regardless of assigned permissions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## ALLOWED_URL_SCHEMES
|
## ALLOWED_URL_SCHEMES
|
||||||
|
|
||||||
!!! tip "Dynamic Configuration Parameter"
|
!!! tip "Dynamic Configuration Parameter"
|
||||||
|
@ -157,6 +157,14 @@ The file path to the location where [custom scripts](../customization/custom-scr
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## SEARCH_BACKEND
|
||||||
|
|
||||||
|
Default: `'netbox.search.backends.CachedValueSearchBackend'`
|
||||||
|
|
||||||
|
The dotted path to the desired search backend class. `CachedValueSearchBackend` is currently the only search backend provided in NetBox, however this setting can be used to enable a custom backend.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## STORAGE_BACKEND
|
## STORAGE_BACKEND
|
||||||
|
|
||||||
Default: None (local storage)
|
Default: None (local storage)
|
||||||
|
@ -13,6 +13,7 @@ Custom fields may be created by navigating to Customization > Custom Fields. Net
|
|||||||
* Text: Free-form text (intended for single-line use)
|
* Text: Free-form text (intended for single-line use)
|
||||||
* Long text: Free-form of any length; supports Markdown rendering
|
* Long text: Free-form of any length; supports Markdown rendering
|
||||||
* Integer: A whole number (positive or negative)
|
* Integer: A whole number (positive or negative)
|
||||||
|
* Decimal: A fixed-precision decimal number (4 decimal places)
|
||||||
* Boolean: True or false
|
* Boolean: True or false
|
||||||
* Date: A date in ISO 8601 format (YYYY-MM-DD)
|
* Date: A date in ISO 8601 format (YYYY-MM-DD)
|
||||||
* URL: This will be presented as a link in the web UI
|
* URL: This will be presented as a link in the web UI
|
||||||
|
@ -267,7 +267,7 @@ An IPv4 or IPv6 network with a mask. Returns a `netaddr.IPNetwork` object. Two a
|
|||||||
|
|
||||||
### Via the Web UI
|
### Via the Web UI
|
||||||
|
|
||||||
Custom scripts can be run via the web UI by navigating to the script, completing any required form data, and clicking the "run script" button.
|
Custom scripts can be run via the web UI by navigating to the script, completing any required form data, and clicking the "run script" button. It is possible to schedule a script to be executed at specified time in the future. A scheduled script can be canceled by deleting the associated job result object.
|
||||||
|
|
||||||
### Via the API
|
### Via the API
|
||||||
|
|
||||||
@ -282,6 +282,8 @@ http://netbox/api/extras/scripts/example.MyReport/ \
|
|||||||
--data '{"data": {"foo": "somevalue", "bar": 123}, "commit": true}'
|
--data '{"data": {"foo": "somevalue", "bar": 123}, "commit": true}'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Optionally `schedule_at` can be passed in the form data with a datetime string to schedule a script at the specified date and time.
|
||||||
|
|
||||||
### Via the CLI
|
### Via the CLI
|
||||||
|
|
||||||
Scripts can be run on the CLI by invoking the management command:
|
Scripts can be run on the CLI by invoking the management command:
|
||||||
|
@ -136,7 +136,7 @@ Once you have created a report, it will appear in the reports list. Initially, r
|
|||||||
|
|
||||||
### Via the Web UI
|
### Via the Web UI
|
||||||
|
|
||||||
Reports can be run via the web UI by navigating to the report and clicking the "run report" button at top right. Once a report has been run, its associated results will be included in the report view.
|
Reports can be run via the web UI by navigating to the report and clicking the "run report" button at top right. Once a report has been run, its associated results will be included in the report view. It is possible to schedule a report to be executed at specified time in the future. A scheduled report can be canceled by deleting the associated job result object.
|
||||||
|
|
||||||
### Via the API
|
### Via the API
|
||||||
|
|
||||||
@ -152,6 +152,8 @@ Our example report above would be called as:
|
|||||||
POST /api/extras/reports/devices.DeviceConnectionsReport/run/
|
POST /api/extras/reports/devices.DeviceConnectionsReport/run/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Optionally `schedule_at` can be passed in the form data with a datetime string to schedule a script at the specified date and time.
|
||||||
|
|
||||||
### Via the CLI
|
### Via the CLI
|
||||||
|
|
||||||
Reports can be run on the CLI by invoking the management command:
|
Reports can be run on the CLI by invoking the management command:
|
||||||
|
37
docs/development/search.md
Normal file
37
docs/development/search.md
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# Search
|
||||||
|
|
||||||
|
NetBox v3.4 introduced a new global search mechanism, which employs the `extras.CachedValue` model to store discrete field values from many models in a single table.
|
||||||
|
|
||||||
|
## SearchIndex
|
||||||
|
|
||||||
|
To enable search support for a model, declare and register a subclass of `netbox.search.SearchIndex` for it. Typically, this will be done within an app's `search.py` module.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from netbox.search import SearchIndex, register_search
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class MyModelIndex(SearchIndex):
|
||||||
|
model = MyModel
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('description', 500),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
A SearchIndex subclass defines both its model and a list of two-tuples specifying which model fields to be indexed and the weight (precedence) associated with each. Guidance on weight assignment for fields is provided below.
|
||||||
|
|
||||||
|
### Field Weight Guidance
|
||||||
|
|
||||||
|
| Weight | Field Role | Examples |
|
||||||
|
|--------|--------------------------------------------------|----------------------------------------------------|
|
||||||
|
| 50 | Unique serialized attribute | Device.asset_tag |
|
||||||
|
| 60 | Unique serialized attribute (per related object) | Device.serial |
|
||||||
|
| 100 | Primary human identifier | Device.name, Circuit.cid, Cable.label |
|
||||||
|
| 110 | Slug | Site.slug |
|
||||||
|
| 200 | Secondary identifier | Provider.account, DeviceType.part_number |
|
||||||
|
| 300 | Highly unique descriptive attribute | CircuitTermination.xconnect_id, IPAddress.dns_name |
|
||||||
|
| 500 | Description | Site.description |
|
||||||
|
| 1000 | Custom field default | - |
|
||||||
|
| 2000 | Other discrete attribute | CircuitTermination.port_speed |
|
||||||
|
| 5000 | Comment field | Site.comments |
|
@ -1,5 +1,5 @@
|
|||||||
# Journaling
|
# Journaling
|
||||||
|
|
||||||
All primary objects in NetBox support journaling. A journal is a collection of human-generated notes and comments about an object maintained for historical context. It supplements NetBox's change log to provide additional information about why changes have been made or to convey events which occur outside NetBox. Unlike the change log, in which records typically expire after a configurable period of time, journal entries persist for the life of their associated object.
|
All primary and organizational models in NetBox support journaling. A journal is a collection of human-generated notes and comments about an object maintained for historical context. It supplements NetBox's change log to provide additional information about why changes have been made or to convey events which occur outside NetBox. Unlike the change log, in which records typically expire after a configurable period of time, journal entries persist for the life of their associated object.
|
||||||
|
|
||||||
Each journal entry has a selectable kind (info, success, warning, or danger) and a user-populated `comments` field. Each entry automatically records the date, time, and associated user upon being created.
|
Each journal entry has a selectable kind (info, success, warning, or danger) and a user-populated `comments` field. Each entry automatically records the date, time, and associated user upon being created.
|
||||||
|
@ -20,12 +20,14 @@ To create a new object in NetBox, find the object type in the navigation menu an
|
|||||||
|
|
||||||
## Bulk Import (CSV/YAML)
|
## Bulk Import (CSV/YAML)
|
||||||
|
|
||||||
NetBox supports the bulk import of new objects using CSV-formatted data. This method can be ideal for importing spreadsheet data, which is very easy to convert to CSV data. CSV data can be imported either as raw text using the form field, or by uploading a properly formatted CSV file.
|
NetBox supports the bulk import of new objects, and updating of existing objects using CSV-formatted data. This method can be ideal for importing spreadsheet data, which is very easy to convert to CSV data. CSV data can be imported either as raw text using the form field, or by uploading a properly formatted CSV file.
|
||||||
|
|
||||||
When viewing the CSV import form for an object type, you'll notice that the headers for the required columns have been pre-populated. Each form has a table beneath it titled "CSV Field Options," which lists _all_ supported columns for your reference. (Generally, these map to the fields you see in the corresponding creation form for individual objects.)
|
When viewing the CSV import form for an object type, you'll notice that the headers for the required columns have been pre-populated. Each form has a table beneath it titled "CSV Field Options," which lists _all_ supported columns for your reference. (Generally, these map to the fields you see in the corresponding creation form for individual objects.)
|
||||||
|
|
||||||
<!-- TODO: Screenshot -->
|
<!-- TODO: Screenshot -->
|
||||||
|
|
||||||
|
If an "id" field is added the data will be used to update existing records instead of importing new objects.
|
||||||
|
|
||||||
Note that some models (namely device types and module types) do not support CSV import. Instead, they accept YAML-formatted data to facilitate the import of both the parent object as well as child components.
|
Note that some models (namely device types and module types) do not support CSV import. Instead, they accept YAML-formatted data to facilitate the import of both the parent object as well as child components.
|
||||||
|
|
||||||
## Scripting
|
## Scripting
|
||||||
|
@ -7,7 +7,7 @@ This section of the documentation discusses installing and configuring the NetBo
|
|||||||
Begin by installing all system packages required by NetBox and its dependencies.
|
Begin by installing all system packages required by NetBox and its dependencies.
|
||||||
|
|
||||||
!!! warning "Python 3.8 or later required"
|
!!! warning "Python 3.8 or later required"
|
||||||
NetBox requires Python 3.8, 3.9, or 3.10.
|
NetBox requires Python 3.8, 3.9, 3.10 or 3.11.
|
||||||
|
|
||||||
=== "Ubuntu"
|
=== "Ubuntu"
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ Next, create a file in the same directory as `configuration.py` (typically `/opt
|
|||||||
### General Server Configuration
|
### General Server Configuration
|
||||||
|
|
||||||
!!! info
|
!!! info
|
||||||
When using Windows Server 2012 you may need to specify a port on `AUTH_LDAP_SERVER_URI`. Use `3269` for secure, or `3268` for non-secure.
|
When using Active Directory you may need to specify a port on `AUTH_LDAP_SERVER_URI` to authenticate users from all domains in the forest. Use `3269` for secure, or `3268` for non-secure access to the GC (Global Catalog).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import ldap
|
import ldap
|
||||||
@ -67,6 +67,16 @@ AUTH_LDAP_BIND_PASSWORD = "demo"
|
|||||||
# Note that this is a NetBox-specific setting which sets:
|
# Note that this is a NetBox-specific setting which sets:
|
||||||
# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
# ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
|
||||||
LDAP_IGNORE_CERT_ERRORS = True
|
LDAP_IGNORE_CERT_ERRORS = True
|
||||||
|
|
||||||
|
# Include this setting if you want to validate the LDAP server certificates against a CA certificate directory on your server
|
||||||
|
# Note that this is a NetBox-specific setting which sets:
|
||||||
|
# ldap.set_option(ldap.OPT_X_TLS_CACERTDIR, LDAP_CA_CERT_DIR)
|
||||||
|
LDAP_CA_CERT_DIR = '/etc/ssl/certs'
|
||||||
|
|
||||||
|
# Include this setting if you want to validate the LDAP server certificates against your own CA.
|
||||||
|
# Note that this is a NetBox-specific setting which sets:
|
||||||
|
# ldap.set_option(ldap.OPT_X_TLS_CACERTFILE, LDAP_CA_CERT_FILE)
|
||||||
|
LDAP_CA_CERT_FILE = '/path/to/example-CA.crt'
|
||||||
```
|
```
|
||||||
|
|
||||||
STARTTLS can be configured by setting `AUTH_LDAP_START_TLS = True` and using the `ldap://` URI scheme.
|
STARTTLS can be configured by setting `AUTH_LDAP_START_TLS = True` and using the `ldap://` URI scheme.
|
||||||
|
@ -47,7 +47,7 @@ NetBox provides both a singular and plural query field for each object type:
|
|||||||
|
|
||||||
For example, query `device(id:123)` to fetch a specific device (identified by its unique ID), and query `device_list` (with an optional set of filters) to fetch all devices.
|
For example, query `device(id:123)` to fetch a specific device (identified by its unique ID), and query `device_list` (with an optional set of filters) to fetch all devices.
|
||||||
|
|
||||||
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/).
|
For more detail on constructing GraphQL queries, see the [Graphene documentation](https://docs.graphene-python.org/en/latest/) as well as the [GraphQL queries documentation](https://graphql.org/learn/queries/).
|
||||||
|
|
||||||
## Filtering
|
## Filtering
|
||||||
|
|
||||||
@ -56,6 +56,47 @@ The GraphQL API employs the same filtering logic as the UI and REST API. Filters
|
|||||||
```
|
```
|
||||||
{"query": "query {site_list(region:\"north-carolina\", status:\"active\") {name}}"}
|
{"query": "query {site_list(region:\"north-carolina\", status:\"active\") {name}}"}
|
||||||
```
|
```
|
||||||
|
In addition, filtering can be done on list of related objects as shown in the following query:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
device_list {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
interfaces(enabled: true) {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Multiple Return Types
|
||||||
|
|
||||||
|
Certain queries can return multiple types of objects, for example cable terminations can return circuit terminations, console ports and many others. These can be queried using [inline fragments](https://graphql.org/learn/schema/#union-types) as shown below:
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
cable_list {
|
||||||
|
id
|
||||||
|
a_terminations {
|
||||||
|
... on CircuitTerminationType {
|
||||||
|
id
|
||||||
|
class_type
|
||||||
|
}
|
||||||
|
... on ConsolePortType {
|
||||||
|
id
|
||||||
|
class_type
|
||||||
|
}
|
||||||
|
... on ConsoleServerPortType {
|
||||||
|
id
|
||||||
|
class_type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
The field "class_type" is an easy way to distinguish what type of object it is when viewing the returned data, or when filtering. It contains the class name, for example "CircuitTermination" or "ConsoleServerPort".
|
||||||
|
|
||||||
## Authentication
|
## Authentication
|
||||||
|
|
||||||
|
@ -579,6 +579,9 @@ By default, a token can be used to perform all actions via the API that a user w
|
|||||||
|
|
||||||
Additionally, a token can be set to expire at a specific time. This can be useful if an external client needs to be granted temporary access to NetBox.
|
Additionally, a token can be set to expire at a specific time. This can be useful if an external client needs to be granted temporary access to NetBox.
|
||||||
|
|
||||||
|
!!! warning "Restricting Token Retrieval"
|
||||||
|
The ability to retrieve the key value of a previously-created API token can be restricted by disabling the [`ALLOW_TOKEN_RETRIEVAL`](../configuration/security.md#allow_token_retrieval) configuration parameter.
|
||||||
|
|
||||||
#### Client IP Restriction
|
#### Client IP Restriction
|
||||||
|
|
||||||
!!! note
|
!!! note
|
||||||
|
@ -41,6 +41,10 @@ Indicates whether this is a parent type (capable of housing child devices), a ch
|
|||||||
|
|
||||||
The default direction in which airflow circulates within the device chassis. This may be configured differently for instantiated devices (e.g. because of different fan modules).
|
The default direction in which airflow circulates within the device chassis. This may be configured differently for instantiated devices (e.g. because of different fan modules).
|
||||||
|
|
||||||
|
### Weight
|
||||||
|
|
||||||
|
The numeric weight of the device, including a unit designation (e.g. 10 kilograms or 20 pounds).
|
||||||
|
|
||||||
### Front & Rear Images
|
### Front & Rear Images
|
||||||
|
|
||||||
Users can upload illustrations of the device's front and rear panels. If present, these will be used to render the device in [rack](./rack.md) elevation diagrams.
|
Users can upload illustrations of the device's front and rear panels. If present, these will be used to render the device in [rack](./rack.md) elevation diagrams.
|
||||||
|
@ -35,3 +35,7 @@ The model number assigned to this module type by its manufacturer. Must be uniqu
|
|||||||
### Part Number
|
### Part Number
|
||||||
|
|
||||||
An alternative part number to uniquely identify the module type.
|
An alternative part number to uniquely identify the module type.
|
||||||
|
|
||||||
|
### Weight
|
||||||
|
|
||||||
|
The numeric weight of the module, including a unit designation (e.g. 3 kilograms or 1 pound).
|
||||||
|
@ -65,6 +65,14 @@ The height of the rack, measured in units.
|
|||||||
|
|
||||||
The external width and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches.
|
The external width and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches.
|
||||||
|
|
||||||
|
### Mounting Depth
|
||||||
|
|
||||||
|
The maximum depth of a mounted device that the rack can accommodate, in millimeters. For four-post frames or cabinets, this is the horizontal distance between the front and rear vertical rails. (Note that this measurement does _not_ include space between the rails and the cabinet doors.)
|
||||||
|
|
||||||
|
### Weight
|
||||||
|
|
||||||
|
The numeric weight of the rack, including a unit designation (e.g. 10 kilograms or 20 pounds).
|
||||||
|
|
||||||
### Descending Units
|
### Descending Units
|
||||||
|
|
||||||
If selected, the rack's elevation will display unit 1 at the top of the rack. (Most racks use asceneding numbering, with unit 1 assigned to the bottommost position.)
|
If selected, the rack's elevation will display unit 1 at the top of the rack. (Most racks use asceneding numbering, with unit 1 assigned to the bottommost position.)
|
||||||
|
@ -33,7 +33,7 @@ Each site can have multiple [AS numbers](../ipam/asn.md) assigned to it.
|
|||||||
|
|
||||||
### Time Zone
|
### Time Zone
|
||||||
|
|
||||||
The site's local time zone. (Time zones are provided by the [pytz](https://pypi.org/project/pytz/) package.)
|
The site's local time zone. (Time zones are provided by the [zoneinfo](https://docs.python.org/3/library/zoneinfo.html) library.)
|
||||||
|
|
||||||
### Physical Address
|
### Physical Address
|
||||||
|
|
||||||
|
@ -12,6 +12,13 @@ The service set identifier (SSID) for the wireless network.
|
|||||||
|
|
||||||
The [wireless LAN group](./wirelesslangroup.md) to which this wireless LAN is assigned (if any).
|
The [wireless LAN group](./wirelesslangroup.md) to which this wireless LAN is assigned (if any).
|
||||||
|
|
||||||
|
### Status
|
||||||
|
|
||||||
|
The operational status of the wireless network.
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
Additional statuses may be defined by setting `WirelessLAN.status` under the [`FIELD_CHOICES`](../../configuration/data-validation.md#field_choices) configuration parameter.
|
||||||
|
|
||||||
### VLAN
|
### VLAN
|
||||||
|
|
||||||
Each wireless LAN can optionally be mapped to a [VLAN](../ipam/vlan.md), to model a bridge between wired and wireless segments.
|
Each wireless LAN can optionally be mapped to a [VLAN](../ipam/vlan.md), to model a bridge between wired and wireless segments.
|
||||||
|
@ -144,73 +144,73 @@ class MyModelFilterForm(NetBoxModelFilterSetForm):
|
|||||||
In addition to the [form fields provided by Django](https://docs.djangoproject.com/en/stable/ref/forms/fields/), NetBox provides several field classes for use within forms to handle specific types of data. These can be imported from `utilities.forms.fields` and are documented below.
|
In addition to the [form fields provided by Django](https://docs.djangoproject.com/en/stable/ref/forms/fields/), NetBox provides several field classes for use within forms to handle specific types of data. These can be imported from `utilities.forms.fields` and are documented below.
|
||||||
|
|
||||||
::: utilities.forms.ColorField
|
::: utilities.forms.ColorField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.CommentField
|
::: utilities.forms.CommentField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.JSONField
|
::: utilities.forms.JSONField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.MACAddressField
|
::: utilities.forms.MACAddressField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.SlugField
|
::: utilities.forms.SlugField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
## Choice Fields
|
## Choice Fields
|
||||||
|
|
||||||
::: utilities.forms.ChoiceField
|
::: utilities.forms.ChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.MultipleChoiceField
|
::: utilities.forms.MultipleChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
## Dynamic Object Fields
|
## Dynamic Object Fields
|
||||||
|
|
||||||
::: utilities.forms.DynamicModelChoiceField
|
::: utilities.forms.DynamicModelChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.DynamicModelMultipleChoiceField
|
::: utilities.forms.DynamicModelMultipleChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
## Content Type Fields
|
## Content Type Fields
|
||||||
|
|
||||||
::: utilities.forms.ContentTypeChoiceField
|
::: utilities.forms.ContentTypeChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.ContentTypeMultipleChoiceField
|
::: utilities.forms.ContentTypeMultipleChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
## CSV Import Fields
|
## CSV Import Fields
|
||||||
|
|
||||||
::: utilities.forms.CSVChoiceField
|
::: utilities.forms.CSVChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.CSVMultipleChoiceField
|
::: utilities.forms.CSVMultipleChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.CSVModelChoiceField
|
::: utilities.forms.CSVModelChoiceField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.CSVContentTypeField
|
::: utilities.forms.CSVContentTypeField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: utilities.forms.CSVMultipleContentTypeField
|
::: utilities.forms.CSVMultipleContentTypeField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
@ -32,11 +32,11 @@ schema = MyQuery
|
|||||||
NetBox provides two object type classes for use by plugins.
|
NetBox provides two object type classes for use by plugins.
|
||||||
|
|
||||||
::: netbox.graphql.types.BaseObjectType
|
::: netbox.graphql.types.BaseObjectType
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.graphql.types.NetBoxObjectType
|
::: netbox.graphql.types.NetBoxObjectType
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
## GraphQL Fields
|
## GraphQL Fields
|
||||||
@ -44,9 +44,9 @@ NetBox provides two object type classes for use by plugins.
|
|||||||
NetBox provides two field classes for use by plugins.
|
NetBox provides two field classes for use by plugins.
|
||||||
|
|
||||||
::: netbox.graphql.fields.ObjectField
|
::: netbox.graphql.fields.ObjectField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.graphql.fields.ObjectListField
|
::: netbox.graphql.fields.ObjectListField
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
@ -14,6 +14,7 @@ Plugins can do a lot, including:
|
|||||||
* Provide their own "pages" (views) in the web user interface
|
* Provide their own "pages" (views) in the web user interface
|
||||||
* Inject template content and navigation links
|
* Inject template content and navigation links
|
||||||
* Extend NetBox's REST and GraphQL APIs
|
* Extend NetBox's REST and GraphQL APIs
|
||||||
|
* Load additional Django apps
|
||||||
* Add custom request/response middleware
|
* Add custom request/response middleware
|
||||||
|
|
||||||
However, keep in mind that each piece of functionality is entirely optional. For example, if your plugin merely adds a piece of middleware or an API endpoint for existing data, there's no need to define any new models.
|
However, keep in mind that each piece of functionality is entirely optional. For example, if your plugin merely adds a piece of middleware or an API endpoint for existing data, there's no need to define any new models.
|
||||||
@ -82,6 +83,7 @@ class FooBarConfig(PluginConfig):
|
|||||||
default_settings = {
|
default_settings = {
|
||||||
'baz': True
|
'baz': True
|
||||||
}
|
}
|
||||||
|
django_apps = ["foo", "bar", "baz"]
|
||||||
|
|
||||||
config = FooBarConfig
|
config = FooBarConfig
|
||||||
```
|
```
|
||||||
@ -101,10 +103,12 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
|
|||||||
| `base_url` | Base path to use for plugin URLs (optional). If not specified, the project's `name` will be used. |
|
| `base_url` | Base path to use for plugin URLs (optional). If not specified, the project's `name` will be used. |
|
||||||
| `required_settings` | A list of any configuration parameters that **must** be defined by the user |
|
| `required_settings` | A list of any configuration parameters that **must** be defined by the user |
|
||||||
| `default_settings` | A dictionary of configuration parameters and their default values |
|
| `default_settings` | A dictionary of configuration parameters and their default values |
|
||||||
|
| `django_apps` | A list of additional Django apps to load alongside the plugin |
|
||||||
| `min_version` | Minimum version of NetBox with which the plugin is compatible |
|
| `min_version` | Minimum version of NetBox with which the plugin is compatible |
|
||||||
| `max_version` | Maximum version of NetBox with which the plugin is compatible |
|
| `max_version` | Maximum version of NetBox with which the plugin is compatible |
|
||||||
| `middleware` | A list of middleware classes to append after NetBox's build-in middleware |
|
| `middleware` | A list of middleware classes to append after NetBox's build-in middleware |
|
||||||
| `queues` | A list of custom background task queues to create |
|
| `queues` | A list of custom background task queues to create |
|
||||||
|
| `search_extensions` | The dotted path to the list of search index classes (default: `search.indexes`) |
|
||||||
| `template_extensions` | The dotted path to the list of template extension classes (default: `template_content.template_extensions`) |
|
| `template_extensions` | The dotted path to the list of template extension classes (default: `template_content.template_extensions`) |
|
||||||
| `menu_items` | The dotted path to the list of menu items provided by the plugin (default: `navigation.menu_items`) |
|
| `menu_items` | The dotted path to the list of menu items provided by the plugin (default: `navigation.menu_items`) |
|
||||||
| `graphql_schema` | The dotted path to the plugin's GraphQL schema class, if any (default: `graphql.schema`) |
|
| `graphql_schema` | The dotted path to the plugin's GraphQL schema class, if any (default: `graphql.schema`) |
|
||||||
@ -112,6 +116,22 @@ NetBox looks for the `config` variable within a plugin's `__init__.py` to load i
|
|||||||
|
|
||||||
All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
|
All required settings must be configured by the user. If a configuration parameter is listed in both `required_settings` and `default_settings`, the default setting will be ignored.
|
||||||
|
|
||||||
|
!!! tip "Accessing Config Parameters"
|
||||||
|
Plugin configuration parameters can be accessed using the `get_plugin_config()` function. For example:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from extras.plugins import get_plugin_config
|
||||||
|
get_plugin_config('my_plugin', 'verbose_name')
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Important Notes About `django_apps`
|
||||||
|
|
||||||
|
Loading additional apps may cause more harm than good and could make identifying problems within NetBox itself more difficult. The `django_apps` attribute is intended only for advanced use cases that require a deeper Django integration.
|
||||||
|
|
||||||
|
Apps from this list are inserted *before* the plugin's `PluginConfig` in the order defined. Adding the plugin's `PluginConfig` module to this list changes this behavior and allows for apps to be loaded *after* the plugin.
|
||||||
|
|
||||||
|
Any additional apps must be installed within the same Python environment as NetBox or `ImproperlyConfigured` exceptions will be raised when loading the plugin.
|
||||||
|
|
||||||
## Create setup.py
|
## Create setup.py
|
||||||
|
|
||||||
`setup.py` is the [setup script](https://docs.python.org/3.8/distutils/setupscript.html) used to package and install our plugin once it's finished. The primary function of this script is to call the setuptools library's `setup()` function to create a Python distribution package. We can pass a number of keyword arguments to control the package creation as well as to provide metadata about the plugin. An example `setup.py` is below:
|
`setup.py` is the [setup script](https://docs.python.org/3.8/distutils/setupscript.html) used to package and install our plugin once it's finished. The primary function of this script is to call the setuptools library's `setup()` function to create a Python distribution package. We can pass a number of keyword arguments to control the package creation as well as to provide metadata about the plugin. An example `setup.py` is below:
|
||||||
|
@ -49,6 +49,12 @@ class MyModel(NetBoxModel):
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### NetBoxModel Properties
|
||||||
|
|
||||||
|
#### `docs_url`
|
||||||
|
|
||||||
|
This attribute specifies the URL at which the documentation for this model can be reached. By default, it will return `/static/docs/models/<app_label>/<model_name>/`. Plugin models can override this to return a custom URL. For example, you might direct the user to your plugin's documentation hosted on [ReadTheDocs](https://readthedocs.org/).
|
||||||
|
|
||||||
### Enabling Features Individually
|
### Enabling Features Individually
|
||||||
|
|
||||||
If you prefer instead to enable only a subset of these features for a plugin model, NetBox provides a discrete "mix-in" class for each feature. You can subclass each of these individually when defining your model. (Your model will also need to inherit from Django's built-in `Model` class.)
|
If you prefer instead to enable only a subset of these features for a plugin model, NetBox provides a discrete "mix-in" class for each feature. You can subclass each of these individually when defining your model. (Your model will also need to inherit from Django's built-in `Model` class.)
|
||||||
|
28
docs/plugins/development/search.md
Normal file
28
docs/plugins/development/search.md
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
# Search
|
||||||
|
|
||||||
|
Plugins can define and register their own models to extend NetBox's core search functionality. Typically, a plugin will include a file named `search.py`, which holds all search indexes for its models (see the example below).
|
||||||
|
|
||||||
|
```python
|
||||||
|
# search.py
|
||||||
|
from netbox.search import SearchIndex
|
||||||
|
from .models import MyModel
|
||||||
|
|
||||||
|
class MyModelIndex(SearchIndex):
|
||||||
|
model = MyModel
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('description', 500),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
To register one or more indexes with NetBox, define a list named `indexes` at the end of this file:
|
||||||
|
|
||||||
|
```python
|
||||||
|
indexes = [MyModelIndex]
|
||||||
|
```
|
||||||
|
|
||||||
|
!!! tip
|
||||||
|
The path to the list of search indexes can be modified by setting `search_indexes` in the PluginConfig instance.
|
||||||
|
|
||||||
|
::: netbox.search.SearchIndex
|
@ -52,38 +52,38 @@ This will automatically apply any user-specific preferences for the table. (If u
|
|||||||
The table column classes listed below are supported for use in plugins. These classes can be imported from `netbox.tables.columns`.
|
The table column classes listed below are supported for use in plugins. These classes can be imported from `netbox.tables.columns`.
|
||||||
|
|
||||||
::: netbox.tables.BooleanColumn
|
::: netbox.tables.BooleanColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.ChoiceFieldColumn
|
::: netbox.tables.ChoiceFieldColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.ColorColumn
|
::: netbox.tables.ColorColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.ColoredLabelColumn
|
::: netbox.tables.ColoredLabelColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.ContentTypeColumn
|
::: netbox.tables.ContentTypeColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.ContentTypesColumn
|
::: netbox.tables.ContentTypesColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.MarkdownColumn
|
::: netbox.tables.MarkdownColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.TagColumn
|
::: netbox.tables.TagColumn
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.tables.TemplateColumn
|
::: netbox.tables.TemplateColumn
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- __init__
|
- __init__
|
||||||
|
@ -82,26 +82,28 @@ class ThingEditView(ObjectEditView):
|
|||||||
Below are the class definitions for NetBox's object views. These views handle CRUD actions for individual objects. The view, add/edit, and delete views each inherit from `BaseObjectView`, which is not intended to be used directly.
|
Below are the class definitions for NetBox's object views. These views handle CRUD actions for individual objects. The view, add/edit, and delete views each inherit from `BaseObjectView`, which is not intended to be used directly.
|
||||||
|
|
||||||
::: netbox.views.generic.base.BaseObjectView
|
::: netbox.views.generic.base.BaseObjectView
|
||||||
|
options:
|
||||||
|
members:
|
||||||
|
- get_queryset
|
||||||
|
- get_object
|
||||||
|
- get_extra_context
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectView
|
::: netbox.views.generic.ObjectView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_object
|
|
||||||
- get_template_name
|
- get_template_name
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectEditView
|
::: netbox.views.generic.ObjectEditView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_object
|
|
||||||
- alter_object
|
- alter_object
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectDeleteView
|
::: netbox.views.generic.ObjectDeleteView
|
||||||
selection:
|
options:
|
||||||
members:
|
members: false
|
||||||
- get_object
|
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectChildrenView
|
::: netbox.views.generic.ObjectChildrenView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_children
|
- get_children
|
||||||
- prep_table_data
|
- prep_table_data
|
||||||
@ -111,24 +113,28 @@ Below are the class definitions for NetBox's object views. These views handle CR
|
|||||||
Below are the class definitions for NetBox's multi-object views. These views handle simultaneous actions for sets objects. The list, import, edit, and delete views each inherit from `BaseMultiObjectView`, which is not intended to be used directly.
|
Below are the class definitions for NetBox's multi-object views. These views handle simultaneous actions for sets objects. The list, import, edit, and delete views each inherit from `BaseMultiObjectView`, which is not intended to be used directly.
|
||||||
|
|
||||||
::: netbox.views.generic.base.BaseMultiObjectView
|
::: netbox.views.generic.base.BaseMultiObjectView
|
||||||
|
options:
|
||||||
|
members:
|
||||||
|
- get_queryset
|
||||||
|
- get_extra_context
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectListView
|
::: netbox.views.generic.ObjectListView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_table
|
- get_table
|
||||||
- export_table
|
- export_table
|
||||||
- export_template
|
- export_template
|
||||||
|
|
||||||
::: netbox.views.generic.BulkImportView
|
::: netbox.views.generic.BulkImportView
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.views.generic.BulkEditView
|
::: netbox.views.generic.BulkEditView
|
||||||
selection:
|
options:
|
||||||
members: false
|
members: false
|
||||||
|
|
||||||
::: netbox.views.generic.BulkDeleteView
|
::: netbox.views.generic.BulkDeleteView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_form
|
- get_form
|
||||||
|
|
||||||
@ -137,17 +143,43 @@ Below are the class definitions for NetBox's multi-object views. These views han
|
|||||||
These views are provided to enable or enhance certain NetBox model features, such as change logging or journaling. These typically do not need to be subclassed: They can be used directly e.g. in a URL path.
|
These views are provided to enable or enhance certain NetBox model features, such as change logging or journaling. These typically do not need to be subclassed: They can be used directly e.g. in a URL path.
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectChangeLogView
|
::: netbox.views.generic.ObjectChangeLogView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_form
|
- get_form
|
||||||
|
|
||||||
::: netbox.views.generic.ObjectJournalView
|
::: netbox.views.generic.ObjectJournalView
|
||||||
selection:
|
options:
|
||||||
members:
|
members:
|
||||||
- get_form
|
- get_form
|
||||||
|
|
||||||
## Extending Core Views
|
## Extending Core Views
|
||||||
|
|
||||||
|
### Additional Tabs
|
||||||
|
|
||||||
|
Plugins can "attach" a custom view to a core NetBox model by registering it with `register_model_view()`. To include a tab for this view within the NetBox UI, declare a TabView instance named `tab`:
|
||||||
|
|
||||||
|
```python
|
||||||
|
from dcim.models import Site
|
||||||
|
from myplugin.models import Stuff
|
||||||
|
from netbox.views import generic
|
||||||
|
from utilities.views import ViewTab, register_model_view
|
||||||
|
|
||||||
|
@register_model_view(Site, 'mview', path='some-other-stuff')
|
||||||
|
class MyView(generic.ObjectView):
|
||||||
|
...
|
||||||
|
tab = ViewTab(
|
||||||
|
label='Other Stuff',
|
||||||
|
badge=lambda obj: Stuff.objects.filter(site=obj).count(),
|
||||||
|
permission='myplugin.view_stuff'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
::: utilities.views.register_model_view
|
||||||
|
|
||||||
|
::: utilities.views.ViewTab
|
||||||
|
|
||||||
|
### Extra Template Content
|
||||||
|
|
||||||
Plugins can inject custom content into certain areas of the detail views of applicable models. This is accomplished by subclassing `PluginTemplateExtension`, designating a particular NetBox model, and defining the desired methods to render custom content. Four methods are available:
|
Plugins can inject custom content into certain areas of the detail views of applicable models. This is accomplished by subclassing `PluginTemplateExtension`, designating a particular NetBox model, and defining the desired methods to render custom content. Four methods are available:
|
||||||
|
|
||||||
* `left_page()` - Inject content on the left side of the page
|
* `left_page()` - Inject content on the left side of the page
|
||||||
|
@ -1,18 +1,83 @@
|
|||||||
# NetBox v3.3
|
# NetBox v3.3
|
||||||
|
|
||||||
## v3.3.5 (FUTURE)
|
## v3.3.8 (FUTURE)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v3.3.7 (2022-11-01)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* [#10282](https://github.com/netbox-community/netbox/issues/10282) - Enforce advisory locks when allocating available IP addresses to prevent race conditions
|
||||||
|
* [#10770](https://github.com/netbox-community/netbox/issues/10282) - Fix social authentication for new users
|
||||||
|
* [#10791](https://github.com/netbox-community/netbox/issues/10791) - Permit nullifying VLAN group `scope_type` via REST API
|
||||||
|
* [#10803](https://github.com/netbox-community/netbox/issues/10803) - Fix exception when ordering contacts by number of assignments
|
||||||
|
* [#10809](https://github.com/netbox-community/netbox/issues/10809) - Permit nullifying site `time_zone` via REST API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v3.3.6 (2022-10-26)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [#9584](https://github.com/netbox-community/netbox/issues/9584) - Enable filtering devices by device type slug
|
||||||
|
* [#9722](https://github.com/netbox-community/netbox/issues/9722) - Add LDAP configuration parameters to specify certificates
|
||||||
|
* [#10580](https://github.com/netbox-community/netbox/issues/10580) - Link "assigned" checkbox in IP address table to assigned interface
|
||||||
|
* [#10639](https://github.com/netbox-community/netbox/issues/10639) - Set cookie paths according to configured `BASE_PATH`
|
||||||
|
* [#10685](https://github.com/netbox-community/netbox/issues/10685) - Position A/Z termination cards above the fold under circuit view
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* [#9669](https://github.com/netbox-community/netbox/issues/9669) - Strip colons from usernames when using remote authentication
|
||||||
|
* [#10575](https://github.com/netbox-community/netbox/issues/10575) - Include OIDC dependencies for python-social-auth
|
||||||
|
* [#10584](https://github.com/netbox-community/netbox/issues/10584) - Fix service clone link
|
||||||
|
* [#10610](https://github.com/netbox-community/netbox/issues/10610) - Allow assignment of VC member to LAG on non-master peer
|
||||||
|
* [#10643](https://github.com/netbox-community/netbox/issues/10643) - Ensure consistent display of custom fields for all model forms
|
||||||
|
* [#10646](https://github.com/netbox-community/netbox/issues/10646) - Fix filtering of power feed by power panel when connecting a cable
|
||||||
|
* [#10655](https://github.com/netbox-community/netbox/issues/10655) - Correct display of assigned contacts in object tables
|
||||||
|
* [#10666](https://github.com/netbox-community/netbox/issues/10666) - Re-evaluate disabled LDAP user when processing API requests
|
||||||
|
* [#10682](https://github.com/netbox-community/netbox/issues/10682) - Correct home view links to connection lists
|
||||||
|
* [#10712](https://github.com/netbox-community/netbox/issues/10712) - Fix ModuleNotFoundError exception when generating API schema under Python 3.9+
|
||||||
|
* [#10716](https://github.com/netbox-community/netbox/issues/10716) - Add left/right page plugin content embeds for tag view
|
||||||
|
* [#10719](https://github.com/netbox-community/netbox/issues/10719) - Prevent user without sufficient permission from creating an IP address via FHRP group creation
|
||||||
|
* [#10723](https://github.com/netbox-community/netbox/issues/10723) - Distinguish between inside/outside NAT assignments for device/VM primary IPs
|
||||||
|
* [#10745](https://github.com/netbox-community/netbox/issues/10745) - Correct display of status field in clusters list
|
||||||
|
* [#10746](https://github.com/netbox-community/netbox/issues/10746) - Add missing status attribute to cluster view
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## v3.3.5 (2022-10-05)
|
||||||
|
|
||||||
|
### Enhancements
|
||||||
|
|
||||||
|
* [#8424](https://github.com/netbox-community/netbox/issues/8424) - Include rack elevation under device view
|
||||||
|
* [#10352](https://github.com/netbox-community/netbox/issues/10352) - Omit extraneous URL query attributes during search
|
||||||
|
* [#10465](https://github.com/netbox-community/netbox/issues/10465) - Improve formatting of device heights and rack positions
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view
|
* [#9497](https://github.com/netbox-community/netbox/issues/9497) - Adjust non-racked device filter on site and location detailed view
|
||||||
|
* [#10408](https://github.com/netbox-community/netbox/issues/10408) - Fix validation when attempting to add redundant contact assignments
|
||||||
|
* [#10423](https://github.com/netbox-community/netbox/issues/10423) - Enforce object type validation when creating journal entries
|
||||||
* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned
|
* [#10435](https://github.com/netbox-community/netbox/issues/10435) - Fix exception when filtering VLANs by virtual machine with no cluster assigned
|
||||||
* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field
|
* [#10439](https://github.com/netbox-community/netbox/issues/10439) - Fix form widget styling for DeviceType airflow field
|
||||||
|
* [#10445](https://github.com/netbox-community/netbox/issues/10445) - Avoid rounding virtual machine memory values
|
||||||
|
* [#10460](https://github.com/netbox-community/netbox/issues/10460) - Restore missing connection details for device components
|
||||||
|
* [#10461](https://github.com/netbox-community/netbox/issues/10461) - Enable filtering by read-only custom fields in the UI
|
||||||
|
* [#10470](https://github.com/netbox-community/netbox/issues/10470) - Omit read-only custom fields from CSV import forms
|
||||||
|
* [#10480](https://github.com/netbox-community/netbox/issues/10480) - Cable trace SVG links should not force a new window
|
||||||
|
* [#10491](https://github.com/netbox-community/netbox/issues/10491) - Clarify representation of blocking contact assignments during contact deletion
|
||||||
|
* [#10513](https://github.com/netbox-community/netbox/issues/10513) - Disable the reassignment of a module to a new device
|
||||||
|
* [#10517](https://github.com/netbox-community/netbox/issues/10517) - Automatically inherit site assignment from cluster when creating a virtual machine
|
||||||
|
* [#10559](https://github.com/netbox-community/netbox/issues/10559) - Permit the pinning of a VM to a particular device within a cluster which has no site assignment
|
||||||
|
* [#10562](https://github.com/netbox-community/netbox/issues/10562) - Correct URL for contacts table tags column
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## v3.3.4 (2022-09-16)
|
## v3.3.4 (2022-09-16)
|
||||||
|
|
||||||
### Bug Fixes
|
### Bug Fixes
|
||||||
|
|
||||||
* [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI
|
* [#10383](https://github.com/netbox-community/netbox/issues/10383) - Fix assignment of component templates to module types via web UI
|
||||||
* [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface
|
* [#10387](https://github.com/netbox-community/netbox/issues/10387) - Fix `MultiValueDictKeyError` exception when editing a device interface
|
||||||
|
|
||||||
|
@ -8,32 +8,156 @@
|
|||||||
* Device and virtual machine names are no longer case-sensitive. Attempting to create e.g. "device1" and "DEVICE1" will raise a validation error.
|
* Device and virtual machine names are no longer case-sensitive. Attempting to create e.g. "device1" and "DEVICE1" will raise a validation error.
|
||||||
* The `asn` field has been removed from the provider model. Please replicate any provider ASN assignments to the ASN model introduced in NetBox v3.1 prior to upgrading.
|
* The `asn` field has been removed from the provider model. Please replicate any provider ASN assignments to the ASN model introduced in NetBox v3.1 prior to upgrading.
|
||||||
* The `noc_contact`, `admin_contact`, and `portal_url` fields have been removed from the provider model. Please replicate any data remaining in these fields to the contact model introduced in NetBox v3.1 prior to upgrading.
|
* The `noc_contact`, `admin_contact`, and `portal_url` fields have been removed from the provider model. Please replicate any data remaining in these fields to the contact model introduced in NetBox v3.1 prior to upgrading.
|
||||||
|
* The `content_type` field on the CustomLink and ExportTemplate models have been renamed to `content_types` and now supports the assignment of multiple content types.
|
||||||
|
* The `cf` property on an object with custom fields now returns deserialized values. For example, a custom field referencing an object will return the object instance rather than its numeric ID. To access the raw serialized values, use `custom_field_data` instead.
|
||||||
|
|
||||||
### New Features
|
### New Features
|
||||||
|
|
||||||
|
#### New Global Search ([#10560](https://github.com/netbox-community/netbox/issues/10560))
|
||||||
|
|
||||||
|
NetBox's global search functionality has been completely overhauled and replaced by a new cache-based lookup.
|
||||||
|
|
||||||
|
#### CSV-Based Bulk Updates ([#7961](https://github.com/netbox-community/netbox/issues/7961))
|
||||||
|
|
||||||
|
NetBox's CSV-based bulk import functionality has been extended to support also modifying existing objects. When an `id` column is present in the import form, it will be used to infer the object to be modified, rather than a new object being created. All fields (columns) are optional when modifying existing objects.
|
||||||
|
|
||||||
#### Top-Level Plugin Navigation Menus ([#9071](https://github.com/netbox-community/netbox/issues/9071))
|
#### Top-Level Plugin Navigation Menus ([#9071](https://github.com/netbox-community/netbox/issues/9071))
|
||||||
|
|
||||||
A new `PluginMenu` class has been introduced, which enables a plugin to inject a top-level menu in NetBox's navigation menu. This menu can have one or more groups of menu items, just like core items. Backward compatibility with the existing `menu_items` has been maintained.
|
A new `PluginMenu` class has been introduced, which enables a plugin to inject a top-level menu in NetBox's navigation menu. This menu can have one or more groups of menu items, just like core items. Backward compatibility with the existing `menu_items` has been maintained.
|
||||||
|
|
||||||
### Enhancements
|
### Enhancements
|
||||||
|
|
||||||
|
* [#7376](https://github.com/netbox-community/netbox/issues/7376) - Enable the assignment of tags during CSV import
|
||||||
|
* [#8245](https://github.com/netbox-community/netbox/issues/8245) - Enable GraphQL filtering of related objects
|
||||||
|
* [#8274](https://github.com/netbox-community/netbox/issues/8274) - Enable associating a custom link with multiple object types
|
||||||
|
* [#8485](https://github.com/netbox-community/netbox/issues/8485) - Enable journaling for all organizational models
|
||||||
|
* [#8853](https://github.com/netbox-community/netbox/issues/8853) - Introduce the `ALLOW_TOKEN_RETRIEVAL` config parameter to restrict the display of API tokens
|
||||||
* [#9249](https://github.com/netbox-community/netbox/issues/9249) - Device and virtual machine names are no longer case-sensitive
|
* [#9249](https://github.com/netbox-community/netbox/issues/9249) - Device and virtual machine names are no longer case-sensitive
|
||||||
|
* [#9478](https://github.com/netbox-community/netbox/issues/9478) - Add `link_peers` field to GraphQL types for cabled objects
|
||||||
|
* [#9654](https://github.com/netbox-community/netbox/issues/9654) - Add `weight` field to racks, device types, and module types
|
||||||
|
* [#9817](https://github.com/netbox-community/netbox/issues/9817) - Add `assigned_object` field to GraphQL type for IP addresses and L2VPN terminations
|
||||||
|
* [#9832](https://github.com/netbox-community/netbox/issues/9832) - Add `mounting_depth` field to rack model
|
||||||
* [#9892](https://github.com/netbox-community/netbox/issues/9892) - Add optional `name` field for FHRP groups
|
* [#9892](https://github.com/netbox-community/netbox/issues/9892) - Add optional `name` field for FHRP groups
|
||||||
|
* [#10052](https://github.com/netbox-community/netbox/issues/10052) - The `cf` attribute now returns deserialized custom field data
|
||||||
|
* [#10348](https://github.com/netbox-community/netbox/issues/10348) - Add decimal custom field type
|
||||||
|
* [#10556](https://github.com/netbox-community/netbox/issues/10556) - Include a `display` field in all GraphQL object types
|
||||||
|
* [#10595](https://github.com/netbox-community/netbox/issues/10595) - Add GraphQL relationships for additional generic foreign key fields
|
||||||
|
* [#10698](https://github.com/netbox-community/netbox/issues/10698) - Omit app label from content type in table columns
|
||||||
|
* [#10710](https://github.com/netbox-community/netbox/issues/10710) - Add `status` field to WirelessLAN
|
||||||
|
* [#10761](https://github.com/netbox-community/netbox/issues/10761) - Enable associating an export template with multiple object types
|
||||||
|
* [#10781](https://github.com/netbox-community/netbox/issues/10781) - Add support for Python v3.11
|
||||||
|
|
||||||
### Plugins API
|
### Plugins API
|
||||||
|
|
||||||
|
* [#8927](https://github.com/netbox-community/netbox/issues/8927) - Enable inclusion of plugin models in global search via `SearchIndex`
|
||||||
* [#9071](https://github.com/netbox-community/netbox/issues/9071) - Introduce `PluginMenu` for top-level plugin navigation menus
|
* [#9071](https://github.com/netbox-community/netbox/issues/9071) - Introduce `PluginMenu` for top-level plugin navigation menus
|
||||||
|
* [#9072](https://github.com/netbox-community/netbox/issues/9072) - Enable registration of tabbed plugin views for core NetBox models
|
||||||
|
* [#9880](https://github.com/netbox-community/netbox/issues/9880) - Introduce `django_apps` plugin configuration parameter
|
||||||
|
* [#9887](https://github.com/netbox-community/netbox/issues/9887) - Inspect `docs_url` property to determine link to model documentation
|
||||||
* [#10314](https://github.com/netbox-community/netbox/issues/10314) - Move `clone()` method from NetBoxModel to CloningMixin
|
* [#10314](https://github.com/netbox-community/netbox/issues/10314) - Move `clone()` method from NetBoxModel to CloningMixin
|
||||||
|
* [#10543](https://github.com/netbox-community/netbox/issues/10543) - Introduce `get_plugin_config()` utility function
|
||||||
|
* [#10739](https://github.com/netbox-community/netbox/issues/10739) - Introduce `get_queryset()` method on generic views
|
||||||
|
|
||||||
### Other Changes
|
### Other Changes
|
||||||
|
|
||||||
* [#9045](https://github.com/netbox-community/netbox/issues/9045) - Remove legacy ASN field from provider model
|
* [#9045](https://github.com/netbox-community/netbox/issues/9045) - Remove legacy ASN field from provider model
|
||||||
* [#9046](https://github.com/netbox-community/netbox/issues/9046) - Remove legacy contact fields from provider model
|
* [#9046](https://github.com/netbox-community/netbox/issues/9046) - Remove legacy contact fields from provider model
|
||||||
* [#10358](https://github.com/netbox-community/netbox/issues/10358) - Raise minimum required PostgreSQL version from 10 to 11
|
* [#10358](https://github.com/netbox-community/netbox/issues/10358) - Raise minimum required PostgreSQL version from 10 to 11
|
||||||
|
* [#10697](https://github.com/netbox-community/netbox/issues/10697) - Move application registry into core app
|
||||||
|
* [#10699](https://github.com/netbox-community/netbox/issues/10699) - Remove custom `import_object()` function
|
||||||
|
* [#10816](https://github.com/netbox-community/netbox/issues/10816) - Pass the current request when instantiating a FilterSet within UI views
|
||||||
|
* [#10820](https://github.com/netbox-community/netbox/issues/10820) - Switch timezone library from pytz to zoneinfo
|
||||||
|
* [#10821](https://github.com/netbox-community/netbox/issues/10821) - Enable data localization
|
||||||
|
|
||||||
### REST API Changes
|
### REST API Changes
|
||||||
|
|
||||||
* circuits.provider
|
* circuits.provider
|
||||||
* Removed the `asn`, `noc_contact`, `admin_contact`, and `portal_url` fields
|
* Removed the `asn`, `noc_contact`, `admin_contact`, and `portal_url` fields
|
||||||
|
* Added a `description` field
|
||||||
|
* dcim.Cable
|
||||||
|
* Added `description` and `comments` fields
|
||||||
|
* dcim.Device
|
||||||
|
* Added a `description` field
|
||||||
|
* dcim.DeviceType
|
||||||
|
* Added a `description` field
|
||||||
|
* Added optional `weight` and `weight_unit` fields
|
||||||
|
* dcim.Module
|
||||||
|
* Added a `description` field
|
||||||
|
* dcim.ModuleType
|
||||||
|
* Added a `description` field
|
||||||
|
* Added optional `weight` and `weight_unit` fields
|
||||||
|
* dcim.PowerFeed
|
||||||
|
* Added a `description` field
|
||||||
|
* dcim.PowerPanel
|
||||||
|
* Added `description` and `comments` fields
|
||||||
|
* dcim.Rack
|
||||||
|
* Added a `description` field
|
||||||
|
* Added optional `weight` and `weight_unit` fields
|
||||||
|
* dcim.RackReservation
|
||||||
|
* Added a `comments` field
|
||||||
|
* dcim.VirtualChassis
|
||||||
|
* Added `description` and `comments` fields
|
||||||
|
* extras.CustomLink
|
||||||
|
* Renamed `content_type` field to `content_types`
|
||||||
|
* extras.ExportTemplate
|
||||||
|
* Renamed `content_type` field to `content_types`
|
||||||
|
* ipam.Aggregate
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.ASN
|
||||||
|
* Added a `comments` field
|
||||||
* ipam.FHRPGroup
|
* ipam.FHRPGroup
|
||||||
|
* Added a `comments` field
|
||||||
* Added optional `name` field
|
* Added optional `name` field
|
||||||
|
* ipam.IPAddress
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.IPRange
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.L2VPN
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.Prefix
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.RouteTarget
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.Service
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.ServiceTemplate
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.VLAN
|
||||||
|
* Added a `comments` field
|
||||||
|
* ipam.VRF
|
||||||
|
* Added a `comments` field
|
||||||
|
* tenancy.Contact
|
||||||
|
* Added a `description` field
|
||||||
|
* virtualization.Cluster
|
||||||
|
* Added a `description` field
|
||||||
|
* virtualization.VirtualMachine
|
||||||
|
* Added a `description` field
|
||||||
|
* wireless.WirelessLAN
|
||||||
|
* Added a required `status` choice field
|
||||||
|
* Added a `comments` field
|
||||||
|
* wireless.WirelessLink
|
||||||
|
* Added a `comments` field
|
||||||
|
|
||||||
|
### GraphQL API Changes
|
||||||
|
|
||||||
|
* All object types now include a `display` field
|
||||||
|
* All cabled object types now include a `link_peers` field
|
||||||
|
* Add a `contacts` relationship for all relevant models
|
||||||
|
* dcim.Cable
|
||||||
|
* Add A/B terminations fields
|
||||||
|
* dcim.CableTermination
|
||||||
|
* Add `termination` field
|
||||||
|
* dcim.InventoryItem
|
||||||
|
* Add `component` field
|
||||||
|
* dcim.InventoryItemTemplate
|
||||||
|
* Add `component` field
|
||||||
|
* dcim.Rack
|
||||||
|
* Add `mounting_depth` field
|
||||||
|
* ipam.FHRPGroupAssignment
|
||||||
|
* Add `interface` field
|
||||||
|
* ipam.IPAddress
|
||||||
|
* Add `assigned_object` field
|
||||||
|
* ipam.L2VPNTermination
|
||||||
|
* Add `assigned_object` field
|
||||||
|
* ipam.VLANGroupType
|
||||||
|
* Add `scope` field
|
||||||
|
@ -30,7 +30,7 @@ plugins:
|
|||||||
- os.chdir('netbox/')
|
- os.chdir('netbox/')
|
||||||
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings")
|
- os.environ.setdefault("DJANGO_SETTINGS_MODULE", "netbox.settings")
|
||||||
- django.setup()
|
- django.setup()
|
||||||
rendering:
|
options:
|
||||||
heading_level: 3
|
heading_level: 3
|
||||||
members_order: source
|
members_order: source
|
||||||
show_root_heading: true
|
show_root_heading: true
|
||||||
@ -38,7 +38,6 @@ plugins:
|
|||||||
show_root_toc_entry: false
|
show_root_toc_entry: false
|
||||||
show_source: false
|
show_source: false
|
||||||
extra:
|
extra:
|
||||||
readthedocs: !ENV READTHEDOCS
|
|
||||||
social:
|
social:
|
||||||
- icon: fontawesome/brands/github
|
- icon: fontawesome/brands/github
|
||||||
link: https://github.com/netbox-community/netbox
|
link: https://github.com/netbox-community/netbox
|
||||||
@ -133,6 +132,7 @@ nav:
|
|||||||
- GraphQL API: 'plugins/development/graphql-api.md'
|
- GraphQL API: 'plugins/development/graphql-api.md'
|
||||||
- Background Tasks: 'plugins/development/background-tasks.md'
|
- Background Tasks: 'plugins/development/background-tasks.md'
|
||||||
- Exceptions: 'plugins/development/exceptions.md'
|
- Exceptions: 'plugins/development/exceptions.md'
|
||||||
|
- Search: 'plugins/development/search.md'
|
||||||
- Administration:
|
- Administration:
|
||||||
- Authentication:
|
- Authentication:
|
||||||
- Overview: 'administration/authentication/overview.md'
|
- Overview: 'administration/authentication/overview.md'
|
||||||
@ -245,6 +245,7 @@ nav:
|
|||||||
- Adding Models: 'development/adding-models.md'
|
- Adding Models: 'development/adding-models.md'
|
||||||
- Extending Models: 'development/extending-models.md'
|
- Extending Models: 'development/extending-models.md'
|
||||||
- Signals: 'development/signals.md'
|
- Signals: 'development/signals.md'
|
||||||
|
- Search: 'development/search.md'
|
||||||
- Application Registry: 'development/application-registry.md'
|
- Application Registry: 'development/application-registry.md'
|
||||||
- User Preferences: 'development/user-preferences.md'
|
- User Preferences: 'development/user-preferences.md'
|
||||||
- Web UI: 'development/web-ui.md'
|
- Web UI: 'development/web-ui.md'
|
||||||
|
@ -31,8 +31,8 @@ class ProviderSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'name', 'slug', 'account',
|
'id', 'url', 'display', 'name', 'slug', 'account', 'description', 'comments', 'asns', 'tags',
|
||||||
'comments', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count',
|
'custom_fields', 'created', 'last_updated', 'circuit_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,4 +6,4 @@ class CircuitsConfig(AppConfig):
|
|||||||
verbose_name = "Circuits"
|
verbose_name = "Circuits"
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
import circuits.signals
|
from . import signals, search
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from .bulk_edit import *
|
from .bulk_edit import *
|
||||||
from .bulk_import import *
|
from .bulk_import import *
|
||||||
from .filtersets import *
|
from .filtersets import *
|
||||||
from .models import *
|
from .model_forms import *
|
||||||
|
@ -30,6 +30,10 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label='Account number'
|
label='Account number'
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
comments = CommentField(
|
comments = CommentField(
|
||||||
widget=SmallTextarea,
|
widget=SmallTextarea,
|
||||||
label='Comments'
|
label='Comments'
|
||||||
@ -40,7 +44,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
(None, ('asns', 'account', )),
|
(None, ('asns', 'account', )),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'asns', 'account', 'comments',
|
'asns', 'account', 'description', 'comments',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ class ProviderCSVForm(NetBoxModelCSVForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'slug', 'account', 'comments',
|
'name', 'slug', 'account', 'description', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ class ProviderNetworkCSVForm(NetBoxModelCSVForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ProviderNetwork
|
model = ProviderNetwork
|
||||||
fields = [
|
fields = [
|
||||||
'provider', 'name', 'service_id', 'description', 'comments',
|
'provider', 'name', 'service_id', 'description', 'comments', 'tags'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -41,7 +41,7 @@ class CircuitTypeCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
fields = ('name', 'slug', 'description')
|
fields = ('name', 'slug', 'description', 'tags')
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': 'Name of circuit type',
|
'name': 'Name of circuit type',
|
||||||
}
|
}
|
||||||
@ -73,5 +73,5 @@ class CircuitCSVForm(NetBoxModelCSVForm):
|
|||||||
model = Circuit
|
model = Circuit
|
||||||
fields = [
|
fields = [
|
||||||
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate',
|
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate',
|
||||||
'description', 'comments',
|
'description', 'comments', 'tags'
|
||||||
]
|
]
|
||||||
|
@ -20,7 +20,7 @@ __all__ = (
|
|||||||
class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Provider
|
model = Provider
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id')),
|
||||||
('ASN', ('asn',)),
|
('ASN', ('asn',)),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
||||||
@ -59,7 +59,7 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
|
class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
|
||||||
model = ProviderNetwork
|
model = ProviderNetwork
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('provider_id', 'service_id')),
|
('Attributes', ('provider_id', 'service_id')),
|
||||||
)
|
)
|
||||||
provider_id = DynamicModelMultipleChoiceField(
|
provider_id = DynamicModelMultipleChoiceField(
|
||||||
@ -82,7 +82,7 @@ class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
|
|||||||
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Provider', ('provider_id', 'provider_network_id')),
|
('Provider', ('provider_id', 'provider_network_id')),
|
||||||
('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')),
|
('Attributes', ('type_id', 'status', 'install_date', 'termination_date', 'commit_rate')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id')),
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from django import forms
|
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
@ -7,8 +6,8 @@ from ipam.models import ASN
|
|||||||
from netbox.forms import NetBoxModelForm
|
from netbox.forms import NetBoxModelForm
|
||||||
from tenancy.forms import TenancyForm
|
from tenancy.forms import TenancyForm
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
BootstrapMixin, CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SelectSpeedWidget, SlugField,
|
||||||
SelectSpeedWidget, SmallTextarea, SlugField, StaticSelect,
|
StaticSelect,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -30,14 +29,14 @@ class ProviderForm(NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Provider', ('name', 'slug', 'asns', 'tags')),
|
('Provider', ('name', 'slug', 'asns', 'description', 'tags')),
|
||||||
('Support Info', ('account',)),
|
('Support Info', ('account',)),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'slug', 'account', 'asns', 'comments', 'tags',
|
'name', 'slug', 'account', 'asns', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'name': "Full name of the provider",
|
'name': "Full name of the provider",
|
||||||
@ -64,6 +63,12 @@ class ProviderNetworkForm(NetBoxModelForm):
|
|||||||
class CircuitTypeForm(NetBoxModelForm):
|
class CircuitTypeForm(NetBoxModelForm):
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Circuit Type', (
|
||||||
|
'name', 'slug', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
fields = [
|
fields = [
|
@ -1,6 +1,8 @@
|
|||||||
|
import graphene
|
||||||
|
|
||||||
from circuits import filtersets, models
|
from circuits import filtersets, models
|
||||||
from dcim.graphql.mixins import CabledObjectMixin
|
from dcim.graphql.mixins import CabledObjectMixin
|
||||||
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
|
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin, ContactsMixin
|
||||||
from netbox.graphql.types import ObjectType, OrganizationalObjectType, NetBoxObjectType
|
from netbox.graphql.types import ObjectType, OrganizationalObjectType, NetBoxObjectType
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -20,8 +22,7 @@ class CircuitTerminationType(CustomFieldsMixin, TagsMixin, CabledObjectMixin, Ob
|
|||||||
filterset_class = filtersets.CircuitTerminationFilterSet
|
filterset_class = filtersets.CircuitTerminationFilterSet
|
||||||
|
|
||||||
|
|
||||||
class CircuitType(NetBoxObjectType):
|
class CircuitType(NetBoxObjectType, ContactsMixin):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Circuit
|
model = models.Circuit
|
||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
@ -36,7 +37,7 @@ class CircuitTypeType(OrganizationalObjectType):
|
|||||||
filterset_class = filtersets.CircuitTypeFilterSet
|
filterset_class = filtersets.CircuitTypeFilterSet
|
||||||
|
|
||||||
|
|
||||||
class ProviderType(NetBoxObjectType):
|
class ProviderType(NetBoxObjectType, ContactsMixin):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Provider
|
model = models.Provider
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import dcim.fields
|
import dcim.fields
|
||||||
import django.core.serializers.json
|
from utilities.json import CustomFieldJSONEncoder
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('cid', models.CharField(max_length=100)),
|
('cid', models.CharField(max_length=100)),
|
||||||
('status', models.CharField(default='active', max_length=50)),
|
('status', models.CharField(default='active', max_length=50)),
|
||||||
@ -58,14 +58,14 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -73,7 +73,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -93,7 +93,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100)),
|
('name', models.CharField(max_length=100)),
|
||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import django.core.serializers.json
|
from utilities.json import CustomFieldJSONEncoder
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import taggit.managers
|
import taggit.managers
|
||||||
|
|
||||||
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='circuittermination',
|
model_name='circuittermination',
|
||||||
name='custom_field_data',
|
name='custom_field_data',
|
||||||
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
|
field=models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder),
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='circuittermination',
|
model_name='circuittermination',
|
||||||
|
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.2 on 2022-11-03 18:24
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('circuits', '0040_provider_remove_deprecated_fields'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='provider',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
]
|
@ -7,7 +7,7 @@ from django.urls import reverse
|
|||||||
from circuits.choices import *
|
from circuits.choices import *
|
||||||
from dcim.models import CabledObjectModel
|
from dcim.models import CabledObjectModel
|
||||||
from netbox.models import (
|
from netbox.models import (
|
||||||
ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, NetBoxModel, TagsMixin,
|
ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, PrimaryModel, TagsMixin,
|
||||||
)
|
)
|
||||||
from netbox.models.features import WebhooksMixin
|
from netbox.models.features import WebhooksMixin
|
||||||
|
|
||||||
@ -23,30 +23,11 @@ class CircuitType(OrganizationalModel):
|
|||||||
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
|
Circuits can be organized by their functional role. For example, a user might wish to define CircuitTypes named
|
||||||
"Long Haul," "Metro," or "Out-of-Band".
|
"Long Haul," "Metro," or "Out-of-Band".
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('circuits:circuittype', args=[self.pk])
|
return reverse('circuits:circuittype', args=[self.pk])
|
||||||
|
|
||||||
|
|
||||||
class Circuit(NetBoxModel):
|
class Circuit(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
A communications circuit connects two points. Each Circuit belongs to a Provider; Providers may have multiple
|
A communications circuit connects two points. Each Circuit belongs to a Provider; Providers may have multiple
|
||||||
circuits. Each circuit is also assigned a CircuitType and a Site. Circuit port speed and commit rate are measured
|
circuits. Each circuit is also assigned a CircuitType and a Site. Circuit port speed and commit rate are measured
|
||||||
@ -92,13 +73,6 @@ class Circuit(NetBoxModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True,
|
null=True,
|
||||||
verbose_name='Commit rate (Kbps)')
|
verbose_name='Commit rate (Kbps)')
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
contacts = GenericRelation(
|
contacts = GenericRelation(
|
||||||
|
@ -2,8 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
|||||||
from django.db import models
|
from django.db import models
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from dcim.fields import ASNField
|
from netbox.models import PrimaryModel
|
||||||
from netbox.models import NetBoxModel
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ProviderNetwork',
|
'ProviderNetwork',
|
||||||
@ -11,7 +10,7 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class Provider(NetBoxModel):
|
class Provider(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model
|
Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model
|
||||||
stores information pertinent to the user's relationship with the Provider.
|
stores information pertinent to the user's relationship with the Provider.
|
||||||
@ -34,9 +33,6 @@ class Provider(NetBoxModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
verbose_name='Account number'
|
verbose_name='Account number'
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
contacts = GenericRelation(
|
contacts = GenericRelation(
|
||||||
@ -57,7 +53,7 @@ class Provider(NetBoxModel):
|
|||||||
return reverse('circuits:provider', args=[self.pk])
|
return reverse('circuits:provider', args=[self.pk])
|
||||||
|
|
||||||
|
|
||||||
class ProviderNetwork(NetBoxModel):
|
class ProviderNetwork(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
This represents a provider network which exists outside of NetBox, the details of which are unknown or
|
This represents a provider network which exists outside of NetBox, the details of which are unknown or
|
||||||
unimportant to the user.
|
unimportant to the user.
|
||||||
@ -75,13 +71,6 @@ class ProviderNetwork(NetBoxModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
verbose_name='Service ID'
|
verbose_name='Service ID'
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('provider', 'name')
|
ordering = ('provider', 'name')
|
||||||
|
55
netbox/circuits/search.py
Normal file
55
netbox/circuits/search.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
from netbox.search import SearchIndex, register_search
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class CircuitIndex(SearchIndex):
|
||||||
|
model = models.Circuit
|
||||||
|
fields = (
|
||||||
|
('cid', 100),
|
||||||
|
('description', 500),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class CircuitTerminationIndex(SearchIndex):
|
||||||
|
model = models.CircuitTermination
|
||||||
|
fields = (
|
||||||
|
('xconnect_id', 300),
|
||||||
|
('pp_info', 300),
|
||||||
|
('description', 500),
|
||||||
|
('port_speed', 2000),
|
||||||
|
('upstream_speed', 2000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class CircuitTypeIndex(SearchIndex):
|
||||||
|
model = models.CircuitType
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ProviderIndex(SearchIndex):
|
||||||
|
model = models.Provider
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('account', 200),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ProviderNetworkIndex(SearchIndex):
|
||||||
|
model = models.ProviderNetwork
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('service_id', 200),
|
||||||
|
('description', 500),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
@ -1,8 +1,9 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
|
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
|
||||||
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
from tenancy.tables import TenancyColumnsMixin
|
|
||||||
from .columns import CommitRateColumn
|
from .columns import CommitRateColumn
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -39,7 +40,7 @@ class CircuitTypeTable(NetBoxTable):
|
|||||||
default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
|
default_columns = ('pk', 'name', 'circuit_count', 'description', 'slug')
|
||||||
|
|
||||||
|
|
||||||
class CircuitTable(TenancyColumnsMixin, NetBoxTable):
|
class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
cid = tables.Column(
|
cid = tables.Column(
|
||||||
linkify=True,
|
linkify=True,
|
||||||
verbose_name='Circuit ID'
|
verbose_name='Circuit ID'
|
||||||
@ -58,9 +59,6 @@ class CircuitTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
)
|
)
|
||||||
commit_rate = CommitRateColumn()
|
commit_rate = CommitRateColumn()
|
||||||
comments = columns.MarkdownColumn()
|
comments = columns.MarkdownColumn()
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='circuits:circuit_list'
|
url_name='circuits:circuit_list'
|
||||||
)
|
)
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
from django_tables2.utils import Accessor
|
|
||||||
|
|
||||||
from circuits.models import *
|
from circuits.models import *
|
||||||
|
from django_tables2.utils import Accessor
|
||||||
|
from tenancy.tables import ContactsColumnMixin
|
||||||
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -10,7 +11,7 @@ __all__ = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ProviderTable(NetBoxTable):
|
class ProviderTable(ContactsColumnMixin, NetBoxTable):
|
||||||
name = tables.Column(
|
name = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -31,9 +32,6 @@ class ProviderTable(NetBoxTable):
|
|||||||
verbose_name='Circuits'
|
verbose_name='Circuits'
|
||||||
)
|
)
|
||||||
comments = columns.MarkdownColumn()
|
comments = columns.MarkdownColumn()
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='circuits:provider_list'
|
url_name='circuits:provider_list'
|
||||||
)
|
)
|
||||||
@ -41,8 +39,8 @@ class ProviderTable(NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'asns', 'account', 'asn_count',
|
'pk', 'id', 'name', 'asns', 'account', 'asn_count', 'circuit_count', 'description', 'comments', 'contacts',
|
||||||
'circuit_count', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'name', 'account', 'circuit_count')
|
default_columns = ('pk', 'name', 'account', 'circuit_count')
|
||||||
|
|
||||||
|
@ -50,6 +50,13 @@ class ProviderTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Provider 6,provider-6",
|
"Provider 6,provider-6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,comments",
|
||||||
|
f"{providers[0].pk},Provider 7,New comment7",
|
||||||
|
f"{providers[1].pk},Provider 8,New comment8",
|
||||||
|
f"{providers[2].pk},Provider 9,New comment9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'account': '5678',
|
'account': '5678',
|
||||||
'comments': 'New comments',
|
'comments': 'New comments',
|
||||||
@ -62,11 +69,13 @@ class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
CircuitType.objects.bulk_create([
|
circuit_types = (
|
||||||
CircuitType(name='Circuit Type 1', slug='circuit-type-1'),
|
CircuitType(name='Circuit Type 1', slug='circuit-type-1'),
|
||||||
CircuitType(name='Circuit Type 2', slug='circuit-type-2'),
|
CircuitType(name='Circuit Type 2', slug='circuit-type-2'),
|
||||||
CircuitType(name='Circuit Type 3', slug='circuit-type-3'),
|
CircuitType(name='Circuit Type 3', slug='circuit-type-3'),
|
||||||
])
|
)
|
||||||
|
|
||||||
|
CircuitType.objects.bulk_create(circuit_types)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -84,6 +93,13 @@ class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Circuit Type 6,circuit-type-6",
|
"Circuit Type 6,circuit-type-6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{circuit_types[0].pk},Circuit Type 7,New description7",
|
||||||
|
f"{circuit_types[1].pk},Circuit Type 8,New description8",
|
||||||
|
f"{circuit_types[2].pk},Circuit Type 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'description': 'Foo',
|
'description': 'Foo',
|
||||||
}
|
}
|
||||||
@ -107,11 +123,13 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
)
|
)
|
||||||
CircuitType.objects.bulk_create(circuittypes)
|
CircuitType.objects.bulk_create(circuittypes)
|
||||||
|
|
||||||
Circuit.objects.bulk_create([
|
circuits = (
|
||||||
Circuit(cid='Circuit 1', provider=providers[0], type=circuittypes[0]),
|
Circuit(cid='Circuit 1', provider=providers[0], type=circuittypes[0]),
|
||||||
Circuit(cid='Circuit 2', provider=providers[0], type=circuittypes[0]),
|
Circuit(cid='Circuit 2', provider=providers[0], type=circuittypes[0]),
|
||||||
Circuit(cid='Circuit 3', provider=providers[0], type=circuittypes[0]),
|
Circuit(cid='Circuit 3', provider=providers[0], type=circuittypes[0]),
|
||||||
])
|
)
|
||||||
|
|
||||||
|
Circuit.objects.bulk_create(circuits)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -136,6 +154,13 @@ class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Circuit 6,Provider 1,Circuit Type 1,active",
|
"Circuit 6,Provider 1,Circuit Type 1,active",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
f"id,cid,description,status",
|
||||||
|
f"{circuits[0].pk},Circuit 7,New description7,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
|
||||||
|
f"{circuits[1].pk},Circuit 8,New description8,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
|
||||||
|
f"{circuits[2].pk},Circuit 9,New description9,{CircuitStatusChoices.STATUS_DECOMMISSIONED}",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'provider': providers[1].pk,
|
'provider': providers[1].pk,
|
||||||
'type': circuittypes[1].pk,
|
'type': circuittypes[1].pk,
|
||||||
@ -159,11 +184,13 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
)
|
)
|
||||||
Provider.objects.bulk_create(providers)
|
Provider.objects.bulk_create(providers)
|
||||||
|
|
||||||
ProviderNetwork.objects.bulk_create([
|
provider_networks = (
|
||||||
ProviderNetwork(name='Provider Network 1', provider=providers[0]),
|
ProviderNetwork(name='Provider Network 1', provider=providers[0]),
|
||||||
ProviderNetwork(name='Provider Network 2', provider=providers[0]),
|
ProviderNetwork(name='Provider Network 2', provider=providers[0]),
|
||||||
ProviderNetwork(name='Provider Network 3', provider=providers[0]),
|
ProviderNetwork(name='Provider Network 3', provider=providers[0]),
|
||||||
])
|
)
|
||||||
|
|
||||||
|
ProviderNetwork.objects.bulk_create(provider_networks)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -182,6 +209,13 @@ class ProviderNetworkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Provider Network 6,Provider 1,Baz",
|
"Provider Network 6,Provider 1,Baz",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{provider_networks[0].pk},Provider Network 7,New description7",
|
||||||
|
f"{provider_networks[1].pk},Provider Network 8,New description8",
|
||||||
|
f"{provider_networks[2].pk},Provider Network 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'provider': providers[1].pk,
|
'provider': providers[1].pk,
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
from django.urls import path
|
from django.urls import include, path
|
||||||
|
|
||||||
from dcim.views import PathTraceView
|
from utilities.urls import get_model_urls
|
||||||
from netbox.views.generic import ObjectChangeLogView, ObjectJournalView
|
|
||||||
from . import views
|
from . import views
|
||||||
from .models import *
|
|
||||||
|
|
||||||
app_name = 'circuits'
|
app_name = 'circuits'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -14,11 +12,7 @@ urlpatterns = [
|
|||||||
path('providers/import/', views.ProviderBulkImportView.as_view(), name='provider_import'),
|
path('providers/import/', views.ProviderBulkImportView.as_view(), name='provider_import'),
|
||||||
path('providers/edit/', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
|
path('providers/edit/', views.ProviderBulkEditView.as_view(), name='provider_bulk_edit'),
|
||||||
path('providers/delete/', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
|
path('providers/delete/', views.ProviderBulkDeleteView.as_view(), name='provider_bulk_delete'),
|
||||||
path('providers/<int:pk>/', views.ProviderView.as_view(), name='provider'),
|
path('providers/<int:pk>/', include(get_model_urls('circuits', 'provider'))),
|
||||||
path('providers/<int:pk>/edit/', views.ProviderEditView.as_view(), name='provider_edit'),
|
|
||||||
path('providers/<int:pk>/delete/', views.ProviderDeleteView.as_view(), name='provider_delete'),
|
|
||||||
path('providers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='provider_changelog', kwargs={'model': Provider}),
|
|
||||||
path('providers/<int:pk>/journal/', ObjectJournalView.as_view(), name='provider_journal', kwargs={'model': Provider}),
|
|
||||||
|
|
||||||
# Provider networks
|
# Provider networks
|
||||||
path('provider-networks/', views.ProviderNetworkListView.as_view(), name='providernetwork_list'),
|
path('provider-networks/', views.ProviderNetworkListView.as_view(), name='providernetwork_list'),
|
||||||
@ -26,11 +20,7 @@ urlpatterns = [
|
|||||||
path('provider-networks/import/', views.ProviderNetworkBulkImportView.as_view(), name='providernetwork_import'),
|
path('provider-networks/import/', views.ProviderNetworkBulkImportView.as_view(), name='providernetwork_import'),
|
||||||
path('provider-networks/edit/', views.ProviderNetworkBulkEditView.as_view(), name='providernetwork_bulk_edit'),
|
path('provider-networks/edit/', views.ProviderNetworkBulkEditView.as_view(), name='providernetwork_bulk_edit'),
|
||||||
path('provider-networks/delete/', views.ProviderNetworkBulkDeleteView.as_view(), name='providernetwork_bulk_delete'),
|
path('provider-networks/delete/', views.ProviderNetworkBulkDeleteView.as_view(), name='providernetwork_bulk_delete'),
|
||||||
path('provider-networks/<int:pk>/', views.ProviderNetworkView.as_view(), name='providernetwork'),
|
path('provider-networks/<int:pk>/', include(get_model_urls('circuits', 'providernetwork'))),
|
||||||
path('provider-networks/<int:pk>/edit/', views.ProviderNetworkEditView.as_view(), name='providernetwork_edit'),
|
|
||||||
path('provider-networks/<int:pk>/delete/', views.ProviderNetworkDeleteView.as_view(), name='providernetwork_delete'),
|
|
||||||
path('provider-networks/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='providernetwork_changelog', kwargs={'model': ProviderNetwork}),
|
|
||||||
path('provider-networks/<int:pk>/journal/', ObjectJournalView.as_view(), name='providernetwork_journal', kwargs={'model': ProviderNetwork}),
|
|
||||||
|
|
||||||
# Circuit types
|
# Circuit types
|
||||||
path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'),
|
path('circuit-types/', views.CircuitTypeListView.as_view(), name='circuittype_list'),
|
||||||
@ -38,10 +28,7 @@ urlpatterns = [
|
|||||||
path('circuit-types/import/', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
|
path('circuit-types/import/', views.CircuitTypeBulkImportView.as_view(), name='circuittype_import'),
|
||||||
path('circuit-types/edit/', views.CircuitTypeBulkEditView.as_view(), name='circuittype_bulk_edit'),
|
path('circuit-types/edit/', views.CircuitTypeBulkEditView.as_view(), name='circuittype_bulk_edit'),
|
||||||
path('circuit-types/delete/', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
|
path('circuit-types/delete/', views.CircuitTypeBulkDeleteView.as_view(), name='circuittype_bulk_delete'),
|
||||||
path('circuit-types/<int:pk>/', views.CircuitTypeView.as_view(), name='circuittype'),
|
path('circuit-types/<int:pk>/', include(get_model_urls('circuits', 'circuittype'))),
|
||||||
path('circuit-types/<int:pk>/edit/', views.CircuitTypeEditView.as_view(), name='circuittype_edit'),
|
|
||||||
path('circuit-types/<int:pk>/delete/', views.CircuitTypeDeleteView.as_view(), name='circuittype_delete'),
|
|
||||||
path('circuit-types/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='circuittype_changelog', kwargs={'model': CircuitType}),
|
|
||||||
|
|
||||||
# Circuits
|
# Circuits
|
||||||
path('circuits/', views.CircuitListView.as_view(), name='circuit_list'),
|
path('circuits/', views.CircuitListView.as_view(), name='circuit_list'),
|
||||||
@ -49,17 +36,11 @@ urlpatterns = [
|
|||||||
path('circuits/import/', views.CircuitBulkImportView.as_view(), name='circuit_import'),
|
path('circuits/import/', views.CircuitBulkImportView.as_view(), name='circuit_import'),
|
||||||
path('circuits/edit/', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'),
|
path('circuits/edit/', views.CircuitBulkEditView.as_view(), name='circuit_bulk_edit'),
|
||||||
path('circuits/delete/', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'),
|
path('circuits/delete/', views.CircuitBulkDeleteView.as_view(), name='circuit_bulk_delete'),
|
||||||
path('circuits/<int:pk>/', views.CircuitView.as_view(), name='circuit'),
|
|
||||||
path('circuits/<int:pk>/edit/', views.CircuitEditView.as_view(), name='circuit_edit'),
|
|
||||||
path('circuits/<int:pk>/delete/', views.CircuitDeleteView.as_view(), name='circuit_delete'),
|
|
||||||
path('circuits/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='circuit_changelog', kwargs={'model': Circuit}),
|
|
||||||
path('circuits/<int:pk>/journal/', ObjectJournalView.as_view(), name='circuit_journal', kwargs={'model': Circuit}),
|
|
||||||
path('circuits/<int:pk>/terminations/swap/', views.CircuitSwapTerminations.as_view(), name='circuit_terminations_swap'),
|
path('circuits/<int:pk>/terminations/swap/', views.CircuitSwapTerminations.as_view(), name='circuit_terminations_swap'),
|
||||||
|
path('circuits/<int:pk>/', include(get_model_urls('circuits', 'circuit'))),
|
||||||
|
|
||||||
# Circuit terminations
|
# Circuit terminations
|
||||||
path('circuit-terminations/add/', views.CircuitTerminationEditView.as_view(), name='circuittermination_add'),
|
path('circuit-terminations/add/', views.CircuitTerminationEditView.as_view(), name='circuittermination_add'),
|
||||||
path('circuit-terminations/<int:pk>/edit/', views.CircuitTerminationEditView.as_view(), name='circuittermination_edit'),
|
path('circuit-terminations/<int:pk>/', include(get_model_urls('circuits', 'circuittermination'))),
|
||||||
path('circuit-terminations/<int:pk>/delete/', views.CircuitTerminationDeleteView.as_view(), name='circuittermination_delete'),
|
|
||||||
path('circuit-terminations/<int:pk>/trace/', PathTraceView.as_view(), name='circuittermination_trace', kwargs={'model': CircuitTermination}),
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
@ -3,9 +3,11 @@ from django.db import transaction
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.shortcuts import get_object_or_404, redirect, render
|
from django.shortcuts import get_object_or_404, redirect, render
|
||||||
|
|
||||||
|
from dcim.views import PathTraceView
|
||||||
from netbox.views import generic
|
from netbox.views import generic
|
||||||
from utilities.forms import ConfirmationForm
|
from utilities.forms import ConfirmationForm
|
||||||
from utilities.utils import count_related
|
from utilities.utils import count_related
|
||||||
|
from utilities.views import register_model_view
|
||||||
from . import filtersets, forms, tables
|
from . import filtersets, forms, tables
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
@ -23,6 +25,7 @@ class ProviderListView(generic.ObjectListView):
|
|||||||
table = tables.ProviderTable
|
table = tables.ProviderTable
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Provider)
|
||||||
class ProviderView(generic.ObjectView):
|
class ProviderView(generic.ObjectView):
|
||||||
queryset = Provider.objects.all()
|
queryset = Provider.objects.all()
|
||||||
|
|
||||||
@ -41,11 +44,13 @@ class ProviderView(generic.ObjectView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Provider, 'edit')
|
||||||
class ProviderEditView(generic.ObjectEditView):
|
class ProviderEditView(generic.ObjectEditView):
|
||||||
queryset = Provider.objects.all()
|
queryset = Provider.objects.all()
|
||||||
form = forms.ProviderForm
|
form = forms.ProviderForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Provider, 'delete')
|
||||||
class ProviderDeleteView(generic.ObjectDeleteView):
|
class ProviderDeleteView(generic.ObjectDeleteView):
|
||||||
queryset = Provider.objects.all()
|
queryset = Provider.objects.all()
|
||||||
|
|
||||||
@ -84,6 +89,7 @@ class ProviderNetworkListView(generic.ObjectListView):
|
|||||||
table = tables.ProviderNetworkTable
|
table = tables.ProviderNetworkTable
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(ProviderNetwork)
|
||||||
class ProviderNetworkView(generic.ObjectView):
|
class ProviderNetworkView(generic.ObjectView):
|
||||||
queryset = ProviderNetwork.objects.all()
|
queryset = ProviderNetwork.objects.all()
|
||||||
|
|
||||||
@ -103,11 +109,13 @@ class ProviderNetworkView(generic.ObjectView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(ProviderNetwork, 'edit')
|
||||||
class ProviderNetworkEditView(generic.ObjectEditView):
|
class ProviderNetworkEditView(generic.ObjectEditView):
|
||||||
queryset = ProviderNetwork.objects.all()
|
queryset = ProviderNetwork.objects.all()
|
||||||
form = forms.ProviderNetworkForm
|
form = forms.ProviderNetworkForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(ProviderNetwork, 'delete')
|
||||||
class ProviderNetworkDeleteView(generic.ObjectDeleteView):
|
class ProviderNetworkDeleteView(generic.ObjectDeleteView):
|
||||||
queryset = ProviderNetwork.objects.all()
|
queryset = ProviderNetwork.objects.all()
|
||||||
|
|
||||||
@ -144,6 +152,7 @@ class CircuitTypeListView(generic.ObjectListView):
|
|||||||
table = tables.CircuitTypeTable
|
table = tables.CircuitTypeTable
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(CircuitType)
|
||||||
class CircuitTypeView(generic.ObjectView):
|
class CircuitTypeView(generic.ObjectView):
|
||||||
queryset = CircuitType.objects.all()
|
queryset = CircuitType.objects.all()
|
||||||
|
|
||||||
@ -157,11 +166,13 @@ class CircuitTypeView(generic.ObjectView):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(CircuitType, 'edit')
|
||||||
class CircuitTypeEditView(generic.ObjectEditView):
|
class CircuitTypeEditView(generic.ObjectEditView):
|
||||||
queryset = CircuitType.objects.all()
|
queryset = CircuitType.objects.all()
|
||||||
form = forms.CircuitTypeForm
|
form = forms.CircuitTypeForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(CircuitType, 'delete')
|
||||||
class CircuitTypeDeleteView(generic.ObjectDeleteView):
|
class CircuitTypeDeleteView(generic.ObjectDeleteView):
|
||||||
queryset = CircuitType.objects.all()
|
queryset = CircuitType.objects.all()
|
||||||
|
|
||||||
@ -202,15 +213,18 @@ class CircuitListView(generic.ObjectListView):
|
|||||||
table = tables.CircuitTable
|
table = tables.CircuitTable
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Circuit)
|
||||||
class CircuitView(generic.ObjectView):
|
class CircuitView(generic.ObjectView):
|
||||||
queryset = Circuit.objects.all()
|
queryset = Circuit.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Circuit, 'edit')
|
||||||
class CircuitEditView(generic.ObjectEditView):
|
class CircuitEditView(generic.ObjectEditView):
|
||||||
queryset = Circuit.objects.all()
|
queryset = Circuit.objects.all()
|
||||||
form = forms.CircuitForm
|
form = forms.CircuitForm
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(Circuit, 'delete')
|
||||||
class CircuitDeleteView(generic.ObjectDeleteView):
|
class CircuitDeleteView(generic.ObjectDeleteView):
|
||||||
queryset = Circuit.objects.all()
|
queryset = Circuit.objects.all()
|
||||||
|
|
||||||
@ -318,11 +332,17 @@ class CircuitSwapTerminations(generic.ObjectEditView):
|
|||||||
# Circuit terminations
|
# Circuit terminations
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@register_model_view(CircuitTermination, 'edit')
|
||||||
class CircuitTerminationEditView(generic.ObjectEditView):
|
class CircuitTerminationEditView(generic.ObjectEditView):
|
||||||
queryset = CircuitTermination.objects.all()
|
queryset = CircuitTermination.objects.all()
|
||||||
form = forms.CircuitTerminationForm
|
form = forms.CircuitTerminationForm
|
||||||
template_name = 'circuits/circuittermination_edit.html'
|
template_name = 'circuits/circuittermination_edit.html'
|
||||||
|
|
||||||
|
|
||||||
|
@register_model_view(CircuitTermination, 'delete')
|
||||||
class CircuitTerminationDeleteView(generic.ObjectDeleteView):
|
class CircuitTerminationDeleteView(generic.ObjectDeleteView):
|
||||||
queryset = CircuitTermination.objects.all()
|
queryset = CircuitTermination.objects.all()
|
||||||
|
|
||||||
|
|
||||||
|
# Trace view
|
||||||
|
register_model_view(CircuitTermination, 'trace', kwargs={'model': CircuitTermination})(PathTraceView)
|
||||||
|
@ -130,7 +130,7 @@ class SiteSerializer(NetBoxModelSerializer):
|
|||||||
region = NestedRegionSerializer(required=False, allow_null=True)
|
region = NestedRegionSerializer(required=False, allow_null=True)
|
||||||
group = NestedSiteGroupSerializer(required=False, allow_null=True)
|
group = NestedSiteGroupSerializer(required=False, allow_null=True)
|
||||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||||
time_zone = TimeZoneSerializerField(required=False)
|
time_zone = TimeZoneSerializerField(required=False, allow_null=True)
|
||||||
asns = SerializedPKRelatedField(
|
asns = SerializedPKRelatedField(
|
||||||
queryset=ASN.objects.all(),
|
queryset=ASN.objects.all(),
|
||||||
serializer=NestedASNSerializer,
|
serializer=NestedASNSerializer,
|
||||||
@ -201,6 +201,7 @@ class RackSerializer(NetBoxModelSerializer):
|
|||||||
default=None)
|
default=None)
|
||||||
width = ChoiceField(choices=RackWidthChoices, required=False)
|
width = ChoiceField(choices=RackWidthChoices, required=False)
|
||||||
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
|
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
|
||||||
|
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
|
||||||
device_count = serializers.IntegerField(read_only=True)
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
powerfeed_count = serializers.IntegerField(read_only=True)
|
powerfeed_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
@ -208,8 +209,9 @@ class RackSerializer(NetBoxModelSerializer):
|
|||||||
model = Rack
|
model = Rack
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial',
|
'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial',
|
||||||
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
|
'asset_tag', 'type', 'width', 'u_height', 'weight', 'weight_unit', 'desc_units', 'outer_width',
|
||||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
|
'outer_depth', 'outer_unit', 'mounting_depth', 'description', 'comments', 'tags', 'custom_fields',
|
||||||
|
'created', 'last_updated', 'device_count', 'powerfeed_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -241,8 +243,8 @@ class RackReservationSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description', 'tags',
|
'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description',
|
||||||
'custom_fields',
|
'comments', 'tags', 'custom_fields',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -315,27 +317,28 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
|
|||||||
)
|
)
|
||||||
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)
|
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)
|
||||||
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
|
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
|
||||||
|
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
|
||||||
device_count = serializers.IntegerField(read_only=True)
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
|
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
|
||||||
'subdevice_role', 'airflow', 'front_image', 'rear_image', 'comments', 'tags', 'custom_fields', 'created',
|
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'description',
|
||||||
'last_updated', 'device_count',
|
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ModuleTypeSerializer(NetBoxModelSerializer):
|
class ModuleTypeSerializer(NetBoxModelSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
|
||||||
manufacturer = NestedManufacturerSerializer()
|
manufacturer = NestedManufacturerSerializer()
|
||||||
# module_count = serializers.IntegerField(read_only=True)
|
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'comments', 'tags', 'custom_fields',
|
'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description',
|
||||||
'created', 'last_updated',
|
'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -652,8 +655,8 @@ class DeviceSerializer(NetBoxModelSerializer):
|
|||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
|
'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag',
|
||||||
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
|
'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip',
|
||||||
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments',
|
'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description',
|
||||||
'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
'comments', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
|
@swagger_serializer_method(serializer_or_field=NestedDeviceSerializer)
|
||||||
@ -677,8 +680,8 @@ class ModuleSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Module
|
model = Module
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'comments', 'tags',
|
'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'description',
|
||||||
'custom_fields', 'created', 'last_updated',
|
'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -1016,7 +1019,7 @@ class CableSerializer(NetBoxModelSerializer):
|
|||||||
model = Cable
|
model = Cable
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'label', 'color',
|
'id', 'url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'label', 'color',
|
||||||
'length', 'length_unit', 'tags', 'custom_fields', 'created', 'last_updated',
|
'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -1082,8 +1085,8 @@ class VirtualChassisSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'name', 'domain', 'master', 'tags', 'custom_fields', 'member_count',
|
'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields',
|
||||||
'created', 'last_updated',
|
'member_count', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -1104,8 +1107,8 @@ class PowerPanelSerializer(NetBoxModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'site', 'location', 'name', 'tags', 'custom_fields', 'powerfeed_count',
|
'id', 'url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags', 'custom_fields',
|
||||||
'created', 'last_updated',
|
'powerfeed_count', 'created', 'last_updated',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -1138,7 +1141,7 @@ class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
|
|||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
|
'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
|
||||||
'amperage', 'max_utilization', 'comments', 'mark_connected', 'cable', 'cable_end', 'link_peers',
|
'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
|
||||||
'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable',
|
'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'description',
|
||||||
'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
|
'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
|
||||||
]
|
]
|
||||||
|
@ -8,7 +8,7 @@ class DCIMConfig(AppConfig):
|
|||||||
verbose_name = "DCIM"
|
verbose_name = "DCIM"
|
||||||
|
|
||||||
def ready(self):
|
def ready(self):
|
||||||
import dcim.signals
|
from . import signals, search
|
||||||
from .models import CableTermination
|
from .models import CableTermination
|
||||||
|
|
||||||
# Register denormalized fields
|
# Register denormalized fields
|
||||||
|
@ -1314,6 +1314,24 @@ class CableLengthUnitChoices(ChoiceSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class WeightUnitChoices(ChoiceSet):
|
||||||
|
|
||||||
|
# Metric
|
||||||
|
UNIT_KILOGRAM = 'kg'
|
||||||
|
UNIT_GRAM = 'g'
|
||||||
|
|
||||||
|
# Imperial
|
||||||
|
UNIT_POUND = 'lb'
|
||||||
|
UNIT_OUNCE = 'oz'
|
||||||
|
|
||||||
|
CHOICES = (
|
||||||
|
(UNIT_KILOGRAM, 'Kilograms'),
|
||||||
|
(UNIT_GRAM, 'Grams'),
|
||||||
|
(UNIT_POUND, 'Pounds'),
|
||||||
|
(UNIT_OUNCE, 'Ounces'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# CableTerminations
|
# CableTerminations
|
||||||
#
|
#
|
||||||
|
@ -320,7 +320,7 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
|
|||||||
model = Rack
|
model = Rack
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
|
'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
|
||||||
'outer_unit',
|
'outer_unit', 'mounting_depth', 'weight', 'weight_unit'
|
||||||
]
|
]
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
@ -482,7 +482,7 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
'id', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit'
|
||||||
]
|
]
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
@ -576,7 +576,7 @@ class ModuleTypeFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = ['id', 'model', 'part_number']
|
fields = ['id', 'model', 'part_number', 'weight', 'weight_unit']
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -800,6 +800,12 @@ class DeviceFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilter
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label='Manufacturer (slug)',
|
label='Manufacturer (slug)',
|
||||||
)
|
)
|
||||||
|
device_type = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='device_type__slug',
|
||||||
|
queryset=DeviceType.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
label='Device type (slug)',
|
||||||
|
)
|
||||||
device_type_id = django_filters.ModelMultipleChoiceFilter(
|
device_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=DeviceType.objects.all(),
|
queryset=DeviceType.objects.all(),
|
||||||
label='Device type (ID)',
|
label='Device type (ID)',
|
||||||
@ -1360,7 +1366,7 @@ class InterfaceFilterSet(
|
|||||||
try:
|
try:
|
||||||
devices = Device.objects.filter(pk__in=id_list)
|
devices = Device.objects.filter(pk__in=id_list)
|
||||||
for device in devices:
|
for device in devices:
|
||||||
vc_interface_ids += device.vc_interfaces().values_list('id', flat=True)
|
vc_interface_ids += device.vc_interfaces(if_master=False).values_list('id', flat=True)
|
||||||
return queryset.filter(pk__in=vc_interface_ids)
|
return queryset.filter(pk__in=vc_interface_ids)
|
||||||
except Device.DoesNotExist:
|
except Device.DoesNotExist:
|
||||||
return queryset.none()
|
return queryset.none()
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from .models import *
|
from .model_forms import *
|
||||||
from .filtersets import *
|
from .filtersets import *
|
||||||
from .object_create import *
|
from .object_create import *
|
||||||
from .object_import import *
|
from .object_import import *
|
||||||
|
@ -127,22 +127,26 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label='Contact E-mail'
|
label='Contact E-mail'
|
||||||
)
|
)
|
||||||
description = forms.CharField(
|
|
||||||
max_length=100,
|
|
||||||
required=False
|
|
||||||
)
|
|
||||||
time_zone = TimeZoneFormField(
|
time_zone = TimeZoneFormField(
|
||||||
choices=add_blank_choice(TimeZoneFormField().choices),
|
choices=add_blank_choice(TimeZoneFormField().choices),
|
||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = Site
|
model = Site
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('status', 'region', 'group', 'tenant', 'asns', 'time_zone', 'description')),
|
(None, ('status', 'region', 'group', 'tenant', 'asns', 'time_zone', 'description')),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'region', 'group', 'tenant', 'asns', 'description', 'time_zone',
|
'region', 'group', 'tenant', 'asns', 'time_zone', 'description', 'comments',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -281,6 +285,24 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
|
mounting_depth = forms.IntegerField(
|
||||||
|
required=False,
|
||||||
|
min_value=1
|
||||||
|
)
|
||||||
|
weight = forms.DecimalField(
|
||||||
|
min_value=0,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
weight_unit = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(WeightUnitChoices),
|
||||||
|
required=False,
|
||||||
|
initial='',
|
||||||
|
widget=StaticSelect()
|
||||||
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
comments = CommentField(
|
comments = CommentField(
|
||||||
widget=SmallTextarea,
|
widget=SmallTextarea,
|
||||||
label='Comments'
|
label='Comments'
|
||||||
@ -288,12 +310,16 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = Rack
|
model = Rack
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag')),
|
('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag', 'description')),
|
||||||
('Location', ('region', 'site_group', 'site', 'location')),
|
('Location', ('region', 'site_group', 'site', 'location')),
|
||||||
('Hardware', ('type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit')),
|
('Hardware', (
|
||||||
|
'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth',
|
||||||
|
)),
|
||||||
|
('Weight', ('weight', 'weight_unit')),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments',
|
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight',
|
||||||
|
'weight_unit', 'description', 'comments',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -310,14 +336,19 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
description = forms.CharField(
|
description = forms.CharField(
|
||||||
max_length=100,
|
max_length=200,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('user', 'tenant', 'description')),
|
(None, ('user', 'tenant', 'description')),
|
||||||
)
|
)
|
||||||
|
nullable_fields = ('comments',)
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerBulkEditForm(NetBoxModelBulkEditForm):
|
class ManufacturerBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
@ -355,12 +386,31 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
|
weight = forms.DecimalField(
|
||||||
|
min_value=0,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
weight_unit = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(WeightUnitChoices),
|
||||||
|
required=False,
|
||||||
|
initial='',
|
||||||
|
widget=StaticSelect()
|
||||||
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow')),
|
('Device Type', ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')),
|
||||||
|
('Weight', ('weight', 'weight_unit')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('part_number', 'airflow')
|
nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
|
class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
@ -371,12 +421,31 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
part_number = forms.CharField(
|
part_number = forms.CharField(
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
weight = forms.DecimalField(
|
||||||
|
min_value=0,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
weight_unit = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(WeightUnitChoices),
|
||||||
|
required=False,
|
||||||
|
initial='',
|
||||||
|
widget=StaticSelect()
|
||||||
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('manufacturer', 'part_number')),
|
('Module Type', ('manufacturer', 'part_number', 'description')),
|
||||||
|
('Weight', ('weight', 'weight_unit')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('part_number',)
|
nullable_fields = ('part_number', 'weight', 'weight_unit', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
|
class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
@ -472,15 +541,23 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label='Serial Number'
|
label='Serial Number'
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = Device
|
model = Device
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Device', ('device_role', 'status', 'tenant', 'platform')),
|
('Device', ('device_role', 'status', 'tenant', 'platform', 'description')),
|
||||||
('Location', ('site', 'location')),
|
('Location', ('site', 'location')),
|
||||||
('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')),
|
('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'location', 'tenant', 'platform', 'serial', 'airflow',
|
'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -501,12 +578,20 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
label='Serial Number'
|
label='Serial Number'
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = Module
|
model = Module
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('manufacturer', 'module_type', 'serial')),
|
(None, ('manufacturer', 'module_type', 'serial', 'description')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('serial',)
|
nullable_fields = ('serial', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class CableBulkEditForm(NetBoxModelBulkEditForm):
|
class CableBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
@ -543,39 +628,44 @@ class CableBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
initial='',
|
initial='',
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = Cable
|
model = Cable
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('type', 'status', 'tenant', 'label')),
|
(None, ('type', 'status', 'tenant', 'label', 'description')),
|
||||||
('Attributes', ('color', 'length', 'length_unit')),
|
('Attributes', ('color', 'length', 'length_unit')),
|
||||||
)
|
)
|
||||||
nullable_fields = (
|
nullable_fields = (
|
||||||
'type', 'status', 'tenant', 'label', 'color', 'length',
|
'type', 'status', 'tenant', 'label', 'color', 'length', 'description', 'comments',
|
||||||
)
|
)
|
||||||
|
|
||||||
def clean(self):
|
|
||||||
super().clean()
|
|
||||||
|
|
||||||
# Validate length/unit
|
|
||||||
length = self.cleaned_data.get('length')
|
|
||||||
length_unit = self.cleaned_data.get('length_unit')
|
|
||||||
if length and not length_unit:
|
|
||||||
raise forms.ValidationError({
|
|
||||||
'length_unit': "Must specify a unit when setting length"
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
|
class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
domain = forms.CharField(
|
domain = forms.CharField(
|
||||||
max_length=30,
|
max_length=30,
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('domain',)),
|
(None, ('domain', 'description')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('domain',)
|
nullable_fields = ('domain', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
|
class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
@ -608,12 +698,20 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
'site_id': '$site'
|
'site_id': '$site'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
comments = CommentField(
|
||||||
|
widget=SmallTextarea,
|
||||||
|
label='Comments'
|
||||||
|
)
|
||||||
|
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('region', 'site_group', 'site', 'location')),
|
(None, ('region', 'site_group', 'site', 'location', 'description')),
|
||||||
)
|
)
|
||||||
nullable_fields = ('location',)
|
nullable_fields = ('location', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
|
class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
|
||||||
@ -662,6 +760,10 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
required=False,
|
required=False,
|
||||||
widget=BulkEditNullBooleanSelect
|
widget=BulkEditNullBooleanSelect
|
||||||
)
|
)
|
||||||
|
description = forms.CharField(
|
||||||
|
max_length=200,
|
||||||
|
required=False
|
||||||
|
)
|
||||||
comments = CommentField(
|
comments = CommentField(
|
||||||
widget=SmallTextarea,
|
widget=SmallTextarea,
|
||||||
label='Comments'
|
label='Comments'
|
||||||
@ -669,10 +771,10 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
|
|||||||
|
|
||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('power_panel', 'rack', 'status', 'type', 'mark_connected')),
|
(None, ('power_panel', 'rack', 'status', 'type', 'mark_connected', 'description')),
|
||||||
('Power', ('supply', 'phase', 'voltage', 'amperage', 'max_utilization'))
|
('Power', ('supply', 'phase', 'voltage', 'amperage', 'max_utilization'))
|
||||||
)
|
)
|
||||||
nullable_fields = ('location', 'comments')
|
nullable_fields = ('location', 'description', 'comments')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -56,7 +56,7 @@ class RegionCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Region
|
model = Region
|
||||||
fields = ('name', 'slug', 'parent', 'description')
|
fields = ('name', 'slug', 'parent', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class SiteGroupCSVForm(NetBoxModelCSVForm):
|
class SiteGroupCSVForm(NetBoxModelCSVForm):
|
||||||
@ -100,7 +100,7 @@ class SiteCSVForm(NetBoxModelCSVForm):
|
|||||||
model = Site
|
model = Site
|
||||||
fields = (
|
fields = (
|
||||||
'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'time_zone', 'description',
|
'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'time_zone', 'description',
|
||||||
'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments',
|
'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'tags'
|
||||||
)
|
)
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'time_zone': mark_safe(
|
'time_zone': mark_safe(
|
||||||
@ -137,7 +137,7 @@ class LocationCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Location
|
model = Location
|
||||||
fields = ('site', 'parent', 'name', 'slug', 'status', 'tenant', 'description')
|
fields = ('site', 'parent', 'name', 'slug', 'status', 'tenant', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class RackRoleCSVForm(NetBoxModelCSVForm):
|
class RackRoleCSVForm(NetBoxModelCSVForm):
|
||||||
@ -145,7 +145,7 @@ class RackRoleCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackRole
|
model = RackRole
|
||||||
fields = ('name', 'slug', 'color', 'description')
|
fields = ('name', 'slug', 'color', 'description', 'tags')
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
||||||
}
|
}
|
||||||
@ -196,7 +196,8 @@ class RackCSVForm(NetBoxModelCSVForm):
|
|||||||
model = Rack
|
model = Rack
|
||||||
fields = (
|
fields = (
|
||||||
'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag',
|
'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag',
|
||||||
'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'comments',
|
'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth',
|
||||||
|
'description', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
@ -240,7 +241,7 @@ class RackReservationCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = ('site', 'location', 'rack', 'units', 'tenant', 'description')
|
fields = ('site', 'location', 'rack', 'units', 'tenant', 'description', 'comments', 'tags')
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
super().__init__(data, *args, **kwargs)
|
super().__init__(data, *args, **kwargs)
|
||||||
@ -263,7 +264,7 @@ class ManufacturerCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
fields = ('name', 'slug', 'description')
|
fields = ('name', 'slug', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleCSVForm(NetBoxModelCSVForm):
|
class DeviceRoleCSVForm(NetBoxModelCSVForm):
|
||||||
@ -271,7 +272,7 @@ class DeviceRoleCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
fields = ('name', 'slug', 'color', 'vm_role', 'description')
|
fields = ('name', 'slug', 'color', 'vm_role', 'description', 'tags')
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
||||||
}
|
}
|
||||||
@ -288,7 +289,7 @@ class PlatformCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = ('name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description')
|
fields = ('name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class BaseDeviceCSVForm(NetBoxModelCSVForm):
|
class BaseDeviceCSVForm(NetBoxModelCSVForm):
|
||||||
@ -387,7 +388,7 @@ class DeviceCSVForm(BaseDeviceCSVForm):
|
|||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
||||||
'site', 'location', 'rack', 'position', 'face', 'airflow', 'virtual_chassis', 'vc_position', 'vc_priority',
|
'site', 'location', 'rack', 'position', 'face', 'airflow', 'virtual_chassis', 'vc_position', 'vc_priority',
|
||||||
'cluster', 'comments',
|
'cluster', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
@ -424,7 +425,7 @@ class ModuleCSVForm(NetBoxModelCSVForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Module
|
model = Module
|
||||||
fields = (
|
fields = (
|
||||||
'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'comments',
|
'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'description', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
@ -451,7 +452,7 @@ class ChildDeviceCSVForm(BaseDeviceCSVForm):
|
|||||||
class Meta(BaseDeviceCSVForm.Meta):
|
class Meta(BaseDeviceCSVForm.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
|
||||||
'parent', 'device_bay', 'virtual_chassis', 'vc_position', 'vc_priority', 'cluster', 'comments',
|
'parent', 'device_bay', 'virtual_chassis', 'vc_position', 'vc_priority', 'cluster', 'comments', 'tags'
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
@ -502,7 +503,7 @@ class ConsolePortCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePort
|
model = ConsolePort
|
||||||
fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description')
|
fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortCSVForm(NetBoxModelCSVForm):
|
class ConsoleServerPortCSVForm(NetBoxModelCSVForm):
|
||||||
@ -525,7 +526,7 @@ class ConsoleServerPortCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsoleServerPort
|
model = ConsoleServerPort
|
||||||
fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description')
|
fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class PowerPortCSVForm(NetBoxModelCSVForm):
|
class PowerPortCSVForm(NetBoxModelCSVForm):
|
||||||
@ -542,7 +543,7 @@ class PowerPortCSVForm(NetBoxModelCSVForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPort
|
model = PowerPort
|
||||||
fields = (
|
fields = (
|
||||||
'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description',
|
'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description', 'tags'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -570,13 +571,13 @@ class PowerOutletCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
fields = ('device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description')
|
fields = ('device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description', 'tags')
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Limit PowerPort choices to those belonging to this device (or VC master)
|
# Limit PowerPort choices to those belonging to this device (or VC master)
|
||||||
if self.is_bound:
|
if self.is_bound and 'device' in self.data:
|
||||||
try:
|
try:
|
||||||
device = self.fields['device'].to_python(self.data['device'])
|
device = self.fields['device'].to_python(self.data['device'])
|
||||||
except forms.ValidationError:
|
except forms.ValidationError:
|
||||||
@ -658,7 +659,7 @@ class InterfaceCSVForm(NetBoxModelCSVForm):
|
|||||||
fields = (
|
fields = (
|
||||||
'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled',
|
'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled',
|
||||||
'mark_connected', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode',
|
'mark_connected', 'mac_address', 'wwn', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode',
|
||||||
'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
|
'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags'
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
@ -701,7 +702,7 @@ class FrontPortCSVForm(NetBoxModelCSVForm):
|
|||||||
model = FrontPort
|
model = FrontPort
|
||||||
fields = (
|
fields = (
|
||||||
'device', 'name', 'label', 'type', 'color', 'mark_connected', 'rear_port', 'rear_port_position',
|
'device', 'name', 'label', 'type', 'color', 'mark_connected', 'rear_port', 'rear_port_position',
|
||||||
'description',
|
'description', 'tags'
|
||||||
)
|
)
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'rear_port_position': 'Mapped position on corresponding rear port',
|
'rear_port_position': 'Mapped position on corresponding rear port',
|
||||||
@ -711,7 +712,7 @@ class FrontPortCSVForm(NetBoxModelCSVForm):
|
|||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Limit RearPort choices to those belonging to this device (or VC master)
|
# Limit RearPort choices to those belonging to this device (or VC master)
|
||||||
if self.is_bound:
|
if self.is_bound and 'device' in self.data:
|
||||||
try:
|
try:
|
||||||
device = self.fields['device'].to_python(self.data['device'])
|
device = self.fields['device'].to_python(self.data['device'])
|
||||||
except forms.ValidationError:
|
except forms.ValidationError:
|
||||||
@ -742,7 +743,7 @@ class RearPortCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RearPort
|
model = RearPort
|
||||||
fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description')
|
fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description', 'tags')
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'positions': 'Number of front ports which may be mapped'
|
'positions': 'Number of front ports which may be mapped'
|
||||||
}
|
}
|
||||||
@ -756,7 +757,7 @@ class ModuleBayCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fields = ('device', 'name', 'label', 'position', 'description')
|
fields = ('device', 'name', 'label', 'position', 'description', 'tags')
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayCSVForm(NetBoxModelCSVForm):
|
class DeviceBayCSVForm(NetBoxModelCSVForm):
|
||||||
@ -776,13 +777,13 @@ class DeviceBayCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBay
|
model = DeviceBay
|
||||||
fields = ('device', 'name', 'label', 'installed_device', 'description')
|
fields = ('device', 'name', 'label', 'installed_device', 'description', 'tags')
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
# Limit installed device choices to devices of the correct type and location
|
# Limit installed device choices to devices of the correct type and location
|
||||||
if self.is_bound:
|
if self.is_bound and 'device' in self.data:
|
||||||
try:
|
try:
|
||||||
device = self.fields['device'].to_python(self.data['device'])
|
device = self.fields['device'].to_python(self.data['device'])
|
||||||
except forms.ValidationError:
|
except forms.ValidationError:
|
||||||
@ -831,7 +832,7 @@ class InventoryItemCSVForm(NetBoxModelCSVForm):
|
|||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
fields = (
|
fields = (
|
||||||
'device', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered',
|
'device', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'discovered',
|
||||||
'description',
|
'description', 'tags'
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@ -927,7 +928,7 @@ class CableCSVForm(NetBoxModelCSVForm):
|
|||||||
model = Cable
|
model = Cable
|
||||||
fields = [
|
fields = [
|
||||||
'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'type',
|
'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'type',
|
||||||
'status', 'tenant', 'label', 'color', 'length', 'length_unit',
|
'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
'color': mark_safe('RGB color in hexadecimal (e.g. <code>00ff00</code>)'),
|
||||||
@ -984,7 +985,7 @@ class VirtualChassisCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = ('name', 'domain', 'master')
|
fields = ('name', 'domain', 'master', 'description', 'comments', 'tags')
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -1005,7 +1006,7 @@ class PowerPanelCSVForm(NetBoxModelCSVForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = ('site', 'location', 'name')
|
fields = ('site', 'location', 'name', 'description', 'comments', 'tags')
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
super().__init__(data, *args, **kwargs)
|
super().__init__(data, *args, **kwargs)
|
||||||
@ -1061,7 +1062,7 @@ class PowerFeedCSVForm(NetBoxModelCSVForm):
|
|||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = (
|
fields = (
|
||||||
'site', 'power_panel', 'location', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase',
|
'site', 'power_panel', 'location', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase',
|
||||||
'voltage', 'amperage', 'max_utilization', 'comments',
|
'voltage', 'amperage', 'max_utilization', 'description', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, data=None, *args, **kwargs):
|
def __init__(self, data=None, *args, **kwargs):
|
||||||
|
@ -3,7 +3,7 @@ from django import forms
|
|||||||
from circuits.models import Circuit, CircuitTermination, Provider
|
from circuits.models import Circuit, CircuitTermination, Provider
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField
|
||||||
from .models import CableForm
|
from .model_forms import CableForm
|
||||||
|
|
||||||
|
|
||||||
def get_cable_form(a_type, b_type):
|
def get_cable_form(a_type, b_type):
|
||||||
@ -108,7 +108,7 @@ def get_cable_form(a_type, b_type):
|
|||||||
label='Power Feed',
|
label='Power Feed',
|
||||||
disabled_indicator='_occupied',
|
disabled_indicator='_occupied',
|
||||||
query_params={
|
query_params={
|
||||||
'powerpanel_id': f'$termination_{cable_end}_powerpanel',
|
'power_panel_id': f'$termination_{cable_end}_powerpanel',
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
|
|||||||
class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Region
|
model = Region
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag', 'parent_id')),
|
(None, ('q', 'filter', 'tag', 'parent_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group'))
|
('Contacts', ('contact', 'contact_role', 'contact_group'))
|
||||||
)
|
)
|
||||||
parent_id = DynamicModelMultipleChoiceField(
|
parent_id = DynamicModelMultipleChoiceField(
|
||||||
@ -130,7 +130,7 @@ class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = SiteGroup
|
model = SiteGroup
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag', 'parent_id')),
|
(None, ('q', 'filter', 'tag', 'parent_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group'))
|
('Contacts', ('contact', 'contact_role', 'contact_group'))
|
||||||
)
|
)
|
||||||
parent_id = DynamicModelMultipleChoiceField(
|
parent_id = DynamicModelMultipleChoiceField(
|
||||||
@ -144,7 +144,7 @@ class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Site
|
model = Site
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('status', 'region_id', 'group_id', 'asn_id')),
|
('Attributes', ('status', 'region_id', 'group_id', 'asn_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
||||||
@ -174,7 +174,7 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte
|
|||||||
class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Location
|
model = Location
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('region_id', 'site_group_id', 'site_id', 'parent_id', 'status')),
|
('Attributes', ('region_id', 'site_group_id', 'site_id', 'parent_id', 'status')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
||||||
@ -222,12 +222,13 @@ class RackRoleFilterForm(NetBoxModelFilterSetForm):
|
|||||||
class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Rack
|
model = Rack
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
|
||||||
('Function', ('status', 'role_id')),
|
('Function', ('status', 'role_id')),
|
||||||
('Hardware', ('type', 'width', 'serial', 'asset_tag')),
|
('Hardware', ('type', 'width', 'serial', 'asset_tag')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
||||||
|
('Weight', ('weight', 'weight_unit')),
|
||||||
)
|
)
|
||||||
region_id = DynamicModelMultipleChoiceField(
|
region_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=Region.objects.all(),
|
queryset=Region.objects.all(),
|
||||||
@ -281,6 +282,13 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte
|
|||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
weight = forms.DecimalField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
weight_unit = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(WeightUnitChoices),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RackElevationFilterForm(RackFilterForm):
|
class RackElevationFilterForm(RackFilterForm):
|
||||||
@ -298,7 +306,7 @@ class RackElevationFilterForm(RackFilterForm):
|
|||||||
class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('User', ('user_id',)),
|
('User', ('user_id',)),
|
||||||
('Rack', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
|
('Rack', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
@ -354,7 +362,7 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group'))
|
('Contacts', ('contact', 'contact_role', 'contact_group'))
|
||||||
)
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
@ -363,13 +371,14 @@ class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
|
class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Hardware', ('manufacturer_id', 'part_number', 'subdevice_role', 'airflow')),
|
('Hardware', ('manufacturer_id', 'part_number', 'subdevice_role', 'airflow')),
|
||||||
('Images', ('has_front_image', 'has_rear_image')),
|
('Images', ('has_front_image', 'has_rear_image')),
|
||||||
('Components', (
|
('Components', (
|
||||||
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
|
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
|
||||||
'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items',
|
'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items',
|
||||||
)),
|
)),
|
||||||
|
('Weight', ('weight', 'weight_unit')),
|
||||||
)
|
)
|
||||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=Manufacturer.objects.all(),
|
queryset=Manufacturer.objects.all(),
|
||||||
@ -465,17 +474,25 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
weight = forms.DecimalField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
weight_unit = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(WeightUnitChoices),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
|
class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Hardware', ('manufacturer_id', 'part_number')),
|
('Hardware', ('manufacturer_id', 'part_number')),
|
||||||
('Components', (
|
('Components', (
|
||||||
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
|
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
|
||||||
'pass_through_ports',
|
'pass_through_ports',
|
||||||
)),
|
)),
|
||||||
|
('Weight', ('weight', 'weight_unit')),
|
||||||
)
|
)
|
||||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||||
queryset=Manufacturer.objects.all(),
|
queryset=Manufacturer.objects.all(),
|
||||||
@ -529,6 +546,13 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
tag = TagFilterField(model)
|
tag = TagFilterField(model)
|
||||||
|
weight = forms.DecimalField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
weight_unit = forms.ChoiceField(
|
||||||
|
choices=add_blank_choice(WeightUnitChoices),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleFilterForm(NetBoxModelFilterSetForm):
|
class DeviceRoleFilterForm(NetBoxModelFilterSetForm):
|
||||||
@ -554,7 +578,7 @@ class DeviceFilterForm(
|
|||||||
):
|
):
|
||||||
model = Device
|
model = Device
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id')),
|
||||||
('Operation', ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')),
|
('Operation', ('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address')),
|
||||||
('Hardware', ('manufacturer_id', 'device_type_id', 'platform_id')),
|
('Hardware', ('manufacturer_id', 'device_type_id', 'platform_id')),
|
||||||
@ -707,7 +731,7 @@ class DeviceFilterForm(
|
|||||||
class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
|
class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Module
|
model = Module
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Hardware', ('manufacturer_id', 'module_type_id', 'serial', 'asset_tag')),
|
('Hardware', ('manufacturer_id', 'module_type_id', 'serial', 'asset_tag')),
|
||||||
)
|
)
|
||||||
manufacturer_id = DynamicModelMultipleChoiceField(
|
manufacturer_id = DynamicModelMultipleChoiceField(
|
||||||
@ -737,7 +761,7 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo
|
|||||||
class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
)
|
)
|
||||||
@ -766,7 +790,7 @@ class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = Cable
|
model = Cable
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('site_id', 'location_id', 'rack_id', 'device_id')),
|
('Location', ('site_id', 'location_id', 'rack_id', 'device_id')),
|
||||||
('Attributes', ('type', 'status', 'color', 'length', 'length_unit')),
|
('Attributes', ('type', 'status', 'color', 'length', 'length_unit')),
|
||||||
('Tenant', ('tenant_group_id', 'tenant_id')),
|
('Tenant', ('tenant_group_id', 'tenant_id')),
|
||||||
@ -838,7 +862,7 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id', 'location_id')),
|
||||||
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
('Contacts', ('contact', 'contact_role', 'contact_group')),
|
||||||
)
|
)
|
||||||
@ -876,7 +900,7 @@ class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
|
|||||||
class PowerFeedFilterForm(NetBoxModelFilterSetForm):
|
class PowerFeedFilterForm(NetBoxModelFilterSetForm):
|
||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Location', ('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id')),
|
('Location', ('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id')),
|
||||||
('Attributes', ('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization')),
|
('Attributes', ('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization')),
|
||||||
)
|
)
|
||||||
@ -978,7 +1002,7 @@ class PathEndpointFilterForm(CabledFilterForm):
|
|||||||
class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||||
model = ConsolePort
|
model = ConsolePort
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'type', 'speed')),
|
('Attributes', ('name', 'label', 'type', 'speed')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
('Connection', ('cabled', 'connected', 'occupied')),
|
('Connection', ('cabled', 'connected', 'occupied')),
|
||||||
@ -997,7 +1021,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
|||||||
class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||||
model = ConsoleServerPort
|
model = ConsoleServerPort
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'type', 'speed')),
|
('Attributes', ('name', 'label', 'type', 'speed')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
('Connection', ('cabled', 'connected', 'occupied')),
|
('Connection', ('cabled', 'connected', 'occupied')),
|
||||||
@ -1016,7 +1040,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF
|
|||||||
class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||||
model = PowerPort
|
model = PowerPort
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'type')),
|
('Attributes', ('name', 'label', 'type')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
('Connection', ('cabled', 'connected', 'occupied')),
|
('Connection', ('cabled', 'connected', 'occupied')),
|
||||||
@ -1031,7 +1055,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
|||||||
class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'type')),
|
('Attributes', ('name', 'label', 'type')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
('Connection', ('cabled', 'connected', 'occupied')),
|
('Connection', ('cabled', 'connected', 'occupied')),
|
||||||
@ -1046,7 +1070,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
|||||||
class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
||||||
model = Interface
|
model = Interface
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only')),
|
('Attributes', ('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only')),
|
||||||
('Addressing', ('vrf_id', 'mac_address', 'wwn')),
|
('Addressing', ('vrf_id', 'mac_address', 'wwn')),
|
||||||
('PoE', ('poe_mode', 'poe_type')),
|
('PoE', ('poe_mode', 'poe_type')),
|
||||||
@ -1135,7 +1159,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
|
|||||||
|
|
||||||
class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
|
class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'type', 'color')),
|
('Attributes', ('name', 'label', 'type', 'color')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
('Cable', ('cabled', 'occupied')),
|
('Cable', ('cabled', 'occupied')),
|
||||||
@ -1154,7 +1178,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
|
|||||||
class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
|
class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
|
||||||
model = RearPort
|
model = RearPort
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'type', 'color')),
|
('Attributes', ('name', 'label', 'type', 'color')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
('Cable', ('cabled', 'occupied')),
|
('Cable', ('cabled', 'occupied')),
|
||||||
@ -1172,7 +1196,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
|
|||||||
class ModuleBayFilterForm(DeviceComponentFilterForm):
|
class ModuleBayFilterForm(DeviceComponentFilterForm):
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'position')),
|
('Attributes', ('name', 'label', 'position')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
)
|
)
|
||||||
@ -1185,7 +1209,7 @@ class ModuleBayFilterForm(DeviceComponentFilterForm):
|
|||||||
class DeviceBayFilterForm(DeviceComponentFilterForm):
|
class DeviceBayFilterForm(DeviceComponentFilterForm):
|
||||||
model = DeviceBay
|
model = DeviceBay
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label')),
|
('Attributes', ('name', 'label')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
)
|
)
|
||||||
@ -1195,7 +1219,7 @@ class DeviceBayFilterForm(DeviceComponentFilterForm):
|
|||||||
class InventoryItemFilterForm(DeviceComponentFilterForm):
|
class InventoryItemFilterForm(DeviceComponentFilterForm):
|
||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, ('q', 'tag')),
|
(None, ('q', 'filter', 'tag')),
|
||||||
('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')),
|
('Attributes', ('name', 'label', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered')),
|
||||||
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
('Device', ('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'virtual_chassis_id', 'device_id')),
|
||||||
)
|
)
|
||||||
|
@ -78,6 +78,12 @@ class RegionForm(NetBoxModelForm):
|
|||||||
)
|
)
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Region', (
|
||||||
|
'parent', 'name', 'slug', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Region
|
model = Region
|
||||||
fields = (
|
fields = (
|
||||||
@ -92,6 +98,12 @@ class SiteGroupForm(NetBoxModelForm):
|
|||||||
)
|
)
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Site Group', (
|
||||||
|
'parent', 'name', 'slug', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SiteGroup
|
model = SiteGroup
|
||||||
fields = (
|
fields = (
|
||||||
@ -213,6 +225,12 @@ class LocationForm(TenancyForm, NetBoxModelForm):
|
|||||||
class RackRoleForm(NetBoxModelForm):
|
class RackRoleForm(NetBoxModelForm):
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Rack Role', (
|
||||||
|
'name', 'slug', 'color', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackRole
|
model = RackRole
|
||||||
fields = [
|
fields = [
|
||||||
@ -260,7 +278,7 @@ class RackForm(TenancyForm, NetBoxModelForm):
|
|||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status',
|
'region', 'site_group', 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status',
|
||||||
'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
|
'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
|
||||||
'outer_unit', 'comments', 'tags',
|
'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'site': "The site at which the rack exists",
|
'site': "The site at which the rack exists",
|
||||||
@ -273,6 +291,7 @@ class RackForm(TenancyForm, NetBoxModelForm):
|
|||||||
'type': StaticSelect(),
|
'type': StaticSelect(),
|
||||||
'width': StaticSelect(),
|
'width': StaticSelect(),
|
||||||
'outer_unit': StaticSelect(),
|
'outer_unit': StaticSelect(),
|
||||||
|
'weight_unit': StaticSelect(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -323,6 +342,7 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
|
|||||||
),
|
),
|
||||||
widget=StaticSelect()
|
widget=StaticSelect()
|
||||||
)
|
)
|
||||||
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Reservation', ('region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'description', 'tags')),
|
('Reservation', ('region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'description', 'tags')),
|
||||||
@ -333,13 +353,19 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
|
|||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'tenant_group', 'tenant',
|
'region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'tenant_group', 'tenant',
|
||||||
'description', 'tags',
|
'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerForm(NetBoxModelForm):
|
class ManufacturerForm(NetBoxModelForm):
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Manufacturer', (
|
||||||
|
'name', 'slug', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
fields = [
|
fields = [
|
||||||
@ -358,11 +384,12 @@ class DeviceTypeForm(NetBoxModelForm):
|
|||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Device Type', (
|
('Device Type', (
|
||||||
'manufacturer', 'model', 'slug', 'part_number', 'tags',
|
'manufacturer', 'model', 'slug', 'description', 'tags',
|
||||||
)),
|
)),
|
||||||
('Chassis', (
|
('Chassis', (
|
||||||
'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
'u_height', 'is_full_depth', 'part_number', 'subdevice_role', 'airflow',
|
||||||
)),
|
)),
|
||||||
|
('Attributes', ('weight', 'weight_unit')),
|
||||||
('Images', ('front_image', 'rear_image')),
|
('Images', ('front_image', 'rear_image')),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -370,7 +397,7 @@ class DeviceTypeForm(NetBoxModelForm):
|
|||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
||||||
'front_image', 'rear_image', 'comments', 'tags',
|
'weight', 'weight_unit', 'front_image', 'rear_image', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'airflow': StaticSelect(),
|
'airflow': StaticSelect(),
|
||||||
@ -380,7 +407,8 @@ class DeviceTypeForm(NetBoxModelForm):
|
|||||||
}),
|
}),
|
||||||
'rear_image': ClearableFileInput(attrs={
|
'rear_image': ClearableFileInput(attrs={
|
||||||
'accept': DEVICETYPE_IMAGE_FORMATS
|
'accept': DEVICETYPE_IMAGE_FORMATS
|
||||||
})
|
}),
|
||||||
|
'weight_unit': StaticSelect(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -391,21 +419,30 @@ class ModuleTypeForm(NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Module Type', (
|
('Module Type', ('manufacturer', 'model', 'part_number', 'description', 'tags')),
|
||||||
'manufacturer', 'model', 'part_number', 'tags',
|
('Weight', ('weight', 'weight_unit'))
|
||||||
)),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = [
|
fields = [
|
||||||
'manufacturer', 'model', 'part_number', 'comments', 'tags',
|
'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
widgets = {
|
||||||
|
'weight_unit': StaticSelect(),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class DeviceRoleForm(NetBoxModelForm):
|
class DeviceRoleForm(NetBoxModelForm):
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Device Role', (
|
||||||
|
'name', 'slug', 'color', 'vm_role', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
fields = [
|
fields = [
|
||||||
@ -422,6 +459,13 @@ class PlatformForm(NetBoxModelForm):
|
|||||||
max_length=64
|
max_length=64
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Platform', (
|
||||||
|
'name', 'slug', 'manufacturer', 'napalm_driver', 'napalm_args', 'description', 'tags',
|
||||||
|
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = [
|
fields = [
|
||||||
@ -547,7 +591,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
|
|||||||
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack',
|
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack',
|
||||||
'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6',
|
'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6',
|
||||||
'cluster_group', 'cluster', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority',
|
'cluster_group', 'cluster', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority',
|
||||||
'comments', 'tags', 'local_context_data'
|
'description', 'comments', 'tags', 'local_context_data'
|
||||||
]
|
]
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'device_role': "The function this device serves",
|
'device_role': "The function this device serves",
|
||||||
@ -661,7 +705,7 @@ class ModuleForm(NetBoxModelForm):
|
|||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Module', (
|
('Module', (
|
||||||
'device', 'module_bay', 'manufacturer', 'module_type', 'tags',
|
'device', 'module_bay', 'manufacturer', 'module_type', 'description', 'tags',
|
||||||
)),
|
)),
|
||||||
('Hardware', (
|
('Hardware', (
|
||||||
'serial', 'asset_tag', 'replicate_components', 'adopt_components',
|
'serial', 'asset_tag', 'replicate_components', 'adopt_components',
|
||||||
@ -672,13 +716,14 @@ class ModuleForm(NetBoxModelForm):
|
|||||||
model = Module
|
model = Module
|
||||||
fields = [
|
fields = [
|
||||||
'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'tags',
|
'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'tags',
|
||||||
'replicate_components', 'adopt_components', 'comments',
|
'replicate_components', 'adopt_components', 'description', 'comments',
|
||||||
]
|
]
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
if self.instance.pk:
|
if self.instance.pk:
|
||||||
|
self.fields['device'].disabled = True
|
||||||
self.fields['replicate_components'].initial = False
|
self.fields['replicate_components'].initial = False
|
||||||
self.fields['replicate_components'].disabled = True
|
self.fields['replicate_components'].disabled = True
|
||||||
self.fields['adopt_components'].initial = False
|
self.fields['adopt_components'].initial = False
|
||||||
@ -748,11 +793,13 @@ class ModuleForm(NetBoxModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class CableForm(TenancyForm, NetBoxModelForm):
|
class CableForm(TenancyForm, NetBoxModelForm):
|
||||||
|
comments = CommentField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cable
|
model = Cable
|
||||||
fields = [
|
fields = [
|
||||||
'type', 'status', 'tenant_group', 'tenant', 'label', 'color', 'length', 'length_unit', 'tags',
|
'type', 'status', 'tenant_group', 'tenant', 'label', 'color', 'length', 'length_unit', 'description',
|
||||||
|
'comments', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'status': StaticSelect,
|
'status': StaticSelect,
|
||||||
@ -795,15 +842,16 @@ class PowerPanelForm(NetBoxModelForm):
|
|||||||
'site_id': '$site'
|
'site_id': '$site'
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'tags')),
|
('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'description', 'tags')),
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'location', 'name', 'tags',
|
'region', 'site_group', 'site', 'location', 'name', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -849,7 +897,7 @@ class PowerFeedForm(NetBoxModelForm):
|
|||||||
comments = CommentField()
|
comments = CommentField()
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Power Panel', ('region', 'site', 'power_panel')),
|
('Power Panel', ('region', 'site', 'power_panel', 'description')),
|
||||||
('Power Feed', ('rack', 'name', 'status', 'type', 'mark_connected', 'tags')),
|
('Power Feed', ('rack', 'name', 'status', 'type', 'mark_connected', 'tags')),
|
||||||
('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')),
|
('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')),
|
||||||
)
|
)
|
||||||
@ -858,7 +906,7 @@ class PowerFeedForm(NetBoxModelForm):
|
|||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = [
|
fields = [
|
||||||
'region', 'site_group', 'site', 'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply',
|
'region', 'site_group', 'site', 'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply',
|
||||||
'phase', 'voltage', 'amperage', 'max_utilization', 'comments', 'tags',
|
'phase', 'voltage', 'amperage', 'max_utilization', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'status': StaticSelect(),
|
'status': StaticSelect(),
|
||||||
@ -877,11 +925,12 @@ class VirtualChassisForm(NetBoxModelForm):
|
|||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
|
comments = CommentField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = [
|
fields = [
|
||||||
'name', 'domain', 'master', 'tags',
|
'name', 'domain', 'master', 'description', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'master': SelectWithPK(),
|
'master': SelectWithPK(),
|
||||||
@ -1576,6 +1625,12 @@ class InventoryItemForm(DeviceComponentForm):
|
|||||||
class InventoryItemRoleForm(NetBoxModelForm):
|
class InventoryItemRoleForm(NetBoxModelForm):
|
||||||
slug = SlugField()
|
slug = SlugField()
|
||||||
|
|
||||||
|
fieldsets = (
|
||||||
|
('Inventory Item Role', (
|
||||||
|
'name', 'slug', 'color', 'description', 'tags',
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItemRole
|
model = InventoryItemRole
|
||||||
fields = [
|
fields = [
|
@ -3,7 +3,7 @@ from django import forms
|
|||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
from netbox.forms import NetBoxModelForm
|
from netbox.forms import NetBoxModelForm
|
||||||
from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField
|
from utilities.forms import DynamicModelChoiceField, DynamicModelMultipleChoiceField, ExpandableNameField
|
||||||
from . import models as model_forms
|
from . import model_forms
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ComponentCreateForm',
|
'ComponentCreateForm',
|
||||||
|
@ -30,7 +30,7 @@ class DeviceTypeImportForm(BootstrapMixin, forms.ModelForm):
|
|||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
||||||
'comments',
|
'description', 'comments',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ class ModuleTypeImportForm(BootstrapMixin, forms.ModelForm):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = ['manufacturer', 'model', 'part_number', 'comments']
|
fields = ['manufacturer', 'model', 'part_number', 'description', 'comments']
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
169
netbox/dcim/graphql/gfk_mixins.py
Normal file
169
netbox/dcim/graphql/gfk_mixins.py
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
import graphene
|
||||||
|
from circuits.graphql.types import CircuitTerminationType
|
||||||
|
from circuits.models import CircuitTermination
|
||||||
|
from dcim.graphql.types import (
|
||||||
|
ConsolePortTemplateType,
|
||||||
|
ConsolePortType,
|
||||||
|
ConsoleServerPortTemplateType,
|
||||||
|
ConsoleServerPortType,
|
||||||
|
FrontPortTemplateType,
|
||||||
|
FrontPortType,
|
||||||
|
InterfaceTemplateType,
|
||||||
|
InterfaceType,
|
||||||
|
PowerFeedType,
|
||||||
|
PowerOutletTemplateType,
|
||||||
|
PowerOutletType,
|
||||||
|
PowerPortTemplateType,
|
||||||
|
PowerPortType,
|
||||||
|
RearPortTemplateType,
|
||||||
|
RearPortType,
|
||||||
|
)
|
||||||
|
from dcim.models import (
|
||||||
|
ConsolePort,
|
||||||
|
ConsolePortTemplate,
|
||||||
|
ConsoleServerPort,
|
||||||
|
ConsoleServerPortTemplate,
|
||||||
|
FrontPort,
|
||||||
|
FrontPortTemplate,
|
||||||
|
Interface,
|
||||||
|
InterfaceTemplate,
|
||||||
|
PowerFeed,
|
||||||
|
PowerOutlet,
|
||||||
|
PowerOutletTemplate,
|
||||||
|
PowerPort,
|
||||||
|
PowerPortTemplate,
|
||||||
|
RearPort,
|
||||||
|
RearPortTemplate,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LinkPeerType(graphene.Union):
|
||||||
|
class Meta:
|
||||||
|
types = (
|
||||||
|
CircuitTerminationType,
|
||||||
|
ConsolePortType,
|
||||||
|
ConsoleServerPortType,
|
||||||
|
FrontPortType,
|
||||||
|
InterfaceType,
|
||||||
|
PowerFeedType,
|
||||||
|
PowerOutletType,
|
||||||
|
PowerPortType,
|
||||||
|
RearPortType,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_type(cls, instance, info):
|
||||||
|
if type(instance) == CircuitTermination:
|
||||||
|
return CircuitTerminationType
|
||||||
|
if type(instance) == ConsolePortType:
|
||||||
|
return ConsolePortType
|
||||||
|
if type(instance) == ConsoleServerPort:
|
||||||
|
return ConsoleServerPortType
|
||||||
|
if type(instance) == FrontPort:
|
||||||
|
return FrontPortType
|
||||||
|
if type(instance) == Interface:
|
||||||
|
return InterfaceType
|
||||||
|
if type(instance) == PowerFeed:
|
||||||
|
return PowerFeedType
|
||||||
|
if type(instance) == PowerOutlet:
|
||||||
|
return PowerOutletType
|
||||||
|
if type(instance) == PowerPort:
|
||||||
|
return PowerPortType
|
||||||
|
if type(instance) == RearPort:
|
||||||
|
return RearPortType
|
||||||
|
|
||||||
|
|
||||||
|
class CableTerminationTerminationType(graphene.Union):
|
||||||
|
class Meta:
|
||||||
|
types = (
|
||||||
|
CircuitTerminationType,
|
||||||
|
ConsolePortType,
|
||||||
|
ConsoleServerPortType,
|
||||||
|
FrontPortType,
|
||||||
|
InterfaceType,
|
||||||
|
PowerFeedType,
|
||||||
|
PowerOutletType,
|
||||||
|
PowerPortType,
|
||||||
|
RearPortType,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_type(cls, instance, info):
|
||||||
|
if type(instance) == CircuitTermination:
|
||||||
|
return CircuitTerminationType
|
||||||
|
if type(instance) == ConsolePortType:
|
||||||
|
return ConsolePortType
|
||||||
|
if type(instance) == ConsoleServerPort:
|
||||||
|
return ConsoleServerPortType
|
||||||
|
if type(instance) == FrontPort:
|
||||||
|
return FrontPortType
|
||||||
|
if type(instance) == Interface:
|
||||||
|
return InterfaceType
|
||||||
|
if type(instance) == PowerFeed:
|
||||||
|
return PowerFeedType
|
||||||
|
if type(instance) == PowerOutlet:
|
||||||
|
return PowerOutletType
|
||||||
|
if type(instance) == PowerPort:
|
||||||
|
return PowerPortType
|
||||||
|
if type(instance) == RearPort:
|
||||||
|
return RearPortType
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemTemplateComponentType(graphene.Union):
|
||||||
|
class Meta:
|
||||||
|
types = (
|
||||||
|
ConsolePortTemplateType,
|
||||||
|
ConsoleServerPortTemplateType,
|
||||||
|
FrontPortTemplateType,
|
||||||
|
InterfaceTemplateType,
|
||||||
|
PowerOutletTemplateType,
|
||||||
|
PowerPortTemplateType,
|
||||||
|
RearPortTemplateType,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_type(cls, instance, info):
|
||||||
|
if type(instance) == ConsolePortTemplate:
|
||||||
|
return ConsolePortTemplateType
|
||||||
|
if type(instance) == ConsoleServerPortTemplate:
|
||||||
|
return ConsoleServerPortTemplateType
|
||||||
|
if type(instance) == FrontPortTemplate:
|
||||||
|
return FrontPortTemplateType
|
||||||
|
if type(instance) == InterfaceTemplate:
|
||||||
|
return InterfaceTemplateType
|
||||||
|
if type(instance) == PowerOutletTemplate:
|
||||||
|
return PowerOutletTemplateType
|
||||||
|
if type(instance) == PowerPortTemplate:
|
||||||
|
return PowerPortTemplateType
|
||||||
|
if type(instance) == RearPortTemplate:
|
||||||
|
return RearPortTemplateType
|
||||||
|
|
||||||
|
|
||||||
|
class InventoryItemComponentType(graphene.Union):
|
||||||
|
class Meta:
|
||||||
|
types = (
|
||||||
|
ConsolePortType,
|
||||||
|
ConsoleServerPortType,
|
||||||
|
FrontPortType,
|
||||||
|
InterfaceType,
|
||||||
|
PowerOutletType,
|
||||||
|
PowerPortType,
|
||||||
|
RearPortType,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve_type(cls, instance, info):
|
||||||
|
if type(instance) == ConsolePort:
|
||||||
|
return ConsolePortType
|
||||||
|
if type(instance) == ConsoleServerPort:
|
||||||
|
return ConsoleServerPortType
|
||||||
|
if type(instance) == FrontPort:
|
||||||
|
return FrontPortType
|
||||||
|
if type(instance) == Interface:
|
||||||
|
return InterfaceType
|
||||||
|
if type(instance) == PowerOutlet:
|
||||||
|
return PowerOutletType
|
||||||
|
if type(instance) == PowerPort:
|
||||||
|
return PowerPortType
|
||||||
|
if type(instance) == RearPort:
|
||||||
|
return RearPortType
|
@ -1,5 +1,12 @@
|
|||||||
|
import graphene
|
||||||
|
|
||||||
|
|
||||||
class CabledObjectMixin:
|
class CabledObjectMixin:
|
||||||
|
link_peers = graphene.List('dcim.graphql.gfk_mixins.LinkPeerType')
|
||||||
|
|
||||||
def resolve_cable_end(self, info):
|
def resolve_cable_end(self, info):
|
||||||
# Handle empty values
|
# Handle empty values
|
||||||
return self.cable_end or None
|
return self.cable_end or None
|
||||||
|
|
||||||
|
def resolve_link_peers(self, info):
|
||||||
|
return self.link_peers
|
||||||
|
@ -2,7 +2,7 @@ import graphene
|
|||||||
|
|
||||||
from dcim import filtersets, models
|
from dcim import filtersets, models
|
||||||
from extras.graphql.mixins import (
|
from extras.graphql.mixins import (
|
||||||
ChangelogMixin, ConfigContextMixin, CustomFieldsMixin, ImageAttachmentsMixin, TagsMixin,
|
ChangelogMixin, ConfigContextMixin, ContactsMixin, CustomFieldsMixin, ImageAttachmentsMixin, TagsMixin,
|
||||||
)
|
)
|
||||||
from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin
|
from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin
|
||||||
from netbox.graphql.scalars import BigInt
|
from netbox.graphql.scalars import BigInt
|
||||||
@ -87,6 +87,8 @@ class ComponentTemplateObjectType(
|
|||||||
#
|
#
|
||||||
|
|
||||||
class CableType(NetBoxObjectType):
|
class CableType(NetBoxObjectType):
|
||||||
|
a_terminations = graphene.List('dcim.graphql.gfk_mixins.CableTerminationTerminationType')
|
||||||
|
b_terminations = graphene.List('dcim.graphql.gfk_mixins.CableTerminationTerminationType')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Cable
|
model = models.Cable
|
||||||
@ -99,12 +101,19 @@ class CableType(NetBoxObjectType):
|
|||||||
def resolve_length_unit(self, info):
|
def resolve_length_unit(self, info):
|
||||||
return self.length_unit or None
|
return self.length_unit or None
|
||||||
|
|
||||||
|
def resolve_a_terminations(self, info):
|
||||||
|
return self.a_terminations
|
||||||
|
|
||||||
|
def resolve_b_terminations(self, info):
|
||||||
|
return self.b_terminations
|
||||||
|
|
||||||
|
|
||||||
class CableTerminationType(NetBoxObjectType):
|
class CableTerminationType(NetBoxObjectType):
|
||||||
|
termination = graphene.Field('dcim.graphql.gfk_mixins.CableTerminationTerminationType')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.CableTermination
|
model = models.CableTermination
|
||||||
fields = '__all__'
|
exclude = ('termination_type', 'termination_id')
|
||||||
filterset_class = filtersets.CableTerminationFilterSet
|
filterset_class = filtersets.CableTerminationFilterSet
|
||||||
|
|
||||||
|
|
||||||
@ -152,7 +161,7 @@ class ConsoleServerPortTemplateType(ComponentTemplateObjectType):
|
|||||||
return self.type or None
|
return self.type or None
|
||||||
|
|
||||||
|
|
||||||
class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, NetBoxObjectType):
|
class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Device
|
model = models.Device
|
||||||
@ -183,10 +192,11 @@ class DeviceBayTemplateType(ComponentTemplateObjectType):
|
|||||||
|
|
||||||
|
|
||||||
class InventoryItemTemplateType(ComponentTemplateObjectType):
|
class InventoryItemTemplateType(ComponentTemplateObjectType):
|
||||||
|
component = graphene.Field('dcim.graphql.gfk_mixins.InventoryItemTemplateComponentType')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.InventoryItemTemplate
|
model = models.InventoryItemTemplate
|
||||||
fields = '__all__'
|
exclude = ('component_type', 'component_id')
|
||||||
filterset_class = filtersets.InventoryItemTemplateFilterSet
|
filterset_class = filtersets.InventoryItemTemplateFilterSet
|
||||||
|
|
||||||
|
|
||||||
@ -211,6 +221,9 @@ class DeviceTypeType(NetBoxObjectType):
|
|||||||
def resolve_airflow(self, info):
|
def resolve_airflow(self, info):
|
||||||
return self.airflow or None
|
return self.airflow or None
|
||||||
|
|
||||||
|
def resolve_weight_unit(self, info):
|
||||||
|
return self.weight_unit or None
|
||||||
|
|
||||||
|
|
||||||
class FrontPortType(ComponentObjectType, CabledObjectMixin):
|
class FrontPortType(ComponentObjectType, CabledObjectMixin):
|
||||||
|
|
||||||
@ -266,10 +279,11 @@ class InterfaceTemplateType(ComponentTemplateObjectType):
|
|||||||
|
|
||||||
|
|
||||||
class InventoryItemType(ComponentObjectType):
|
class InventoryItemType(ComponentObjectType):
|
||||||
|
component = graphene.Field('dcim.graphql.gfk_mixins.InventoryItemComponentType')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.InventoryItem
|
model = models.InventoryItem
|
||||||
fields = '__all__'
|
exclude = ('component_type', 'component_id')
|
||||||
filterset_class = filtersets.InventoryItemFilterSet
|
filterset_class = filtersets.InventoryItemFilterSet
|
||||||
|
|
||||||
|
|
||||||
@ -281,7 +295,7 @@ class InventoryItemRoleType(OrganizationalObjectType):
|
|||||||
filterset_class = filtersets.InventoryItemRoleFilterSet
|
filterset_class = filtersets.InventoryItemRoleFilterSet
|
||||||
|
|
||||||
|
|
||||||
class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, OrganizationalObjectType):
|
class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, OrganizationalObjectType):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Location
|
model = models.Location
|
||||||
@ -289,7 +303,7 @@ class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, OrganizationalObjectT
|
|||||||
filterset_class = filtersets.LocationFilterSet
|
filterset_class = filtersets.LocationFilterSet
|
||||||
|
|
||||||
|
|
||||||
class ManufacturerType(OrganizationalObjectType):
|
class ManufacturerType(OrganizationalObjectType, ContactsMixin):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Manufacturer
|
model = models.Manufacturer
|
||||||
@ -328,6 +342,9 @@ class ModuleTypeType(NetBoxObjectType):
|
|||||||
fields = '__all__'
|
fields = '__all__'
|
||||||
filterset_class = filtersets.ModuleTypeFilterSet
|
filterset_class = filtersets.ModuleTypeFilterSet
|
||||||
|
|
||||||
|
def resolve_weight_unit(self, info):
|
||||||
|
return self.weight_unit or None
|
||||||
|
|
||||||
|
|
||||||
class PlatformType(OrganizationalObjectType):
|
class PlatformType(OrganizationalObjectType):
|
||||||
|
|
||||||
@ -373,7 +390,7 @@ class PowerOutletTemplateType(ComponentTemplateObjectType):
|
|||||||
return self.type or None
|
return self.type or None
|
||||||
|
|
||||||
|
|
||||||
class PowerPanelType(NetBoxObjectType):
|
class PowerPanelType(NetBoxObjectType, ContactsMixin):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.PowerPanel
|
model = models.PowerPanel
|
||||||
@ -403,7 +420,7 @@ class PowerPortTemplateType(ComponentTemplateObjectType):
|
|||||||
return self.type or None
|
return self.type or None
|
||||||
|
|
||||||
|
|
||||||
class RackType(VLANGroupsMixin, ImageAttachmentsMixin, NetBoxObjectType):
|
class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Rack
|
model = models.Rack
|
||||||
@ -416,6 +433,9 @@ class RackType(VLANGroupsMixin, ImageAttachmentsMixin, NetBoxObjectType):
|
|||||||
def resolve_outer_unit(self, info):
|
def resolve_outer_unit(self, info):
|
||||||
return self.outer_unit or None
|
return self.outer_unit or None
|
||||||
|
|
||||||
|
def resolve_weight_unit(self, info):
|
||||||
|
return self.weight_unit or None
|
||||||
|
|
||||||
|
|
||||||
class RackReservationType(NetBoxObjectType):
|
class RackReservationType(NetBoxObjectType):
|
||||||
|
|
||||||
@ -449,7 +469,7 @@ class RearPortTemplateType(ComponentTemplateObjectType):
|
|||||||
filterset_class = filtersets.RearPortTemplateFilterSet
|
filterset_class = filtersets.RearPortTemplateFilterSet
|
||||||
|
|
||||||
|
|
||||||
class RegionType(VLANGroupsMixin, OrganizationalObjectType):
|
class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Region
|
model = models.Region
|
||||||
@ -457,7 +477,7 @@ class RegionType(VLANGroupsMixin, OrganizationalObjectType):
|
|||||||
filterset_class = filtersets.RegionFilterSet
|
filterset_class = filtersets.RegionFilterSet
|
||||||
|
|
||||||
|
|
||||||
class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, NetBoxObjectType):
|
class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType):
|
||||||
asn = graphene.Field(BigInt)
|
asn = graphene.Field(BigInt)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -466,7 +486,7 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, NetBoxObjectType):
|
|||||||
filterset_class = filtersets.SiteFilterSet
|
filterset_class = filtersets.SiteFilterSet
|
||||||
|
|
||||||
|
|
||||||
class SiteGroupType(VLANGroupsMixin, OrganizationalObjectType):
|
class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.SiteGroup
|
model = models.SiteGroup
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import dcim.fields
|
import dcim.fields
|
||||||
import django.contrib.postgres.fields
|
import django.contrib.postgres.fields
|
||||||
import django.core.serializers.json
|
from utilities.json import CustomFieldJSONEncoder
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@ -28,7 +28,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('termination_a_id', models.PositiveIntegerField()),
|
('termination_a_id', models.PositiveIntegerField()),
|
||||||
('termination_b_id', models.PositiveIntegerField()),
|
('termination_b_id', models.PositiveIntegerField()),
|
||||||
@ -60,7 +60,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -96,7 +96,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -132,7 +132,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('local_context_data', models.JSONField(blank=True, null=True)),
|
('local_context_data', models.JSONField(blank=True, null=True)),
|
||||||
('name', models.CharField(blank=True, max_length=64, null=True)),
|
('name', models.CharField(blank=True, max_length=64, null=True)),
|
||||||
@ -155,7 +155,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -186,7 +186,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -195,7 +195,7 @@ class Migration(migrations.Migration):
|
|||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -203,7 +203,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('model', models.CharField(max_length=100)),
|
('model', models.CharField(max_length=100)),
|
||||||
('slug', models.SlugField(max_length=100)),
|
('slug', models.SlugField(max_length=100)),
|
||||||
@ -224,7 +224,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -261,7 +261,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('label', models.CharField(blank=True, max_length=64)),
|
('label', models.CharField(blank=True, max_length=64)),
|
||||||
@ -302,7 +302,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -326,7 +326,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100)),
|
('name', models.CharField(max_length=100)),
|
||||||
('slug', models.SlugField(max_length=100)),
|
('slug', models.SlugField(max_length=100)),
|
||||||
@ -345,14 +345,14 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -360,7 +360,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -369,7 +369,7 @@ class Migration(migrations.Migration):
|
|||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -377,7 +377,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)),
|
('_cable_peer_id', models.PositiveIntegerField(blank=True, null=True)),
|
||||||
('mark_connected', models.BooleanField(default=False)),
|
('mark_connected', models.BooleanField(default=False)),
|
||||||
@ -401,7 +401,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -438,7 +438,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100)),
|
('name', models.CharField(max_length=100)),
|
||||||
],
|
],
|
||||||
@ -451,7 +451,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -490,7 +490,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100)),
|
('name', models.CharField(max_length=100)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -516,7 +516,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('units', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveSmallIntegerField(), size=None)),
|
('units', django.contrib.postgres.fields.ArrayField(base_field=models.PositiveSmallIntegerField(), size=None)),
|
||||||
('description', models.CharField(max_length=200)),
|
('description', models.CharField(max_length=200)),
|
||||||
@ -530,7 +530,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -538,7 +538,7 @@ class Migration(migrations.Migration):
|
|||||||
('description', models.CharField(blank=True, max_length=200)),
|
('description', models.CharField(blank=True, max_length=200)),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
@ -546,7 +546,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -583,7 +583,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -602,7 +602,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -630,7 +630,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -649,7 +649,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('domain', models.CharField(blank=True, max_length=30)),
|
('domain', models.CharField(blank=True, max_length=30)),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import django.core.serializers.json
|
from utilities.json import CustomFieldJSONEncoder
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import taggit.managers
|
import taggit.managers
|
||||||
@ -107,7 +107,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('model', models.CharField(max_length=100)),
|
('model', models.CharField(max_length=100)),
|
||||||
('part_number', models.CharField(blank=True, max_length=50)),
|
('part_number', models.CharField(blank=True, max_length=50)),
|
||||||
@ -125,7 +125,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=64)),
|
('name', models.CharField(max_length=64)),
|
||||||
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
('_name', utilities.fields.NaturalOrderingField('name', blank=True, max_length=100, naturalize_function=utilities.ordering.naturalize)),
|
||||||
@ -145,7 +145,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('local_context_data', models.JSONField(blank=True, null=True)),
|
('local_context_data', models.JSONField(blank=True, null=True)),
|
||||||
('serial', models.CharField(blank=True, max_length=50)),
|
('serial', models.CharField(blank=True, max_length=50)),
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import django.core.serializers.json
|
from utilities.json import CustomFieldJSONEncoder
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
import taggit.managers
|
import taggit.managers
|
||||||
@ -18,7 +18,7 @@ class Migration(migrations.Migration):
|
|||||||
fields=[
|
fields=[
|
||||||
('created', models.DateField(auto_now_add=True, null=True)),
|
('created', models.DateField(auto_now_add=True, null=True)),
|
||||||
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
('last_updated', models.DateTimeField(auto_now=True, null=True)),
|
||||||
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)),
|
('custom_field_data', models.JSONField(blank=True, default=dict, encoder=CustomFieldJSONEncoder)),
|
||||||
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
('id', models.BigAutoField(primary_key=True, serialize=False)),
|
||||||
('name', models.CharField(max_length=100, unique=True)),
|
('name', models.CharField(max_length=100, unique=True)),
|
||||||
('slug', models.SlugField(max_length=100, unique=True)),
|
('slug', models.SlugField(max_length=100, unique=True)),
|
||||||
@ -27,7 +27,7 @@ class Migration(migrations.Migration):
|
|||||||
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'ordering': ['name'],
|
'ordering': ('name',),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
|
@ -0,0 +1,58 @@
|
|||||||
|
# Generated by Django 4.0.7 on 2022-09-23 01:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0162_unique_constraints'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicetype',
|
||||||
|
name='_abs_weight',
|
||||||
|
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicetype',
|
||||||
|
name='weight',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicetype',
|
||||||
|
name='weight_unit',
|
||||||
|
field=models.CharField(blank=True, max_length=50),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='moduletype',
|
||||||
|
name='_abs_weight',
|
||||||
|
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='moduletype',
|
||||||
|
name='weight',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='moduletype',
|
||||||
|
name='weight_unit',
|
||||||
|
field=models.CharField(blank=True, max_length=50),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rack',
|
||||||
|
name='_abs_weight',
|
||||||
|
field=models.PositiveBigIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rack',
|
||||||
|
name='weight',
|
||||||
|
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rack',
|
||||||
|
name='weight_unit',
|
||||||
|
field=models.CharField(blank=True, max_length=50),
|
||||||
|
),
|
||||||
|
]
|
18
netbox/dcim/migrations/0164_rack_mounting_depth.py
Normal file
18
netbox/dcim/migrations/0164_rack_mounting_depth.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Generated by Django 4.1.1 on 2022-10-27 14:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0163_rack_devicetype_moduletype_weights'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rack',
|
||||||
|
name='mounting_depth',
|
||||||
|
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
@ -0,0 +1,78 @@
|
|||||||
|
# Generated by Django 4.1.2 on 2022-11-03 18:24
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0164_rack_mounting_depth'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cable',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='cable',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='device',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='devicetype',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='module',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='moduletype',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powerfeed',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powerpanel',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='powerpanel',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rack',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='rackreservation',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='virtualchassis',
|
||||||
|
name='comments',
|
||||||
|
field=models.TextField(blank=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='virtualchassis',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(blank=True, max_length=200),
|
||||||
|
),
|
||||||
|
]
|
@ -12,8 +12,8 @@ from django.urls import reverse
|
|||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.fields import PathField
|
from dcim.fields import PathField
|
||||||
from dcim.utils import decompile_path_node, object_to_path_node, path_node_to_object
|
from dcim.utils import decompile_path_node, object_to_path_node
|
||||||
from netbox.models import NetBoxModel
|
from netbox.models import PrimaryModel
|
||||||
from utilities.fields import ColorField
|
from utilities.fields import ColorField
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from utilities.querysets import RestrictedQuerySet
|
||||||
from utilities.utils import to_meters
|
from utilities.utils import to_meters
|
||||||
@ -34,7 +34,7 @@ trace_paths = Signal()
|
|||||||
# Cables
|
# Cables
|
||||||
#
|
#
|
||||||
|
|
||||||
class Cable(NetBoxModel):
|
class Cable(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
A physical connection between two endpoints.
|
A physical connection between two endpoints.
|
||||||
"""
|
"""
|
||||||
|
@ -1025,27 +1025,9 @@ class InventoryItemRole(OrganizationalModel):
|
|||||||
"""
|
"""
|
||||||
Inventory items may optionally be assigned a functional role.
|
Inventory items may optionally be assigned a functional role.
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
color = ColorField(
|
color = ColorField(
|
||||||
default=ColorChoices.COLOR_GREY
|
default=ColorChoices.COLOR_GREY
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:inventoryitemrole', args=[self.pk])
|
return reverse('dcim:inventoryitemrole', args=[self.pk])
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import decimal
|
import decimal
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from functools import cached_property
|
||||||
|
|
||||||
from django.apps import apps
|
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
|
||||||
@ -17,10 +18,11 @@ from dcim.constants import *
|
|||||||
from extras.models import ConfigContextModel
|
from extras.models import ConfigContextModel
|
||||||
from extras.querysets import ConfigContextModelQuerySet
|
from extras.querysets import ConfigContextModelQuerySet
|
||||||
from netbox.config import ConfigItem
|
from netbox.config import ConfigItem
|
||||||
from netbox.models import OrganizationalModel, NetBoxModel
|
from netbox.models import OrganizationalModel, PrimaryModel
|
||||||
from utilities.choices import ColorChoices
|
from utilities.choices import ColorChoices
|
||||||
from utilities.fields import ColorField, NaturalOrderingField
|
from utilities.fields import ColorField, NaturalOrderingField
|
||||||
from .device_components import *
|
from .device_components import *
|
||||||
|
from .mixins import WeightMixin
|
||||||
|
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -43,35 +45,16 @@ class Manufacturer(OrganizationalModel):
|
|||||||
"""
|
"""
|
||||||
A Manufacturer represents a company which produces hardware devices; for example, Juniper or Dell.
|
A Manufacturer represents a company which produces hardware devices; for example, Juniper or Dell.
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
contacts = GenericRelation(
|
contacts = GenericRelation(
|
||||||
to='tenancy.ContactAssignment'
|
to='tenancy.ContactAssignment'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:manufacturer', args=[self.pk])
|
return reverse('dcim:manufacturer', args=[self.pk])
|
||||||
|
|
||||||
|
|
||||||
class DeviceType(NetBoxModel):
|
class DeviceType(PrimaryModel, WeightMixin):
|
||||||
"""
|
"""
|
||||||
A DeviceType represents a particular make (Manufacturer) and model of device. It specifies rack height and depth, as
|
A DeviceType represents a particular make (Manufacturer) and model of device. It specifies rack height and depth, as
|
||||||
well as high-level functional role(s).
|
well as high-level functional role(s).
|
||||||
@ -134,12 +117,9 @@ class DeviceType(NetBoxModel):
|
|||||||
upload_to='devicetype-images',
|
upload_to='devicetype-images',
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
clone_fields = (
|
clone_fields = (
|
||||||
'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit',
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -315,7 +295,7 @@ class DeviceType(NetBoxModel):
|
|||||||
return self.subdevice_role == SubdeviceRoleChoices.ROLE_CHILD
|
return self.subdevice_role == SubdeviceRoleChoices.ROLE_CHILD
|
||||||
|
|
||||||
|
|
||||||
class ModuleType(NetBoxModel):
|
class ModuleType(PrimaryModel, WeightMixin):
|
||||||
"""
|
"""
|
||||||
A ModuleType represents a hardware element that can be installed within a device and which houses additional
|
A ModuleType represents a hardware element that can be installed within a device and which houses additional
|
||||||
components; for example, a line card within a chassis-based switch such as the Cisco Catalyst 6500. Like a
|
components; for example, a line card within a chassis-based switch such as the Cisco Catalyst 6500. Like a
|
||||||
@ -335,16 +315,13 @@ class ModuleType(NetBoxModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
help_text='Discrete part number (optional)'
|
help_text='Discrete part number (optional)'
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
images = GenericRelation(
|
images = GenericRelation(
|
||||||
to='extras.ImageAttachment'
|
to='extras.ImageAttachment'
|
||||||
)
|
)
|
||||||
|
|
||||||
clone_fields = ('manufacturer',)
|
clone_fields = ('manufacturer', 'weight', 'weight_unit',)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ('manufacturer', 'model')
|
ordering = ('manufacturer', 'model')
|
||||||
@ -416,14 +393,6 @@ class DeviceRole(OrganizationalModel):
|
|||||||
color to be used when displaying rack elevations. The vm_role field determines whether the role is applicable to
|
color to be used when displaying rack elevations. The vm_role field determines whether the role is applicable to
|
||||||
virtual machines as well.
|
virtual machines as well.
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
color = ColorField(
|
color = ColorField(
|
||||||
default=ColorChoices.COLOR_GREY
|
default=ColorChoices.COLOR_GREY
|
||||||
)
|
)
|
||||||
@ -432,16 +401,6 @@ class DeviceRole(OrganizationalModel):
|
|||||||
verbose_name='VM Role',
|
verbose_name='VM Role',
|
||||||
help_text='Virtual machines may be assigned to this role'
|
help_text='Virtual machines may be assigned to this role'
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:devicerole', args=[self.pk])
|
return reverse('dcim:devicerole', args=[self.pk])
|
||||||
@ -453,14 +412,6 @@ class Platform(OrganizationalModel):
|
|||||||
NetBox uses Platforms to determine how to interact with devices when pulling inventory data or other information by
|
NetBox uses Platforms to determine how to interact with devices when pulling inventory data or other information by
|
||||||
specifying a NAPALM driver.
|
specifying a NAPALM driver.
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
manufacturer = models.ForeignKey(
|
manufacturer = models.ForeignKey(
|
||||||
to='dcim.Manufacturer',
|
to='dcim.Manufacturer',
|
||||||
on_delete=models.PROTECT,
|
on_delete=models.PROTECT,
|
||||||
@ -481,22 +432,12 @@ class Platform(OrganizationalModel):
|
|||||||
verbose_name='NAPALM arguments',
|
verbose_name='NAPALM arguments',
|
||||||
help_text='Additional arguments to pass when initiating the NAPALM driver (JSON format)'
|
help_text='Additional arguments to pass when initiating the NAPALM driver (JSON format)'
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:platform', args=[self.pk])
|
return reverse('dcim:platform', args=[self.pk])
|
||||||
|
|
||||||
|
|
||||||
class Device(NetBoxModel, ConfigContextModel):
|
class Device(PrimaryModel, ConfigContextModel):
|
||||||
"""
|
"""
|
||||||
A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
|
A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
|
||||||
DeviceRole, and (optionally) a Platform. Device names are not required, however if one is set it must be unique.
|
DeviceRole, and (optionally) a Platform. Device names are not required, however if one is set it must be unique.
|
||||||
@ -640,9 +581,6 @@ class Device(NetBoxModel, ConfigContextModel):
|
|||||||
null=True,
|
null=True,
|
||||||
validators=[MaxValueValidator(255)]
|
validators=[MaxValueValidator(255)]
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
contacts = GenericRelation(
|
contacts = GenericRelation(
|
||||||
@ -946,8 +884,20 @@ class Device(NetBoxModel, ConfigContextModel):
|
|||||||
def get_status_color(self):
|
def get_status_color(self):
|
||||||
return DeviceStatusChoices.colors.get(self.status)
|
return DeviceStatusChoices.colors.get(self.status)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def total_weight(self):
|
||||||
|
total_weight = sum(
|
||||||
|
module.module_type._abs_weight
|
||||||
|
for module in Module.objects.filter(device=self)
|
||||||
|
.exclude(module_type___abs_weight__isnull=True)
|
||||||
|
.prefetch_related('module_type')
|
||||||
|
)
|
||||||
|
if self.device_type._abs_weight:
|
||||||
|
total_weight += self.device_type._abs_weight
|
||||||
|
return round(total_weight / 1000, 2)
|
||||||
|
|
||||||
class Module(NetBoxModel, ConfigContextModel):
|
|
||||||
|
class Module(PrimaryModel, ConfigContextModel):
|
||||||
"""
|
"""
|
||||||
A Module represents a field-installable component within a Device which may itself hold multiple device components
|
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.
|
(for example, a line card within a chassis switch). Modules are instantiated from ModuleTypes.
|
||||||
@ -980,9 +930,6 @@ class Module(NetBoxModel, ConfigContextModel):
|
|||||||
verbose_name='Asset tag',
|
verbose_name='Asset tag',
|
||||||
help_text='A unique tag used to identify this device'
|
help_text='A unique tag used to identify this device'
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
clone_fields = ('device', 'module_type')
|
clone_fields = ('device', 'module_type')
|
||||||
|
|
||||||
@ -995,6 +942,14 @@ class Module(NetBoxModel, ConfigContextModel):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:module', args=[self.pk])
|
return reverse('dcim:module', args=[self.pk])
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
if self.module_bay.device != self.device:
|
||||||
|
raise ValidationError(
|
||||||
|
f"Module must be installed within a module bay belonging to the assigned device ({self.device})."
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
is_new = self.pk is None
|
is_new = self.pk is None
|
||||||
|
|
||||||
@ -1052,7 +1007,7 @@ class Module(NetBoxModel, ConfigContextModel):
|
|||||||
# Virtual chassis
|
# Virtual chassis
|
||||||
#
|
#
|
||||||
|
|
||||||
class VirtualChassis(NetBoxModel):
|
class VirtualChassis(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
A collection of Devices which operate with a shared control plane (e.g. a switch stack).
|
A collection of Devices which operate with a shared control plane (e.g. a switch stack).
|
||||||
"""
|
"""
|
||||||
|
45
netbox/dcim/models/mixins.py
Normal file
45
netbox/dcim/models/mixins.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from django.db import models
|
||||||
|
from dcim.choices import *
|
||||||
|
from utilities.utils import to_grams
|
||||||
|
|
||||||
|
|
||||||
|
class WeightMixin(models.Model):
|
||||||
|
weight = models.DecimalField(
|
||||||
|
max_digits=8,
|
||||||
|
decimal_places=2,
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
weight_unit = models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=WeightUnitChoices,
|
||||||
|
blank=True,
|
||||||
|
)
|
||||||
|
# Stores the normalized weight (in grams) for database ordering
|
||||||
|
_abs_weight = models.PositiveBigIntegerField(
|
||||||
|
blank=True,
|
||||||
|
null=True
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
|
||||||
|
# Store the given weight (if any) in grams for use in database ordering
|
||||||
|
if self.weight and self.weight_unit:
|
||||||
|
self._abs_weight = to_grams(self.weight, self.weight_unit)
|
||||||
|
else:
|
||||||
|
self._abs_weight = None
|
||||||
|
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
super().clean()
|
||||||
|
|
||||||
|
# Validate weight and weight_unit
|
||||||
|
if self.weight is not None and not self.weight_unit:
|
||||||
|
raise ValidationError("Must specify a unit when setting a weight")
|
||||||
|
elif self.weight is None:
|
||||||
|
self.weight_unit = ''
|
@ -6,9 +6,8 @@ from django.db import models
|
|||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
|
||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
|
||||||
from netbox.config import ConfigItem
|
from netbox.config import ConfigItem
|
||||||
from netbox.models import NetBoxModel
|
from netbox.models import PrimaryModel
|
||||||
from utilities.validators import ExclusionValidator
|
from utilities.validators import ExclusionValidator
|
||||||
from .device_components import CabledObjectModel, PathEndpoint
|
from .device_components import CabledObjectModel, PathEndpoint
|
||||||
|
|
||||||
@ -22,7 +21,7 @@ __all__ = (
|
|||||||
# Power
|
# Power
|
||||||
#
|
#
|
||||||
|
|
||||||
class PowerPanel(NetBoxModel):
|
class PowerPanel(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
A distribution point for electrical power; e.g. a data center RPP.
|
A distribution point for electrical power; e.g. a data center RPP.
|
||||||
"""
|
"""
|
||||||
@ -77,7 +76,7 @@ class PowerPanel(NetBoxModel):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerFeed(NetBoxModel, PathEndpoint, CabledObjectModel):
|
class PowerFeed(PrimaryModel, PathEndpoint, CabledObjectModel):
|
||||||
"""
|
"""
|
||||||
An electrical circuit delivered from a PowerPanel.
|
An electrical circuit delivered from a PowerPanel.
|
||||||
"""
|
"""
|
||||||
@ -132,9 +131,6 @@ class PowerFeed(NetBoxModel, PathEndpoint, CabledObjectModel):
|
|||||||
default=0,
|
default=0,
|
||||||
editable=False
|
editable=False
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
clone_fields = (
|
clone_fields = (
|
||||||
'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',
|
'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import decimal
|
import decimal
|
||||||
|
from functools import cached_property
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@ -13,12 +14,13 @@ from django.urls import reverse
|
|||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.svg import RackElevationSVG
|
from dcim.svg import RackElevationSVG
|
||||||
from netbox.models import OrganizationalModel, NetBoxModel
|
from netbox.models import OrganizationalModel, PrimaryModel
|
||||||
from utilities.choices import ColorChoices
|
from utilities.choices import ColorChoices
|
||||||
from utilities.fields import ColorField, NaturalOrderingField
|
from utilities.fields import ColorField, NaturalOrderingField
|
||||||
from utilities.utils import array_to_string, drange
|
from utilities.utils import array_to_string, drange
|
||||||
from .device_components import PowerPort
|
from .device_components import PowerPort
|
||||||
from .devices import Device
|
from .devices import Device, Module
|
||||||
|
from .mixins import WeightMixin
|
||||||
from .power import PowerFeed
|
from .power import PowerFeed
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -36,33 +38,15 @@ class RackRole(OrganizationalModel):
|
|||||||
"""
|
"""
|
||||||
Racks can be organized by functional role, similar to Devices.
|
Racks can be organized by functional role, similar to Devices.
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100,
|
|
||||||
unique=True
|
|
||||||
)
|
|
||||||
color = ColorField(
|
color = ColorField(
|
||||||
default=ColorChoices.COLOR_GREY
|
default=ColorChoices.COLOR_GREY
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
ordering = ['name']
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('dcim:rackrole', args=[self.pk])
|
return reverse('dcim:rackrole', args=[self.pk])
|
||||||
|
|
||||||
|
|
||||||
class Rack(NetBoxModel):
|
class Rack(PrimaryModel, WeightMixin):
|
||||||
"""
|
"""
|
||||||
Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face.
|
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.
|
Each Rack is assigned to a Site and (optionally) a Location.
|
||||||
@ -165,8 +149,13 @@ class Rack(NetBoxModel):
|
|||||||
choices=RackDimensionUnitChoices,
|
choices=RackDimensionUnitChoices,
|
||||||
blank=True,
|
blank=True,
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
mounting_depth = models.PositiveSmallIntegerField(
|
||||||
blank=True
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text=(
|
||||||
|
'Maximum depth of a mounted device, in millimeters. For four-post racks, this is the '
|
||||||
|
'distance between the front and rear rails.'
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
@ -185,7 +174,7 @@ class Rack(NetBoxModel):
|
|||||||
|
|
||||||
clone_fields = (
|
clone_fields = (
|
||||||
'site', 'location', 'tenant', 'status', 'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
|
'site', 'location', 'tenant', 'status', 'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
|
||||||
'outer_depth', 'outer_unit',
|
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'weight_unit',
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@ -454,8 +443,24 @@ class Rack(NetBoxModel):
|
|||||||
|
|
||||||
return int(allocated_draw / available_power_total * 100)
|
return int(allocated_draw / available_power_total * 100)
|
||||||
|
|
||||||
|
@cached_property
|
||||||
|
def total_weight(self):
|
||||||
|
total_weight = sum(
|
||||||
|
device.device_type._abs_weight
|
||||||
|
for device in self.devices.exclude(device_type___abs_weight__isnull=True).prefetch_related('device_type')
|
||||||
|
)
|
||||||
|
total_weight += sum(
|
||||||
|
module.module_type._abs_weight
|
||||||
|
for module in Module.objects.filter(device__rack=self)
|
||||||
|
.exclude(module_type___abs_weight__isnull=True)
|
||||||
|
.prefetch_related('module_type')
|
||||||
|
)
|
||||||
|
if self._abs_weight:
|
||||||
|
total_weight += self._abs_weight
|
||||||
|
return round(total_weight / 1000, 2)
|
||||||
|
|
||||||
class RackReservation(NetBoxModel):
|
|
||||||
|
class RackReservation(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
One or more reserved units within a Rack.
|
One or more reserved units within a Rack.
|
||||||
"""
|
"""
|
||||||
|
@ -2,12 +2,11 @@ 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
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from mptt.models import TreeForeignKey
|
|
||||||
from timezone_field import TimeZoneField
|
from timezone_field import TimeZoneField
|
||||||
|
|
||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from netbox.models import NestedGroupModel, NetBoxModel
|
from netbox.models import NestedGroupModel, PrimaryModel
|
||||||
from utilities.fields import NaturalOrderingField
|
from utilities.fields import NaturalOrderingField
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -28,25 +27,6 @@ class Region(NestedGroupModel):
|
|||||||
states, and/or cities. Regions are recursively nested into a hierarchy: all sites belonging to a child region are
|
states, and/or cities. Regions are recursively nested into a hierarchy: all sites belonging to a child region are
|
||||||
also considered to be members of its parent and ancestor region(s).
|
also considered to be members of its parent and ancestor region(s).
|
||||||
"""
|
"""
|
||||||
parent = TreeForeignKey(
|
|
||||||
to='self',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='children',
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
db_index=True
|
|
||||||
)
|
|
||||||
name = models.CharField(
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
vlan_groups = GenericRelation(
|
vlan_groups = GenericRelation(
|
||||||
to='ipam.VLANGroup',
|
to='ipam.VLANGroup',
|
||||||
@ -102,25 +82,6 @@ class SiteGroup(NestedGroupModel):
|
|||||||
within corporate sites you might distinguish between offices and data centers. Like regions, site groups can be
|
within corporate sites you might distinguish between offices and data centers. Like regions, site groups can be
|
||||||
nested recursively to form a hierarchy.
|
nested recursively to form a hierarchy.
|
||||||
"""
|
"""
|
||||||
parent = TreeForeignKey(
|
|
||||||
to='self',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='children',
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
db_index=True
|
|
||||||
)
|
|
||||||
name = models.CharField(
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
vlan_groups = GenericRelation(
|
vlan_groups = GenericRelation(
|
||||||
to='ipam.VLANGroup',
|
to='ipam.VLANGroup',
|
||||||
@ -170,7 +131,7 @@ class SiteGroup(NestedGroupModel):
|
|||||||
# Sites
|
# Sites
|
||||||
#
|
#
|
||||||
|
|
||||||
class Site(NetBoxModel):
|
class Site(PrimaryModel):
|
||||||
"""
|
"""
|
||||||
A Site represents a geographic location within a network; typically a building or campus. The optional facility
|
A Site represents a geographic location within a network; typically a building or campus. The optional facility
|
||||||
field can be used to include an external designation, such as a data center name (e.g. Equinix SV6).
|
field can be used to include an external designation, such as a data center name (e.g. Equinix SV6).
|
||||||
@ -227,10 +188,6 @@ class Site(NetBoxModel):
|
|||||||
time_zone = TimeZoneField(
|
time_zone = TimeZoneField(
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
physical_address = models.CharField(
|
physical_address = models.CharField(
|
||||||
max_length=200,
|
max_length=200,
|
||||||
blank=True
|
blank=True
|
||||||
@ -253,9 +210,6 @@ class Site(NetBoxModel):
|
|||||||
null=True,
|
null=True,
|
||||||
help_text='GPS coordinate (longitude)'
|
help_text='GPS coordinate (longitude)'
|
||||||
)
|
)
|
||||||
comments = models.TextField(
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
vlan_groups = GenericRelation(
|
vlan_groups = GenericRelation(
|
||||||
@ -298,25 +252,11 @@ class Location(NestedGroupModel):
|
|||||||
A Location represents a subgroup of Racks and/or Devices within a Site. A Location may represent a building within a
|
A Location represents a subgroup of Racks and/or Devices within a Site. A Location may represent a building within a
|
||||||
site, or a room within a building, for example.
|
site, or a room within a building, for example.
|
||||||
"""
|
"""
|
||||||
name = models.CharField(
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
slug = models.SlugField(
|
|
||||||
max_length=100
|
|
||||||
)
|
|
||||||
site = models.ForeignKey(
|
site = models.ForeignKey(
|
||||||
to='dcim.Site',
|
to='dcim.Site',
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name='locations'
|
related_name='locations'
|
||||||
)
|
)
|
||||||
parent = TreeForeignKey(
|
|
||||||
to='self',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='children',
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
db_index=True
|
|
||||||
)
|
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
max_length=50,
|
max_length=50,
|
||||||
choices=LocationStatusChoices,
|
choices=LocationStatusChoices,
|
||||||
@ -329,10 +269,6 @@ class Location(NestedGroupModel):
|
|||||||
blank=True,
|
blank=True,
|
||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
description = models.CharField(
|
|
||||||
max_length=200,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generic relations
|
# Generic relations
|
||||||
vlan_groups = GenericRelation(
|
vlan_groups = GenericRelation(
|
||||||
|
293
netbox/dcim/search.py
Normal file
293
netbox/dcim/search.py
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
from netbox.search import SearchIndex, register_search
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class CableIndex(SearchIndex):
|
||||||
|
model = models.Cable
|
||||||
|
fields = (
|
||||||
|
('label', 100),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ConsolePortIndex(SearchIndex):
|
||||||
|
model = models.ConsolePort
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
('speed', 2000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ConsoleServerPortIndex(SearchIndex):
|
||||||
|
model = models.ConsoleServerPort
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
('speed', 2000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class DeviceIndex(SearchIndex):
|
||||||
|
model = models.Device
|
||||||
|
fields = (
|
||||||
|
('asset_tag', 50),
|
||||||
|
('serial', 60),
|
||||||
|
('name', 100),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class DeviceBayIndex(SearchIndex):
|
||||||
|
model = models.DeviceBay
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class DeviceRoleIndex(SearchIndex):
|
||||||
|
model = models.DeviceRole
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class DeviceTypeIndex(SearchIndex):
|
||||||
|
model = models.DeviceType
|
||||||
|
fields = (
|
||||||
|
('model', 100),
|
||||||
|
('part_number', 200),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class FrontPortIndex(SearchIndex):
|
||||||
|
model = models.FrontPort
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class InterfaceIndex(SearchIndex):
|
||||||
|
model = models.Interface
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('mac_address', 300),
|
||||||
|
('wwn', 300),
|
||||||
|
('description', 500),
|
||||||
|
('mtu', 2000),
|
||||||
|
('speed', 2000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class InventoryItemIndex(SearchIndex):
|
||||||
|
model = models.InventoryItem
|
||||||
|
fields = (
|
||||||
|
('asset_tag', 50),
|
||||||
|
('serial', 60),
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
('part_id', 2000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class LocationIndex(SearchIndex):
|
||||||
|
model = models.Location
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ManufacturerIndex(SearchIndex):
|
||||||
|
model = models.Manufacturer
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ModuleIndex(SearchIndex):
|
||||||
|
model = models.Module
|
||||||
|
fields = (
|
||||||
|
('asset_tag', 50),
|
||||||
|
('serial', 60),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ModuleBayIndex(SearchIndex):
|
||||||
|
model = models.ModuleBay
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class ModuleTypeIndex(SearchIndex):
|
||||||
|
model = models.ModuleType
|
||||||
|
fields = (
|
||||||
|
('model', 100),
|
||||||
|
('part_number', 200),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class PlatformIndex(SearchIndex):
|
||||||
|
model = models.Platform
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('napalm_driver', 300),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class PowerFeedIndex(SearchIndex):
|
||||||
|
model = models.PowerFeed
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class PowerOutletIndex(SearchIndex):
|
||||||
|
model = models.PowerOutlet
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class PowerPanelIndex(SearchIndex):
|
||||||
|
model = models.PowerPanel
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class PowerPortIndex(SearchIndex):
|
||||||
|
model = models.PowerPort
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
('maximum_draw', 2000),
|
||||||
|
('allocated_draw', 2000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class RackIndex(SearchIndex):
|
||||||
|
model = models.Rack
|
||||||
|
fields = (
|
||||||
|
('asset_tag', 50),
|
||||||
|
('serial', 60),
|
||||||
|
('name', 100),
|
||||||
|
('facility_id', 200),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class RackReservationIndex(SearchIndex):
|
||||||
|
model = models.RackReservation
|
||||||
|
fields = (
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class RackRoleIndex(SearchIndex):
|
||||||
|
model = models.RackRole
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class RearPortIndex(SearchIndex):
|
||||||
|
model = models.RearPort
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('label', 200),
|
||||||
|
('description', 500),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class RegionIndex(SearchIndex):
|
||||||
|
model = models.Region
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class SiteIndex(SearchIndex):
|
||||||
|
model = models.Site
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('facility', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500),
|
||||||
|
('physical_address', 2000),
|
||||||
|
('shipping_address', 2000),
|
||||||
|
('comments', 5000),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class SiteGroupIndex(SearchIndex):
|
||||||
|
model = models.SiteGroup
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('slug', 110),
|
||||||
|
('description', 500)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@register_search
|
||||||
|
class VirtualChassisIndex(SearchIndex):
|
||||||
|
model = models.VirtualChassis
|
||||||
|
fields = (
|
||||||
|
('name', 100),
|
||||||
|
('domain', 300)
|
||||||
|
)
|
@ -35,7 +35,7 @@ class Node(Hyperlink):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, position, width, url, color, labels, radius=10, **extra):
|
def __init__(self, position, width, url, color, labels, radius=10, **extra):
|
||||||
super(Node, self).__init__(href=url, target='_blank', **extra)
|
super(Node, self).__init__(href=url, target='_parent', **extra)
|
||||||
|
|
||||||
x, y = position
|
x, y = position
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ from svgwrite.text import Text
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
from django.template.defaultfilters import floatformat
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.http import urlencode
|
from django.utils.http import urlencode
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ def get_device_description(device):
|
|||||||
device.device_role,
|
device.device_role,
|
||||||
device.device_type.manufacturer.name,
|
device.device_type.manufacturer.name,
|
||||||
device.device_type.model,
|
device.device_type.model,
|
||||||
device.device_type.u_height,
|
floatformat(device.device_type.u_height),
|
||||||
device.asset_tag or '',
|
device.asset_tag or '',
|
||||||
device.serial or ''
|
device.serial or ''
|
||||||
)
|
)
|
||||||
|
@ -111,6 +111,7 @@ class CableTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
order_by=('_abs_length', 'length_unit')
|
order_by=('_abs_length', 'length_unit')
|
||||||
)
|
)
|
||||||
color = columns.ColorColumn()
|
color = columns.ColorColumn()
|
||||||
|
comments = columns.MarkdownColumn()
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:cable_list'
|
url_name='dcim:cable_list'
|
||||||
)
|
)
|
||||||
@ -120,7 +121,7 @@ class CableTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'device_a', 'device_b', 'rack_a', 'rack_b',
|
'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'device_a', 'device_b', 'rack_a', 'rack_b',
|
||||||
'location_a', 'location_b', 'site_a', 'site_b', 'status', 'type', 'tenant', 'tenant_group', 'color',
|
'location_a', 'location_b', 'site_a', 'site_b', 'status', 'type', 'tenant', 'tenant_group', 'color',
|
||||||
'length', 'tags', 'created', 'last_updated',
|
'length', 'description', 'comments', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'status', 'type',
|
'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'status', 'type',
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
from dcim import models
|
||||||
from django_tables2.utils import Accessor
|
from django_tables2.utils import Accessor
|
||||||
|
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
|
||||||
|
|
||||||
from dcim.models import (
|
|
||||||
ConsolePort, ConsoleServerPort, Device, DeviceBay, DeviceRole, FrontPort, Interface, InventoryItem,
|
|
||||||
InventoryItemRole, ModuleBay, Platform, PowerOutlet, PowerPort, RearPort, VirtualChassis,
|
|
||||||
)
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
from tenancy.tables import TenancyColumnsMixin
|
|
||||||
from .template_code import *
|
from .template_code import *
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -92,7 +90,7 @@ class DeviceRoleTable(NetBoxTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = DeviceRole
|
model = models.DeviceRole
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'slug', 'tags',
|
'pk', 'id', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'slug', 'tags',
|
||||||
'actions', 'created', 'last_updated',
|
'actions', 'created', 'last_updated',
|
||||||
@ -123,7 +121,7 @@ class PlatformTable(NetBoxTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Platform
|
model = models.Platform
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'napalm_args',
|
'pk', 'id', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'napalm_args',
|
||||||
'description', 'tags', 'actions', 'created', 'last_updated',
|
'description', 'tags', 'actions', 'created', 'last_updated',
|
||||||
@ -137,7 +135,7 @@ class PlatformTable(NetBoxTable):
|
|||||||
# Devices
|
# Devices
|
||||||
#
|
#
|
||||||
|
|
||||||
class DeviceTable(TenancyColumnsMixin, NetBoxTable):
|
class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
name = tables.TemplateColumn(
|
name = tables.TemplateColumn(
|
||||||
order_by=('_name',),
|
order_by=('_name',),
|
||||||
template_code=DEVICE_LINK
|
template_code=DEVICE_LINK
|
||||||
@ -201,20 +199,17 @@ class DeviceTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
verbose_name='VC Priority'
|
verbose_name='VC Priority'
|
||||||
)
|
)
|
||||||
comments = columns.MarkdownColumn()
|
comments = columns.MarkdownColumn()
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:device_list'
|
url_name='dcim:device_list'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Device
|
model = models.Device
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type',
|
'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type',
|
||||||
'platform', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'position', 'face',
|
'platform', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'position', 'face',
|
||||||
'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position',
|
'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position',
|
||||||
'vc_priority', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
'vc_priority', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'device_role', 'manufacturer', 'device_type',
|
'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'device_role', 'manufacturer', 'device_type',
|
||||||
@ -241,7 +236,7 @@ class DeviceImportTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Device
|
model = models.Device
|
||||||
fields = ('id', 'name', 'status', 'tenant', 'tenant_group', 'site', 'rack', 'position', 'device_role', 'device_type')
|
fields = ('id', 'name', 'status', 'tenant', 'tenant_group', 'site', 'rack', 'position', 'device_role', 'device_type')
|
||||||
empty_text = False
|
empty_text = False
|
||||||
|
|
||||||
@ -315,7 +310,7 @@ class ConsolePortTable(ModularDeviceComponentTable, PathEndpointTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ConsolePort
|
model = models.ConsolePort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description',
|
||||||
'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', 'last_updated',
|
'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', 'last_updated',
|
||||||
@ -334,7 +329,7 @@ class DeviceConsolePortTable(ConsolePortTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ConsolePort
|
model = models.ConsolePort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected',
|
||||||
'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions'
|
'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions'
|
||||||
@ -357,7 +352,7 @@ class ConsoleServerPortTable(ModularDeviceComponentTable, PathEndpointTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ConsoleServerPort
|
model = models.ConsoleServerPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description',
|
||||||
'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', 'last_updated',
|
'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', 'last_updated',
|
||||||
@ -377,7 +372,7 @@ class DeviceConsoleServerPortTable(ConsoleServerPortTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ConsoleServerPort
|
model = models.ConsoleServerPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected',
|
||||||
'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
|
'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
|
||||||
@ -400,7 +395,7 @@ class PowerPortTable(ModularDeviceComponentTable, PathEndpointTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = PowerPort
|
model = models.PowerPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'mark_connected',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'mark_connected',
|
||||||
'maximum_draw', 'allocated_draw', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created',
|
'maximum_draw', 'allocated_draw', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created',
|
||||||
@ -421,7 +416,7 @@ class DevicePowerPortTable(PowerPortTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = PowerPort
|
model = models.PowerPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'maximum_draw', 'allocated_draw',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'maximum_draw', 'allocated_draw',
|
||||||
'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
|
'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
|
||||||
@ -449,7 +444,7 @@ class PowerOutletTable(ModularDeviceComponentTable, PathEndpointTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = PowerOutlet
|
model = models.PowerOutlet
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'power_port',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'power_port',
|
||||||
'feed_leg', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created',
|
'feed_leg', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created',
|
||||||
@ -469,7 +464,7 @@ class DevicePowerOutletTable(PowerOutletTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = PowerOutlet
|
model = models.PowerOutlet
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'power_port', 'feed_leg', 'description',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'power_port', 'feed_leg', 'description',
|
||||||
'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
|
'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions',
|
||||||
@ -533,7 +528,7 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = Interface
|
model = models.Interface
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu',
|
||||||
'speed', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel',
|
'speed', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel',
|
||||||
@ -567,7 +562,7 @@ class DeviceInterfaceTable(InterfaceTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = Interface
|
model = models.Interface
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag',
|
||||||
'mgmt_only', 'mtu', 'mode', 'mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
'mgmt_only', 'mtu', 'mode', 'mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency',
|
||||||
@ -606,7 +601,7 @@ class FrontPortTable(ModularDeviceComponentTable, CableTerminationTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = FrontPort
|
model = models.FrontPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'rear_port',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'rear_port',
|
||||||
'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags',
|
'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags',
|
||||||
@ -629,7 +624,7 @@ class DeviceFrontPortTable(FrontPortTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = FrontPort
|
model = models.FrontPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'rear_port', 'rear_port_position',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'rear_port', 'rear_port_position',
|
||||||
'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'actions',
|
'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'actions',
|
||||||
@ -655,7 +650,7 @@ class RearPortTable(ModularDeviceComponentTable, CableTerminationTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = RearPort
|
model = models.RearPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'description',
|
'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'description',
|
||||||
'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'created', 'last_updated',
|
'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'created', 'last_updated',
|
||||||
@ -675,7 +670,7 @@ class DeviceRearPortTable(RearPortTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = RearPort
|
model = models.RearPort
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'positions', 'description', 'mark_connected',
|
'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'positions', 'description', 'mark_connected',
|
||||||
'cable', 'cable_color', 'link_peer', 'tags', 'actions',
|
'cable', 'cable_color', 'link_peer', 'tags', 'actions',
|
||||||
@ -716,7 +711,7 @@ class DeviceBayTable(DeviceComponentTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = DeviceBay
|
model = models.DeviceBay
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'label', 'status', 'device_role', 'device_type', 'installed_device', 'description', 'tags',
|
'pk', 'id', 'name', 'device', 'label', 'status', 'device_role', 'device_type', 'installed_device', 'description', 'tags',
|
||||||
'created', 'last_updated',
|
'created', 'last_updated',
|
||||||
@ -737,7 +732,7 @@ class DeviceDeviceBayTable(DeviceBayTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = DeviceBay
|
model = models.DeviceBay
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'label', 'status', 'installed_device', 'description', 'tags', 'actions',
|
'pk', 'id', 'name', 'label', 'status', 'installed_device', 'description', 'tags', 'actions',
|
||||||
)
|
)
|
||||||
@ -766,7 +761,7 @@ class ModuleBayTable(DeviceComponentTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ModuleBay
|
model = models.ModuleBay
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'label', 'position', 'installed_module', 'module_serial', 'module_asset_tag',
|
'pk', 'id', 'name', 'device', 'label', 'position', 'installed_module', 'module_serial', 'module_asset_tag',
|
||||||
'description', 'tags',
|
'description', 'tags',
|
||||||
@ -780,7 +775,7 @@ class DeviceModuleBayTable(ModuleBayTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(DeviceComponentTable.Meta):
|
class Meta(DeviceComponentTable.Meta):
|
||||||
model = ModuleBay
|
model = models.ModuleBay
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'label', 'position', 'installed_module', 'module_serial', 'module_asset_tag',
|
'pk', 'id', 'name', 'label', 'position', 'installed_module', 'module_serial', 'module_asset_tag',
|
||||||
'description', 'tags', 'actions',
|
'description', 'tags', 'actions',
|
||||||
@ -810,7 +805,7 @@ class InventoryItemTable(DeviceComponentTable):
|
|||||||
cable = None # Override DeviceComponentTable
|
cable = None # Override DeviceComponentTable
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = InventoryItem
|
model = models.InventoryItem
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'device', 'component', 'label', 'role', 'manufacturer', 'part_id', 'serial',
|
'pk', 'id', 'name', 'device', 'component', 'label', 'role', 'manufacturer', 'part_id', 'serial',
|
||||||
'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated',
|
'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated',
|
||||||
@ -829,7 +824,7 @@ class DeviceInventoryItemTable(InventoryItemTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = InventoryItem
|
model = models.InventoryItem
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'component',
|
'pk', 'id', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'component',
|
||||||
'description', 'discovered', 'tags', 'actions',
|
'description', 'discovered', 'tags', 'actions',
|
||||||
@ -854,7 +849,7 @@ class InventoryItemRoleTable(NetBoxTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = InventoryItemRole
|
model = models.InventoryItemRole
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'inventoryitem_count', 'color', 'description', 'slug', 'tags', 'actions',
|
'pk', 'id', 'name', 'inventoryitem_count', 'color', 'description', 'slug', 'tags', 'actions',
|
||||||
)
|
)
|
||||||
@ -877,11 +872,15 @@ class VirtualChassisTable(NetBoxTable):
|
|||||||
url_params={'virtual_chassis_id': 'pk'},
|
url_params={'virtual_chassis_id': 'pk'},
|
||||||
verbose_name='Members'
|
verbose_name='Members'
|
||||||
)
|
)
|
||||||
|
comments = columns.MarkdownColumn()
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:virtualchassis_list'
|
url_name='dcim:virtualchassis_list'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = VirtualChassis
|
model = models.VirtualChassis
|
||||||
fields = ('pk', 'id', 'name', 'domain', 'master', 'member_count', 'tags', 'created', 'last_updated',)
|
fields = (
|
||||||
|
'pk', 'id', 'name', 'domain', 'master', 'member_count', 'description', 'comments', 'tags', 'created',
|
||||||
|
'last_updated',
|
||||||
|
)
|
||||||
default_columns = ('pk', 'name', 'domain', 'master', 'member_count')
|
default_columns = ('pk', 'name', 'domain', 'master', 'member_count')
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from dcim.models import (
|
from dcim import models
|
||||||
ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, DeviceType, FrontPortTemplate, InterfaceTemplate,
|
|
||||||
InventoryItemTemplate, Manufacturer, ModuleBayTemplate, PowerOutletTemplate, PowerPortTemplate, RearPortTemplate,
|
|
||||||
)
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
from .template_code import MODULAR_COMPONENT_TEMPLATE_BUTTONS
|
from tenancy.tables import ContactsColumnMixin
|
||||||
|
from .template_code import MODULAR_COMPONENT_TEMPLATE_BUTTONS, DEVICE_WEIGHT
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ConsolePortTemplateTable',
|
'ConsolePortTemplateTable',
|
||||||
@ -27,7 +25,7 @@ __all__ = (
|
|||||||
# Manufacturers
|
# Manufacturers
|
||||||
#
|
#
|
||||||
|
|
||||||
class ManufacturerTable(NetBoxTable):
|
class ManufacturerTable(ContactsColumnMixin, NetBoxTable):
|
||||||
name = tables.Column(
|
name = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -43,15 +41,12 @@ class ManufacturerTable(NetBoxTable):
|
|||||||
verbose_name='Platforms'
|
verbose_name='Platforms'
|
||||||
)
|
)
|
||||||
slug = tables.Column()
|
slug = tables.Column()
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:manufacturer_list'
|
url_name='dcim:manufacturer_list'
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Manufacturer
|
model = models.Manufacturer
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'devicetype_count', 'inventoryitem_count', 'platform_count', 'description', 'slug',
|
'pk', 'id', 'name', 'devicetype_count', 'inventoryitem_count', 'platform_count', 'description', 'slug',
|
||||||
'contacts', 'actions', 'created', 'last_updated',
|
'contacts', 'actions', 'created', 'last_updated',
|
||||||
@ -85,12 +80,19 @@ class DeviceTypeTable(NetBoxTable):
|
|||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:devicetype_list'
|
url_name='dcim:devicetype_list'
|
||||||
)
|
)
|
||||||
|
u_height = columns.TemplateColumn(
|
||||||
|
template_code='{{ value|floatformat }}'
|
||||||
|
)
|
||||||
|
weight = columns.TemplateColumn(
|
||||||
|
template_code=DEVICE_WEIGHT,
|
||||||
|
order_by=('_abs_weight', 'weight_unit')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = DeviceType
|
model = models.DeviceType
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'model', 'manufacturer', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
|
'pk', 'id', 'model', 'manufacturer', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role',
|
||||||
'airflow', 'comments', 'instance_count', 'tags', 'created', 'last_updated',
|
'airflow', 'weight', 'description', 'comments', 'instance_count', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'instance_count',
|
'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'instance_count',
|
||||||
@ -120,7 +122,7 @@ class ConsolePortTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = ConsolePortTemplate
|
model = models.ConsolePortTemplate
|
||||||
fields = ('pk', 'name', 'label', 'type', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'type', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -132,7 +134,7 @@ class ConsoleServerPortTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = ConsoleServerPortTemplate
|
model = models.ConsoleServerPortTemplate
|
||||||
fields = ('pk', 'name', 'label', 'type', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'type', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -144,7 +146,7 @@ class PowerPortTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = PowerPortTemplate
|
model = models.PowerPortTemplate
|
||||||
fields = ('pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -156,7 +158,7 @@ class PowerOutletTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = PowerOutletTemplate
|
model = models.PowerOutletTemplate
|
||||||
fields = ('pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -171,7 +173,7 @@ class InterfaceTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = InterfaceTemplate
|
model = models.InterfaceTemplate
|
||||||
fields = ('pk', 'name', 'label', 'mgmt_only', 'type', 'description', 'poe_mode', 'poe_type', 'actions')
|
fields = ('pk', 'name', 'label', 'mgmt_only', 'type', 'description', 'poe_mode', 'poe_type', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -187,7 +189,7 @@ class FrontPortTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = FrontPortTemplate
|
model = models.FrontPortTemplate
|
||||||
fields = ('pk', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -200,7 +202,7 @@ class RearPortTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = RearPortTemplate
|
model = models.RearPortTemplate
|
||||||
fields = ('pk', 'name', 'label', 'type', 'color', 'positions', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'type', 'color', 'positions', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -211,7 +213,7 @@ class ModuleBayTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = ModuleBayTemplate
|
model = models.ModuleBayTemplate
|
||||||
fields = ('pk', 'name', 'label', 'position', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'position', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -222,7 +224,7 @@ class DeviceBayTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = DeviceBayTemplate
|
model = models.DeviceBayTemplate
|
||||||
fields = ('pk', 'name', 'label', 'description', 'actions')
|
fields = ('pk', 'name', 'label', 'description', 'actions')
|
||||||
empty_text = "None"
|
empty_text = "None"
|
||||||
|
|
||||||
@ -242,7 +244,7 @@ class InventoryItemTemplateTable(ComponentTemplateTable):
|
|||||||
)
|
)
|
||||||
|
|
||||||
class Meta(ComponentTemplateTable.Meta):
|
class Meta(ComponentTemplateTable.Meta):
|
||||||
model = InventoryItemTemplate
|
model = models.InventoryItemTemplate
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'name', 'label', 'parent', 'role', 'manufacturer', 'part_id', 'component', 'description', 'actions',
|
'pk', 'name', 'label', 'parent', 'role', 'manufacturer', 'part_id', 'component', 'description', 'actions',
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,7 @@ import django_tables2 as tables
|
|||||||
|
|
||||||
from dcim.models import Module, ModuleType
|
from dcim.models import Module, ModuleType
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
|
from .template_code import DEVICE_WEIGHT
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ModuleTable',
|
'ModuleTable',
|
||||||
@ -26,11 +27,15 @@ class ModuleTypeTable(NetBoxTable):
|
|||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:moduletype_list'
|
url_name='dcim:moduletype_list'
|
||||||
)
|
)
|
||||||
|
weight = columns.TemplateColumn(
|
||||||
|
template_code=DEVICE_WEIGHT,
|
||||||
|
order_by=('_abs_weight', 'weight_unit')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'model', 'manufacturer', 'part_number', 'comments', 'tags',
|
'pk', 'id', 'model', 'manufacturer', 'part_number', 'weight', 'description', 'comments', 'tags',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'model', 'manufacturer', 'part_number',
|
'pk', 'model', 'manufacturer', 'part_number',
|
||||||
@ -59,8 +64,8 @@ class ModuleTable(NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Module
|
model = Module
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'comments',
|
'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'description',
|
||||||
'tags',
|
'comments', 'tags',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag',
|
'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag',
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from dcim.models import PowerFeed, PowerPanel
|
from dcim.models import PowerFeed, PowerPanel
|
||||||
|
from tenancy.tables import ContactsColumnMixin
|
||||||
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
|
|
||||||
from .devices import CableTerminationTable
|
from .devices import CableTerminationTable
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -14,7 +16,7 @@ __all__ = (
|
|||||||
# Power panels
|
# Power panels
|
||||||
#
|
#
|
||||||
|
|
||||||
class PowerPanelTable(NetBoxTable):
|
class PowerPanelTable(ContactsColumnMixin, NetBoxTable):
|
||||||
name = tables.Column(
|
name = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -29,9 +31,7 @@ class PowerPanelTable(NetBoxTable):
|
|||||||
url_params={'power_panel_id': 'pk'},
|
url_params={'power_panel_id': 'pk'},
|
||||||
verbose_name='Feeds'
|
verbose_name='Feeds'
|
||||||
)
|
)
|
||||||
contacts = columns.ManyToManyColumn(
|
comments = columns.MarkdownColumn()
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:powerpanel_list'
|
url_name='dcim:powerpanel_list'
|
||||||
)
|
)
|
||||||
@ -39,7 +39,8 @@ class PowerPanelTable(NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'site', 'location', 'powerfeed_count', 'contacts', 'tags', 'created', 'last_updated',
|
'pk', 'id', 'name', 'site', 'location', 'powerfeed_count', 'contacts', 'description', 'comments', 'tags',
|
||||||
|
'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'name', 'site', 'location', 'powerfeed_count')
|
default_columns = ('pk', 'name', 'site', 'location', 'powerfeed_count')
|
||||||
|
|
||||||
@ -78,7 +79,7 @@ class PowerFeedTable(CableTerminationTable):
|
|||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
|
'pk', 'id', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase',
|
||||||
'max_utilization', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'available_power',
|
'max_utilization', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'available_power',
|
||||||
'comments', 'tags', 'created', 'last_updated',
|
'description', 'comments', 'tags', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'cable',
|
'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'cable',
|
||||||
|
@ -3,7 +3,8 @@ from django_tables2.utils import Accessor
|
|||||||
|
|
||||||
from dcim.models import Rack, RackReservation, RackRole
|
from dcim.models import Rack, RackReservation, RackRole
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
from tenancy.tables import TenancyColumnsMixin
|
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
|
||||||
|
from .template_code import DEVICE_WEIGHT
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'RackTable',
|
'RackTable',
|
||||||
@ -37,7 +38,7 @@ class RackRoleTable(NetBoxTable):
|
|||||||
# Racks
|
# Racks
|
||||||
#
|
#
|
||||||
|
|
||||||
class RackTable(TenancyColumnsMixin, NetBoxTable):
|
class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
name = tables.Column(
|
name = tables.Column(
|
||||||
order_by=('_name',),
|
order_by=('_name',),
|
||||||
linkify=True
|
linkify=True
|
||||||
@ -68,9 +69,6 @@ class RackTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name='Power'
|
verbose_name='Power'
|
||||||
)
|
)
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:rack_list'
|
url_name='dcim:rack_list'
|
||||||
)
|
)
|
||||||
@ -82,13 +80,18 @@ class RackTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
template_code="{{ record.outer_depth }} {{ record.outer_unit }}",
|
template_code="{{ record.outer_depth }} {{ record.outer_unit }}",
|
||||||
verbose_name='Outer Depth'
|
verbose_name='Outer Depth'
|
||||||
)
|
)
|
||||||
|
weight = columns.TemplateColumn(
|
||||||
|
template_code=DEVICE_WEIGHT,
|
||||||
|
order_by=('_abs_weight', 'weight_unit')
|
||||||
|
)
|
||||||
|
|
||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'serial', 'asset_tag',
|
'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'serial',
|
||||||
'type', 'width', 'outer_width', 'outer_depth', 'u_height', 'comments', 'device_count', 'get_utilization',
|
'asset_tag', 'type', 'u_height', 'width', 'outer_width', 'outer_depth', 'mounting_depth', 'weight',
|
||||||
'get_power_utilization', 'contacts', 'tags', 'created', 'last_updated',
|
'comments', 'device_count', 'get_utilization', 'get_power_utilization', 'description', 'contacts', 'tags',
|
||||||
|
'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = (
|
default_columns = (
|
||||||
'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'u_height', 'device_count',
|
'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'u_height', 'device_count',
|
||||||
@ -120,6 +123,7 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
orderable=False,
|
orderable=False,
|
||||||
verbose_name='Units'
|
verbose_name='Units'
|
||||||
)
|
)
|
||||||
|
comments = columns.MarkdownColumn()
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:rackreservation_list'
|
url_name='dcim:rackreservation_list'
|
||||||
)
|
)
|
||||||
@ -127,7 +131,7 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
class Meta(NetBoxTable.Meta):
|
class Meta(NetBoxTable.Meta):
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = (
|
fields = (
|
||||||
'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'user', 'created', 'tenant', 'tenant_group', 'description', 'tags',
|
'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'user', 'created', 'tenant',
|
||||||
'actions', 'created', 'last_updated',
|
'tenant_group', 'description', 'comments', 'tags', 'actions', 'created', 'last_updated',
|
||||||
)
|
)
|
||||||
default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description')
|
default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description')
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
|
|
||||||
from dcim.models import Location, Region, Site, SiteGroup
|
from dcim.models import Location, Region, Site, SiteGroup
|
||||||
|
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
|
||||||
|
|
||||||
from netbox.tables import NetBoxTable, columns
|
from netbox.tables import NetBoxTable, columns
|
||||||
from tenancy.tables import TenancyColumnsMixin
|
|
||||||
from .template_code import LOCATION_BUTTONS
|
from .template_code import LOCATION_BUTTONS
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
@ -17,7 +18,7 @@ __all__ = (
|
|||||||
# Regions
|
# Regions
|
||||||
#
|
#
|
||||||
|
|
||||||
class RegionTable(NetBoxTable):
|
class RegionTable(ContactsColumnMixin, NetBoxTable):
|
||||||
name = columns.MPTTColumn(
|
name = columns.MPTTColumn(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -26,9 +27,6 @@ class RegionTable(NetBoxTable):
|
|||||||
url_params={'region_id': 'pk'},
|
url_params={'region_id': 'pk'},
|
||||||
verbose_name='Sites'
|
verbose_name='Sites'
|
||||||
)
|
)
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:region_list'
|
url_name='dcim:region_list'
|
||||||
)
|
)
|
||||||
@ -46,7 +44,7 @@ class RegionTable(NetBoxTable):
|
|||||||
# Site groups
|
# Site groups
|
||||||
#
|
#
|
||||||
|
|
||||||
class SiteGroupTable(NetBoxTable):
|
class SiteGroupTable(ContactsColumnMixin, NetBoxTable):
|
||||||
name = columns.MPTTColumn(
|
name = columns.MPTTColumn(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -55,9 +53,6 @@ class SiteGroupTable(NetBoxTable):
|
|||||||
url_params={'group_id': 'pk'},
|
url_params={'group_id': 'pk'},
|
||||||
verbose_name='Sites'
|
verbose_name='Sites'
|
||||||
)
|
)
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:sitegroup_list'
|
url_name='dcim:sitegroup_list'
|
||||||
)
|
)
|
||||||
@ -75,7 +70,7 @@ class SiteGroupTable(NetBoxTable):
|
|||||||
# Sites
|
# Sites
|
||||||
#
|
#
|
||||||
|
|
||||||
class SiteTable(TenancyColumnsMixin, NetBoxTable):
|
class SiteTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
name = tables.Column(
|
name = tables.Column(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -97,9 +92,6 @@ class SiteTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
verbose_name='ASN Count'
|
verbose_name='ASN Count'
|
||||||
)
|
)
|
||||||
comments = columns.MarkdownColumn()
|
comments = columns.MarkdownColumn()
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:site_list'
|
url_name='dcim:site_list'
|
||||||
)
|
)
|
||||||
@ -118,7 +110,7 @@ class SiteTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
# Locations
|
# Locations
|
||||||
#
|
#
|
||||||
|
|
||||||
class LocationTable(TenancyColumnsMixin, NetBoxTable):
|
class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
|
||||||
name = columns.MPTTColumn(
|
name = columns.MPTTColumn(
|
||||||
linkify=True
|
linkify=True
|
||||||
)
|
)
|
||||||
@ -136,9 +128,6 @@ class LocationTable(TenancyColumnsMixin, NetBoxTable):
|
|||||||
url_params={'location_id': 'pk'},
|
url_params={'location_id': 'pk'},
|
||||||
verbose_name='Devices'
|
verbose_name='Devices'
|
||||||
)
|
)
|
||||||
contacts = columns.ManyToManyColumn(
|
|
||||||
linkify_item=True
|
|
||||||
)
|
|
||||||
tags = columns.TagColumn(
|
tags = columns.TagColumn(
|
||||||
url_name='dcim:location_list'
|
url_name='dcim:location_list'
|
||||||
)
|
)
|
||||||
|
@ -15,6 +15,11 @@ CABLE_LENGTH = """
|
|||||||
{% if record.length %}{{ record.length|simplify_decimal }} {{ record.length_unit }}{% endif %}
|
{% if record.length %}{{ record.length|simplify_decimal }} {{ record.length_unit }}{% endif %}
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
DEVICE_WEIGHT = """
|
||||||
|
{% load helpers %}
|
||||||
|
{% if record.weight %}{{ record.weight|simplify_decimal }} {{ record.weight_unit }}{% endif %}
|
||||||
|
"""
|
||||||
|
|
||||||
DEVICE_LINK = """
|
DEVICE_LINK = """
|
||||||
<a href="{% url 'dcim:device' pk=record.pk %}">
|
<a href="{% url 'dcim:device' pk=record.pk %}">
|
||||||
{{ record.name|default:'<span class="badge bg-info">Unnamed device</span>' }}
|
{{ record.name|default:'<span class="badge bg-info">Unnamed device</span>' }}
|
||||||
|
@ -409,9 +409,9 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
Tenant.objects.bulk_create(tenants)
|
Tenant.objects.bulk_create(tenants)
|
||||||
|
|
||||||
racks = (
|
racks = (
|
||||||
Rack(name='Rack 1', facility_id='rack-1', site=sites[0], location=locations[0], tenant=tenants[0], status=RackStatusChoices.STATUS_ACTIVE, role=rack_roles[0], serial='ABC', asset_tag='1001', type=RackTypeChoices.TYPE_2POST, width=RackWidthChoices.WIDTH_19IN, u_height=42, desc_units=False, outer_width=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER),
|
Rack(name='Rack 1', facility_id='rack-1', site=sites[0], location=locations[0], tenant=tenants[0], status=RackStatusChoices.STATUS_ACTIVE, role=rack_roles[0], serial='ABC', asset_tag='1001', type=RackTypeChoices.TYPE_2POST, width=RackWidthChoices.WIDTH_19IN, u_height=42, desc_units=False, outer_width=100, outer_depth=100, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, weight=10, weight_unit=WeightUnitChoices.UNIT_POUND),
|
||||||
Rack(name='Rack 2', facility_id='rack-2', site=sites[1], location=locations[1], tenant=tenants[1], status=RackStatusChoices.STATUS_PLANNED, role=rack_roles[1], serial='DEF', asset_tag='1002', type=RackTypeChoices.TYPE_4POST, width=RackWidthChoices.WIDTH_21IN, u_height=43, desc_units=False, outer_width=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER),
|
Rack(name='Rack 2', facility_id='rack-2', site=sites[1], location=locations[1], tenant=tenants[1], status=RackStatusChoices.STATUS_PLANNED, role=rack_roles[1], serial='DEF', asset_tag='1002', type=RackTypeChoices.TYPE_4POST, width=RackWidthChoices.WIDTH_21IN, u_height=43, desc_units=False, outer_width=200, outer_depth=200, outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER, weight=20, weight_unit=WeightUnitChoices.UNIT_POUND),
|
||||||
Rack(name='Rack 3', facility_id='rack-3', site=sites[2], location=locations[2], tenant=tenants[2], status=RackStatusChoices.STATUS_RESERVED, role=rack_roles[2], serial='GHI', asset_tag='1003', type=RackTypeChoices.TYPE_CABINET, width=RackWidthChoices.WIDTH_23IN, u_height=44, desc_units=True, outer_width=300, outer_depth=300, outer_unit=RackDimensionUnitChoices.UNIT_INCH),
|
Rack(name='Rack 3', facility_id='rack-3', site=sites[2], location=locations[2], tenant=tenants[2], status=RackStatusChoices.STATUS_RESERVED, role=rack_roles[2], serial='GHI', asset_tag='1003', type=RackTypeChoices.TYPE_CABINET, width=RackWidthChoices.WIDTH_23IN, u_height=44, desc_units=True, outer_width=300, outer_depth=300, outer_unit=RackDimensionUnitChoices.UNIT_INCH, weight=30, weight_unit=WeightUnitChoices.UNIT_KILOGRAM),
|
||||||
)
|
)
|
||||||
Rack.objects.bulk_create(racks)
|
Rack.objects.bulk_create(racks)
|
||||||
|
|
||||||
@ -517,6 +517,14 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_weight(self):
|
||||||
|
params = {'weight': [10, 20]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_weight_unit(self):
|
||||||
|
params = {'weight_unit': WeightUnitChoices.UNIT_POUND}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = RackReservation.objects.all()
|
queryset = RackReservation.objects.all()
|
||||||
@ -688,9 +696,9 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
Manufacturer.objects.bulk_create(manufacturers)
|
Manufacturer.objects.bulk_create(manufacturers)
|
||||||
|
|
||||||
device_types = (
|
device_types = (
|
||||||
DeviceType(manufacturer=manufacturers[0], model='Model 1', slug='model-1', part_number='Part Number 1', u_height=1, is_full_depth=True, front_image='front.png', rear_image='rear.png'),
|
DeviceType(manufacturer=manufacturers[0], model='Model 1', slug='model-1', part_number='Part Number 1', u_height=1, is_full_depth=True, front_image='front.png', rear_image='rear.png', weight=10, weight_unit=WeightUnitChoices.UNIT_POUND),
|
||||||
DeviceType(manufacturer=manufacturers[1], model='Model 2', slug='model-2', part_number='Part Number 2', u_height=2, is_full_depth=True, subdevice_role=SubdeviceRoleChoices.ROLE_PARENT, airflow=DeviceAirflowChoices.AIRFLOW_FRONT_TO_REAR),
|
DeviceType(manufacturer=manufacturers[1], model='Model 2', slug='model-2', part_number='Part Number 2', u_height=2, is_full_depth=True, subdevice_role=SubdeviceRoleChoices.ROLE_PARENT, airflow=DeviceAirflowChoices.AIRFLOW_FRONT_TO_REAR, weight=20, weight_unit=WeightUnitChoices.UNIT_POUND),
|
||||||
DeviceType(manufacturer=manufacturers[2], model='Model 3', slug='model-3', part_number='Part Number 3', u_height=3, is_full_depth=False, subdevice_role=SubdeviceRoleChoices.ROLE_CHILD, airflow=DeviceAirflowChoices.AIRFLOW_REAR_TO_FRONT),
|
DeviceType(manufacturer=manufacturers[2], model='Model 3', slug='model-3', part_number='Part Number 3', u_height=3, is_full_depth=False, subdevice_role=SubdeviceRoleChoices.ROLE_CHILD, airflow=DeviceAirflowChoices.AIRFLOW_REAR_TO_FRONT, weight=30, weight_unit=WeightUnitChoices.UNIT_KILOGRAM),
|
||||||
)
|
)
|
||||||
DeviceType.objects.bulk_create(device_types)
|
DeviceType.objects.bulk_create(device_types)
|
||||||
|
|
||||||
@ -839,6 +847,14 @@ class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'inventory_items': 'false'}
|
params = {'inventory_items': 'false'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_weight(self):
|
||||||
|
params = {'weight': [10, 20]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_weight_unit(self):
|
||||||
|
params = {'weight_unit': WeightUnitChoices.UNIT_POUND}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ModuleType.objects.all()
|
queryset = ModuleType.objects.all()
|
||||||
@ -855,9 +871,9 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
Manufacturer.objects.bulk_create(manufacturers)
|
Manufacturer.objects.bulk_create(manufacturers)
|
||||||
|
|
||||||
module_types = (
|
module_types = (
|
||||||
ModuleType(manufacturer=manufacturers[0], model='Model 1', part_number='Part Number 1'),
|
ModuleType(manufacturer=manufacturers[0], model='Model 1', part_number='Part Number 1', weight=10, weight_unit=WeightUnitChoices.UNIT_POUND),
|
||||||
ModuleType(manufacturer=manufacturers[1], model='Model 2', part_number='Part Number 2'),
|
ModuleType(manufacturer=manufacturers[1], model='Model 2', part_number='Part Number 2', weight=20, weight_unit=WeightUnitChoices.UNIT_POUND),
|
||||||
ModuleType(manufacturer=manufacturers[2], model='Model 3', part_number='Part Number 3'),
|
ModuleType(manufacturer=manufacturers[2], model='Model 3', part_number='Part Number 3', weight=30, weight_unit=WeightUnitChoices.UNIT_KILOGRAM),
|
||||||
)
|
)
|
||||||
ModuleType.objects.bulk_create(module_types)
|
ModuleType.objects.bulk_create(module_types)
|
||||||
|
|
||||||
@ -943,6 +959,14 @@ class ModuleTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'pass_through_ports': 'false'}
|
params = {'pass_through_ports': 'false'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
def test_weight(self):
|
||||||
|
params = {'weight': [10, 20]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_weight_unit(self):
|
||||||
|
params = {'weight_unit': WeightUnitChoices.UNIT_POUND}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class ConsolePortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ConsolePortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ConsolePortTemplate.objects.all()
|
queryset = ConsolePortTemplate.objects.all()
|
||||||
@ -1646,6 +1670,8 @@ class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
device_types = DeviceType.objects.all()[:2]
|
device_types = DeviceType.objects.all()[:2]
|
||||||
params = {'device_type_id': [device_types[0].pk, device_types[1].pk]}
|
params = {'device_type_id': [device_types[0].pk, device_types[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
params = {'device_type': [device_types[0].slug, device_types[1].slug]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_devicerole(self):
|
def test_devicerole(self):
|
||||||
device_roles = DeviceRole.objects.all()[:2]
|
device_roles = DeviceRole.objects.all()[:2]
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
try:
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
except ImportError:
|
||||||
|
# Python 3.8
|
||||||
|
from backports.zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pytz
|
|
||||||
import yaml
|
import yaml
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
@ -12,7 +16,6 @@ from dcim.choices import *
|
|||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from dcim.models import *
|
from dcim.models import *
|
||||||
from ipam.models import ASN, RIR, VLAN, VRF
|
from ipam.models import ASN, RIR, VLAN, VRF
|
||||||
from netbox.api.serializers import GenericObjectSerializer
|
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.testing import ViewTestCases, create_tags, create_test_device, post_data
|
from utilities.testing import ViewTestCases, create_tags, create_test_device, post_data
|
||||||
from wireless.models import WirelessLAN
|
from wireless.models import WirelessLAN
|
||||||
@ -50,6 +53,13 @@ class RegionTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Region 6,region-6,Sixth region",
|
"Region 6,region-6,Sixth region",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{regions[0].pk},Region 7,Fourth region7",
|
||||||
|
f"{regions[1].pk},Region 8,Fifth region8",
|
||||||
|
f"{regions[2].pk},Region 0,Sixth region9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
@ -87,6 +97,13 @@ class SiteGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Site Group 6,site-group-6,Sixth site group",
|
"Site Group 6,site-group-6,Sixth site group",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{sitegroups[0].pk},Site Group 7,Fourth site group7",
|
||||||
|
f"{sitegroups[1].pk},Site Group 8,Fifth site group8",
|
||||||
|
f"{sitegroups[2].pk},Site Group 0,Sixth site group9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
@ -139,7 +156,7 @@ class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
'tenant': None,
|
'tenant': None,
|
||||||
'facility': 'Facility X',
|
'facility': 'Facility X',
|
||||||
'asns': [asns[6].pk, asns[7].pk],
|
'asns': [asns[6].pk, asns[7].pk],
|
||||||
'time_zone': pytz.UTC,
|
'time_zone': ZoneInfo('UTC'),
|
||||||
'description': 'Site description',
|
'description': 'Site description',
|
||||||
'physical_address': '742 Evergreen Terrace, Springfield, USA',
|
'physical_address': '742 Evergreen Terrace, Springfield, USA',
|
||||||
'shipping_address': '742 Evergreen Terrace, Springfield, USA',
|
'shipping_address': '742 Evergreen Terrace, Springfield, USA',
|
||||||
@ -156,12 +173,19 @@ class SiteTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Site 6,site-6,staging",
|
"Site 6,site-6,staging",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,status",
|
||||||
|
f"{sites[0].pk},Site 7,staging",
|
||||||
|
f"{sites[1].pk},Site 8,planned",
|
||||||
|
f"{sites[2].pk},Site 9,active",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'status': SiteStatusChoices.STATUS_PLANNED,
|
'status': SiteStatusChoices.STATUS_PLANNED,
|
||||||
'region': regions[1].pk,
|
'region': regions[1].pk,
|
||||||
'group': groups[1].pk,
|
'group': groups[1].pk,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
'time_zone': pytz.timezone('US/Eastern'),
|
'time_zone': ZoneInfo('US/Eastern'),
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,6 +226,13 @@ class LocationTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Site 1,Tenant 1,Location 6,location-6,planned,Sixth location",
|
"Site 1,Tenant 1,Location 6,location-6,planned,Sixth location",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{locations[0].pk},Location 7,Fourth location7",
|
||||||
|
f"{locations[1].pk},Location 8,Fifth location8",
|
||||||
|
f"{locations[2].pk},Location 0,Sixth location9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
@ -213,11 +244,12 @@ class RackRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
RackRole.objects.bulk_create([
|
rack_roles = (
|
||||||
RackRole(name='Rack Role 1', slug='rack-role-1'),
|
RackRole(name='Rack Role 1', slug='rack-role-1'),
|
||||||
RackRole(name='Rack Role 2', slug='rack-role-2'),
|
RackRole(name='Rack Role 2', slug='rack-role-2'),
|
||||||
RackRole(name='Rack Role 3', slug='rack-role-3'),
|
RackRole(name='Rack Role 3', slug='rack-role-3'),
|
||||||
])
|
)
|
||||||
|
RackRole.objects.bulk_create(rack_roles)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -236,6 +268,13 @@ class RackRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Rack Role 6,rack-role-6,0000ff",
|
"Rack Role 6,rack-role-6,0000ff",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{rack_roles[0].pk},Rack Role 7,New description7",
|
||||||
|
f"{rack_roles[1].pk},Rack Role 8,New description8",
|
||||||
|
f"{rack_roles[2].pk},Rack Role 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'color': '00ff00',
|
'color': '00ff00',
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
@ -259,11 +298,12 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
rack = Rack(name='Rack 1', site=site, location=location)
|
rack = Rack(name='Rack 1', site=site, location=location)
|
||||||
rack.save()
|
rack.save()
|
||||||
|
|
||||||
RackReservation.objects.bulk_create([
|
rack_reservations = (
|
||||||
RackReservation(rack=rack, user=user2, units=[1, 2, 3], description='Reservation 1'),
|
RackReservation(rack=rack, user=user2, units=[1, 2, 3], description='Reservation 1'),
|
||||||
RackReservation(rack=rack, user=user2, units=[4, 5, 6], description='Reservation 2'),
|
RackReservation(rack=rack, user=user2, units=[4, 5, 6], description='Reservation 2'),
|
||||||
RackReservation(rack=rack, user=user2, units=[7, 8, 9], description='Reservation 3'),
|
RackReservation(rack=rack, user=user2, units=[7, 8, 9], description='Reservation 3'),
|
||||||
])
|
)
|
||||||
|
RackReservation.objects.bulk_create(rack_reservations)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -283,6 +323,13 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
'Site 1,Location 1,Rack 1,"16,17,18",Reservation 3',
|
'Site 1,Location 1,Rack 1,"16,17,18",Reservation 3',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
'id,description',
|
||||||
|
f'{rack_reservations[0].pk},New description1',
|
||||||
|
f'{rack_reservations[1].pk},New description2',
|
||||||
|
f'{rack_reservations[2].pk},New description3',
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'user': user3.pk,
|
'user': user3.pk,
|
||||||
'tenant': None,
|
'tenant': None,
|
||||||
@ -315,11 +362,12 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
)
|
)
|
||||||
RackRole.objects.bulk_create(rackroles)
|
RackRole.objects.bulk_create(rackroles)
|
||||||
|
|
||||||
Rack.objects.bulk_create((
|
racks = (
|
||||||
Rack(name='Rack 1', site=sites[0]),
|
Rack(name='Rack 1', site=sites[0]),
|
||||||
Rack(name='Rack 2', site=sites[0]),
|
Rack(name='Rack 2', site=sites[0]),
|
||||||
Rack(name='Rack 3', site=sites[0]),
|
Rack(name='Rack 3', site=sites[0]),
|
||||||
))
|
)
|
||||||
|
Rack.objects.bulk_create(racks)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -351,6 +399,13 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Site 2,Location 2,Rack 6,active,19,42",
|
"Site 2,Location 2,Rack 6,active,19,42",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,status",
|
||||||
|
f"{racks[0].pk},Rack 7,{RackStatusChoices.STATUS_DEPRECATED}",
|
||||||
|
f"{racks[1].pk},Rack 8,{RackStatusChoices.STATUS_DEPRECATED}",
|
||||||
|
f"{racks[2].pk},Rack 9,{RackStatusChoices.STATUS_DEPRECATED}",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'site': sites[1].pk,
|
'site': sites[1].pk,
|
||||||
'location': locations[1].pk,
|
'location': locations[1].pk,
|
||||||
@ -383,11 +438,12 @@ class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
Manufacturer.objects.bulk_create([
|
manufacturers = (
|
||||||
Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
|
Manufacturer(name='Manufacturer 1', slug='manufacturer-1'),
|
||||||
Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
|
Manufacturer(name='Manufacturer 2', slug='manufacturer-2'),
|
||||||
Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
|
Manufacturer(name='Manufacturer 3', slug='manufacturer-3'),
|
||||||
])
|
)
|
||||||
|
Manufacturer.objects.bulk_create(manufacturers)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -405,6 +461,13 @@ class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Manufacturer 6,manufacturer-6,Sixth manufacturer",
|
"Manufacturer 6,manufacturer-6,Sixth manufacturer",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{manufacturers[0].pk},Manufacturer 7,Fourth manufacturer7",
|
||||||
|
f"{manufacturers[1].pk},Manufacturer 8,Fifth manufacturer8",
|
||||||
|
f"{manufacturers[2].pk},Manufacturer 9,Sixth manufacturer9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
}
|
}
|
||||||
@ -1444,11 +1507,12 @@ class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
DeviceRole.objects.bulk_create([
|
device_roles = (
|
||||||
DeviceRole(name='Device Role 1', slug='device-role-1'),
|
DeviceRole(name='Device Role 1', slug='device-role-1'),
|
||||||
DeviceRole(name='Device Role 2', slug='device-role-2'),
|
DeviceRole(name='Device Role 2', slug='device-role-2'),
|
||||||
DeviceRole(name='Device Role 3', slug='device-role-3'),
|
DeviceRole(name='Device Role 3', slug='device-role-3'),
|
||||||
])
|
)
|
||||||
|
DeviceRole.objects.bulk_create(device_roles)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -1468,6 +1532,13 @@ class DeviceRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Device Role 6,device-role-6,0000ff",
|
"Device Role 6,device-role-6,0000ff",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{device_roles[0].pk},Device Role 7,New description7",
|
||||||
|
f"{device_roles[1].pk},Device Role 8,New description8",
|
||||||
|
f"{device_roles[2].pk},Device Role 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'color': '00ff00',
|
'color': '00ff00',
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
@ -1482,11 +1553,12 @@ class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
|
|
||||||
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
|
manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
|
||||||
|
|
||||||
Platform.objects.bulk_create([
|
platforms = (
|
||||||
Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturer),
|
Platform(name='Platform 1', slug='platform-1', manufacturer=manufacturer),
|
||||||
Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturer),
|
Platform(name='Platform 2', slug='platform-2', manufacturer=manufacturer),
|
||||||
Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturer),
|
Platform(name='Platform 3', slug='platform-3', manufacturer=manufacturer),
|
||||||
])
|
)
|
||||||
|
Platform.objects.bulk_create(platforms)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -1507,6 +1579,13 @@ class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Platform 6,platform-6,Sixth platform",
|
"Platform 6,platform-6,Sixth platform",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{platforms[0].pk},Platform 7,Fourth platform7",
|
||||||
|
f"{platforms[1].pk},Platform 8,Fifth platform8",
|
||||||
|
f"{platforms[2].pk},Platform 9,Sixth platform9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'napalm_driver': 'ios',
|
'napalm_driver': 'ios',
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
@ -1554,11 +1633,12 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
)
|
)
|
||||||
Platform.objects.bulk_create(platforms)
|
Platform.objects.bulk_create(platforms)
|
||||||
|
|
||||||
Device.objects.bulk_create([
|
devices = (
|
||||||
Device(name='Device 1', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
|
Device(name='Device 1', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
|
||||||
Device(name='Device 2', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
|
Device(name='Device 2', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
|
||||||
Device(name='Device 3', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
|
Device(name='Device 3', site=sites[0], rack=racks[0], device_type=devicetypes[0], device_role=deviceroles[0], platform=platforms[0]),
|
||||||
])
|
)
|
||||||
|
Device.objects.bulk_create(devices)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -1595,6 +1675,13 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Device Role 1,Manufacturer 1,Device Type 1,active,Device 6,Site 1,Location 1,Rack 1,30,front,Virtual Chassis 1,3,30",
|
"Device Role 1,Manufacturer 1,Device Type 1,active,Device 6,Site 1,Location 1,Rack 1,30,front,Virtual Chassis 1,3,30",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,status",
|
||||||
|
f"{devices[0].pk},{DeviceStatusChoices.STATUS_DECOMMISSIONING}",
|
||||||
|
f"{devices[1].pk},{DeviceStatusChoices.STATUS_DECOMMISSIONING}",
|
||||||
|
f"{devices[2].pk},{DeviceStatusChoices.STATUS_DECOMMISSIONING}",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'device_type': devicetypes[1].pk,
|
'device_type': devicetypes[1].pk,
|
||||||
'device_role': deviceroles[1].pk,
|
'device_role': deviceroles[1].pk,
|
||||||
@ -1778,10 +1865,12 @@ class ModuleTestCase(
|
|||||||
ModuleBay(device=devices[0], name='Module Bay 2'),
|
ModuleBay(device=devices[0], name='Module Bay 2'),
|
||||||
ModuleBay(device=devices[0], name='Module Bay 3'),
|
ModuleBay(device=devices[0], name='Module Bay 3'),
|
||||||
ModuleBay(device=devices[0], name='Module Bay 4'),
|
ModuleBay(device=devices[0], name='Module Bay 4'),
|
||||||
|
ModuleBay(device=devices[0], name='Module Bay 5'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 1'),
|
ModuleBay(device=devices[1], name='Module Bay 1'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 2'),
|
ModuleBay(device=devices[1], name='Module Bay 2'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 3'),
|
ModuleBay(device=devices[1], name='Module Bay 3'),
|
||||||
ModuleBay(device=devices[1], name='Module Bay 4'),
|
ModuleBay(device=devices[1], name='Module Bay 4'),
|
||||||
|
ModuleBay(device=devices[1], name='Module Bay 5'),
|
||||||
)
|
)
|
||||||
ModuleBay.objects.bulk_create(module_bays)
|
ModuleBay.objects.bulk_create(module_bays)
|
||||||
|
|
||||||
@ -1795,7 +1884,7 @@ class ModuleTestCase(
|
|||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
cls.form_data = {
|
cls.form_data = {
|
||||||
'device': devices[1].pk,
|
'device': devices[0].pk,
|
||||||
'module_bay': module_bays[3].pk,
|
'module_bay': module_bays[3].pk,
|
||||||
'module_type': module_types[0].pk,
|
'module_type': module_types[0].pk,
|
||||||
'serial': 'A',
|
'serial': 'A',
|
||||||
@ -1813,6 +1902,13 @@ class ModuleTestCase(
|
|||||||
"Device 2,Module Bay 3,Module Type 3,C,C",
|
"Device 2,Module Bay 3,Module Type 3,C,C",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,serial",
|
||||||
|
f"{modules[0].pk},Serial 2",
|
||||||
|
f"{modules[1].pk},Serial 3",
|
||||||
|
f"{modules[2].pk},Serial 1",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_module_component_replication(self):
|
def test_module_component_replication(self):
|
||||||
self.add_permissions('dcim.add_module')
|
self.add_permissions('dcim.add_module')
|
||||||
@ -1867,7 +1963,6 @@ class ModuleTestCase(
|
|||||||
self.assertIsNone(interface.module)
|
self.assertIsNone(interface.module)
|
||||||
|
|
||||||
# Create a module with adopted components
|
# Create a module with adopted components
|
||||||
form_data['module_bay'] = ModuleBay.objects.filter(device=device).first()
|
|
||||||
form_data['module_type'] = module_type
|
form_data['module_type'] = module_type
|
||||||
form_data['replicate_components'] = False
|
form_data['replicate_components'] = False
|
||||||
form_data['adopt_components'] = True
|
form_data['adopt_components'] = True
|
||||||
@ -1893,11 +1988,12 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
device = create_test_device('Device 1')
|
device = create_test_device('Device 1')
|
||||||
|
|
||||||
ConsolePort.objects.bulk_create([
|
console_ports = (
|
||||||
ConsolePort(device=device, name='Console Port 1'),
|
ConsolePort(device=device, name='Console Port 1'),
|
||||||
ConsolePort(device=device, name='Console Port 2'),
|
ConsolePort(device=device, name='Console Port 2'),
|
||||||
ConsolePort(device=device, name='Console Port 3'),
|
ConsolePort(device=device, name='Console Port 3'),
|
||||||
])
|
)
|
||||||
|
ConsolePort.objects.bulk_create(console_ports)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -1931,6 +2027,13 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Console Port 6",
|
"Device 1,Console Port 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{console_ports[0].pk},Console Port 7,New description7",
|
||||||
|
f"{console_ports[1].pk},Console Port 8,New description8",
|
||||||
|
f"{console_ports[2].pk},Console Port 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
consoleport = ConsolePort.objects.first()
|
consoleport = ConsolePort.objects.first()
|
||||||
@ -1952,11 +2055,12 @@ class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
device = create_test_device('Device 1')
|
device = create_test_device('Device 1')
|
||||||
|
|
||||||
ConsoleServerPort.objects.bulk_create([
|
console_server_ports = (
|
||||||
ConsoleServerPort(device=device, name='Console Server Port 1'),
|
ConsoleServerPort(device=device, name='Console Server Port 1'),
|
||||||
ConsoleServerPort(device=device, name='Console Server Port 2'),
|
ConsoleServerPort(device=device, name='Console Server Port 2'),
|
||||||
ConsoleServerPort(device=device, name='Console Server Port 3'),
|
ConsoleServerPort(device=device, name='Console Server Port 3'),
|
||||||
])
|
)
|
||||||
|
ConsoleServerPort.objects.bulk_create(console_server_ports)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -1988,6 +2092,13 @@ class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Console Server Port 6",
|
"Device 1,Console Server Port 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{console_server_ports[0].pk},Console Server Port 7,New description 7",
|
||||||
|
f"{console_server_ports[1].pk},Console Server Port 8,New description 8",
|
||||||
|
f"{console_server_ports[2].pk},Console Server Port 9,New description 9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
consoleserverport = ConsoleServerPort.objects.first()
|
consoleserverport = ConsoleServerPort.objects.first()
|
||||||
@ -2009,11 +2120,12 @@ class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
device = create_test_device('Device 1')
|
device = create_test_device('Device 1')
|
||||||
|
|
||||||
PowerPort.objects.bulk_create([
|
power_ports = (
|
||||||
PowerPort(device=device, name='Power Port 1'),
|
PowerPort(device=device, name='Power Port 1'),
|
||||||
PowerPort(device=device, name='Power Port 2'),
|
PowerPort(device=device, name='Power Port 2'),
|
||||||
PowerPort(device=device, name='Power Port 3'),
|
PowerPort(device=device, name='Power Port 3'),
|
||||||
])
|
)
|
||||||
|
PowerPort.objects.bulk_create(power_ports)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2051,6 +2163,13 @@ class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Power Port 6",
|
"Device 1,Power Port 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{power_ports[0].pk},Power Port 7,New description7",
|
||||||
|
f"{power_ports[1].pk},Power Port 8,New description8",
|
||||||
|
f"{power_ports[2].pk},Power Port 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
powerport = PowerPort.objects.first()
|
powerport = PowerPort.objects.first()
|
||||||
@ -2078,11 +2197,12 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
)
|
)
|
||||||
PowerPort.objects.bulk_create(powerports)
|
PowerPort.objects.bulk_create(powerports)
|
||||||
|
|
||||||
PowerOutlet.objects.bulk_create([
|
power_outlets = (
|
||||||
PowerOutlet(device=device, name='Power Outlet 1', power_port=powerports[0]),
|
PowerOutlet(device=device, name='Power Outlet 1', power_port=powerports[0]),
|
||||||
PowerOutlet(device=device, name='Power Outlet 2', power_port=powerports[0]),
|
PowerOutlet(device=device, name='Power Outlet 2', power_port=powerports[0]),
|
||||||
PowerOutlet(device=device, name='Power Outlet 3', power_port=powerports[0]),
|
PowerOutlet(device=device, name='Power Outlet 3', power_port=powerports[0]),
|
||||||
])
|
)
|
||||||
|
PowerOutlet.objects.bulk_create(power_outlets)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2120,6 +2240,13 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Power Outlet 6",
|
"Device 1,Power Outlet 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{power_outlets[0].pk},Power Outlet 7,New description7",
|
||||||
|
f"{power_outlets[1].pk},Power Outlet 8,New description8",
|
||||||
|
f"{power_outlets[2].pk},Power Outlet 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
poweroutlet = PowerOutlet.objects.first()
|
poweroutlet = PowerOutlet.objects.first()
|
||||||
@ -2246,6 +2373,13 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
f"Device 1,Interface 6,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af",
|
f"Device 1,Interface 6,1000base-t,{vrfs[0].pk},pse,type1-ieee802.3af",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{interfaces[0].pk},Interface 7,New description7",
|
||||||
|
f"{interfaces[1].pk},Interface 8,New description8",
|
||||||
|
f"{interfaces[2].pk},Interface 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
interface1, interface2 = Interface.objects.all()[:2]
|
interface1, interface2 = Interface.objects.all()[:2]
|
||||||
@ -2273,11 +2407,12 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
)
|
)
|
||||||
RearPort.objects.bulk_create(rearports)
|
RearPort.objects.bulk_create(rearports)
|
||||||
|
|
||||||
FrontPort.objects.bulk_create([
|
front_ports = (
|
||||||
FrontPort(device=device, name='Front Port 1', rear_port=rearports[0]),
|
FrontPort(device=device, name='Front Port 1', rear_port=rearports[0]),
|
||||||
FrontPort(device=device, name='Front Port 2', rear_port=rearports[1]),
|
FrontPort(device=device, name='Front Port 2', rear_port=rearports[1]),
|
||||||
FrontPort(device=device, name='Front Port 3', rear_port=rearports[2]),
|
FrontPort(device=device, name='Front Port 3', rear_port=rearports[2]),
|
||||||
])
|
)
|
||||||
|
FrontPort.objects.bulk_create(front_ports)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2312,6 +2447,13 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Front Port 6,8p8c,Rear Port 6,1",
|
"Device 1,Front Port 6,8p8c,Rear Port 6,1",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{front_ports[0].pk},Front Port 7,New description7",
|
||||||
|
f"{front_ports[1].pk},Front Port 8,New description8",
|
||||||
|
f"{front_ports[2].pk},Front Port 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
frontport = FrontPort.objects.first()
|
frontport = FrontPort.objects.first()
|
||||||
@ -2333,11 +2475,12 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
device = create_test_device('Device 1')
|
device = create_test_device('Device 1')
|
||||||
|
|
||||||
RearPort.objects.bulk_create([
|
rear_ports = (
|
||||||
RearPort(device=device, name='Rear Port 1'),
|
RearPort(device=device, name='Rear Port 1'),
|
||||||
RearPort(device=device, name='Rear Port 2'),
|
RearPort(device=device, name='Rear Port 2'),
|
||||||
RearPort(device=device, name='Rear Port 3'),
|
RearPort(device=device, name='Rear Port 3'),
|
||||||
])
|
)
|
||||||
|
RearPort.objects.bulk_create(rear_ports)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2371,6 +2514,13 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Rear Port 6,8p8c,1",
|
"Device 1,Rear Port 6,8p8c,1",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{rear_ports[0].pk},Rear Port 7,New description7",
|
||||||
|
f"{rear_ports[1].pk},Rear Port 8,New description8",
|
||||||
|
f"{rear_ports[2].pk},Rear Port 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=['*'])
|
||||||
def test_trace(self):
|
def test_trace(self):
|
||||||
rearport = RearPort.objects.first()
|
rearport = RearPort.objects.first()
|
||||||
@ -2392,11 +2542,12 @@ class ModuleBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
device = create_test_device('Device 1')
|
device = create_test_device('Device 1')
|
||||||
|
|
||||||
ModuleBay.objects.bulk_create([
|
module_bays = (
|
||||||
ModuleBay(device=device, name='Module Bay 1'),
|
ModuleBay(device=device, name='Module Bay 1'),
|
||||||
ModuleBay(device=device, name='Module Bay 2'),
|
ModuleBay(device=device, name='Module Bay 2'),
|
||||||
ModuleBay(device=device, name='Module Bay 3'),
|
ModuleBay(device=device, name='Module Bay 3'),
|
||||||
])
|
)
|
||||||
|
ModuleBay.objects.bulk_create(module_bays)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2425,6 +2576,13 @@ class ModuleBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Module Bay 6",
|
"Device 1,Module Bay 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{module_bays[0].pk},Module Bay 7,New description7",
|
||||||
|
f"{module_bays[1].pk},Module Bay 8,New description8",
|
||||||
|
f"{module_bays[2].pk},Module Bay 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
||||||
model = DeviceBay
|
model = DeviceBay
|
||||||
@ -2437,11 +2595,12 @@ class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
# Update the DeviceType subdevice role to allow adding DeviceBays
|
# Update the DeviceType subdevice role to allow adding DeviceBays
|
||||||
DeviceType.objects.update(subdevice_role=SubdeviceRoleChoices.ROLE_PARENT)
|
DeviceType.objects.update(subdevice_role=SubdeviceRoleChoices.ROLE_PARENT)
|
||||||
|
|
||||||
DeviceBay.objects.bulk_create([
|
device_bays = (
|
||||||
DeviceBay(device=device, name='Device Bay 1'),
|
DeviceBay(device=device, name='Device Bay 1'),
|
||||||
DeviceBay(device=device, name='Device Bay 2'),
|
DeviceBay(device=device, name='Device Bay 2'),
|
||||||
DeviceBay(device=device, name='Device Bay 3'),
|
DeviceBay(device=device, name='Device Bay 3'),
|
||||||
])
|
)
|
||||||
|
DeviceBay.objects.bulk_create(device_bays)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2470,6 +2629,13 @@ class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Device Bay 6",
|
"Device 1,Device Bay 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{device_bays[0].pk},Device Bay 7,New description7",
|
||||||
|
f"{device_bays[1].pk},Device Bay 8,New description8",
|
||||||
|
f"{device_bays[2].pk},Device Bay 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
@ -2486,9 +2652,9 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
)
|
)
|
||||||
InventoryItemRole.objects.bulk_create(roles)
|
InventoryItemRole.objects.bulk_create(roles)
|
||||||
|
|
||||||
InventoryItem.objects.create(device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer)
|
inventory_item1 = InventoryItem.objects.create(device=device, name='Inventory Item 1', role=roles[0], manufacturer=manufacturer)
|
||||||
InventoryItem.objects.create(device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer)
|
inventory_item2 = InventoryItem.objects.create(device=device, name='Inventory Item 2', role=roles[0], manufacturer=manufacturer)
|
||||||
InventoryItem.objects.create(device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer)
|
inventory_item3 = InventoryItem.objects.create(device=device, name='Inventory Item 3', role=roles[0], manufacturer=manufacturer)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2532,6 +2698,13 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
|
|||||||
"Device 1,Inventory Item 6,Inventory Item 3",
|
"Device 1,Inventory Item 6,Inventory Item 3",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{inventory_item1.pk},Inventory Item 7,New description7",
|
||||||
|
f"{inventory_item2.pk},Inventory Item 8,New description8",
|
||||||
|
f"{inventory_item3.pk},Inventory Item 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
class InventoryItemRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
||||||
model = InventoryItemRole
|
model = InventoryItemRole
|
||||||
@ -2539,11 +2712,12 @@ class InventoryItemRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
InventoryItemRole.objects.bulk_create([
|
inventory_item_roles = (
|
||||||
InventoryItemRole(name='Inventory Item Role 1', slug='inventory-item-role-1'),
|
InventoryItemRole(name='Inventory Item Role 1', slug='inventory-item-role-1'),
|
||||||
InventoryItemRole(name='Inventory Item Role 2', slug='inventory-item-role-2'),
|
InventoryItemRole(name='Inventory Item Role 2', slug='inventory-item-role-2'),
|
||||||
InventoryItemRole(name='Inventory Item Role 3', slug='inventory-item-role-3'),
|
InventoryItemRole(name='Inventory Item Role 3', slug='inventory-item-role-3'),
|
||||||
])
|
)
|
||||||
|
InventoryItemRole.objects.bulk_create(inventory_item_roles)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2562,6 +2736,13 @@ class InventoryItemRoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
|
|||||||
"Inventory Item Role 6,inventory-item-role-6,0000ff",
|
"Inventory Item Role 6,inventory-item-role-6,0000ff",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,description",
|
||||||
|
f"{inventory_item_roles[0].pk},Inventory Item Role 7,New description7",
|
||||||
|
f"{inventory_item_roles[1].pk},Inventory Item Role 8,New description8",
|
||||||
|
f"{inventory_item_roles[2].pk},Inventory Item Role 9,New description9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'color': '00ff00',
|
'color': '00ff00',
|
||||||
'description': 'New description',
|
'description': 'New description',
|
||||||
@ -2614,9 +2795,12 @@ class CableTestCase(
|
|||||||
)
|
)
|
||||||
Interface.objects.bulk_create(interfaces)
|
Interface.objects.bulk_create(interfaces)
|
||||||
|
|
||||||
Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[3]], type=CableTypeChoices.TYPE_CAT6).save()
|
cable1 = Cable(a_terminations=[interfaces[0]], b_terminations=[interfaces[3]], type=CableTypeChoices.TYPE_CAT6)
|
||||||
Cable(a_terminations=[interfaces[1]], b_terminations=[interfaces[4]], type=CableTypeChoices.TYPE_CAT6).save()
|
cable1.save()
|
||||||
Cable(a_terminations=[interfaces[2]], b_terminations=[interfaces[5]], type=CableTypeChoices.TYPE_CAT6).save()
|
cable2 = Cable(a_terminations=[interfaces[1]], b_terminations=[interfaces[4]], type=CableTypeChoices.TYPE_CAT6)
|
||||||
|
cable2.save()
|
||||||
|
cable3 = Cable(a_terminations=[interfaces[2]], b_terminations=[interfaces[5]], type=CableTypeChoices.TYPE_CAT6)
|
||||||
|
cable3.save()
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2642,6 +2826,13 @@ class CableTestCase(
|
|||||||
"Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3",
|
"Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,label,color",
|
||||||
|
f"{cable1.pk},New label7,00ff00",
|
||||||
|
f"{cable2.pk},New label8,00ff00",
|
||||||
|
f"{cable3.pk},New label9,00ff00",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'type': CableTypeChoices.TYPE_CAT5E,
|
'type': CableTypeChoices.TYPE_CAT5E,
|
||||||
'status': LinkStatusChoices.STATUS_CONNECTED,
|
'status': LinkStatusChoices.STATUS_CONNECTED,
|
||||||
@ -2725,6 +2916,13 @@ class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"VC6,Domain 6,Device 12",
|
"VC6,Domain 6,Device 12",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,domain",
|
||||||
|
f"{vc1.pk},VC7,Domain 7",
|
||||||
|
f"{vc2.pk},VC8,Domain 8",
|
||||||
|
f"{vc3.pk},VC9,Domain 9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'domain': 'domain-x',
|
'domain': 'domain-x',
|
||||||
}
|
}
|
||||||
@ -2749,11 +2947,12 @@ class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
for location in locations:
|
for location in locations:
|
||||||
location.save()
|
location.save()
|
||||||
|
|
||||||
PowerPanel.objects.bulk_create((
|
power_panels = (
|
||||||
PowerPanel(site=sites[0], location=locations[0], name='Power Panel 1'),
|
PowerPanel(site=sites[0], location=locations[0], name='Power Panel 1'),
|
||||||
PowerPanel(site=sites[0], location=locations[0], name='Power Panel 2'),
|
PowerPanel(site=sites[0], location=locations[0], name='Power Panel 2'),
|
||||||
PowerPanel(site=sites[0], location=locations[0], name='Power Panel 3'),
|
PowerPanel(site=sites[0], location=locations[0], name='Power Panel 3'),
|
||||||
))
|
)
|
||||||
|
PowerPanel.objects.bulk_create(power_panels)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2771,6 +2970,13 @@ class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Site 1,Location 1,Power Panel 6",
|
"Site 1,Location 1,Power Panel 6",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name",
|
||||||
|
f"{power_panels[0].pk},Power Panel 7",
|
||||||
|
f"{power_panels[1].pk},Power Panel 8",
|
||||||
|
f"{power_panels[2].pk},Power Panel 9",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'site': sites[1].pk,
|
'site': sites[1].pk,
|
||||||
'location': locations[1].pk,
|
'location': locations[1].pk,
|
||||||
@ -2797,11 +3003,12 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
)
|
)
|
||||||
Rack.objects.bulk_create(racks)
|
Rack.objects.bulk_create(racks)
|
||||||
|
|
||||||
PowerFeed.objects.bulk_create((
|
power_feeds = (
|
||||||
PowerFeed(name='Power Feed 1', power_panel=powerpanels[0], rack=racks[0]),
|
PowerFeed(name='Power Feed 1', power_panel=powerpanels[0], rack=racks[0]),
|
||||||
PowerFeed(name='Power Feed 2', power_panel=powerpanels[0], rack=racks[0]),
|
PowerFeed(name='Power Feed 2', power_panel=powerpanels[0], rack=racks[0]),
|
||||||
PowerFeed(name='Power Feed 3', power_panel=powerpanels[0], rack=racks[0]),
|
PowerFeed(name='Power Feed 3', power_panel=powerpanels[0], rack=racks[0]),
|
||||||
))
|
)
|
||||||
|
PowerFeed.objects.bulk_create(power_feeds)
|
||||||
|
|
||||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||||
|
|
||||||
@ -2827,6 +3034,13 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|||||||
"Site 1,Power Panel 1,Power Feed 6,active,primary,ac,single-phase,120,20,80",
|
"Site 1,Power Panel 1,Power Feed 6,active,primary,ac,single-phase,120,20,80",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cls.csv_update_data = (
|
||||||
|
"id,name,status",
|
||||||
|
f"{power_feeds[0].pk},Power Feed 7,{PowerFeedStatusChoices.STATUS_PLANNED}",
|
||||||
|
f"{power_feeds[1].pk},Power Feed 8,{PowerFeedStatusChoices.STATUS_PLANNED}",
|
||||||
|
f"{power_feeds[2].pk},Power Feed 9,{PowerFeedStatusChoices.STATUS_PLANNED}",
|
||||||
|
)
|
||||||
|
|
||||||
cls.bulk_edit_data = {
|
cls.bulk_edit_data = {
|
||||||
'power_panel': powerpanels[1].pk,
|
'power_panel': powerpanels[1].pk,
|
||||||
'rack': racks[1].pk,
|
'rack': racks[1].pk,
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
from django.urls import path
|
from django.urls import include, path
|
||||||
|
|
||||||
from netbox.views.generic import ObjectChangeLogView, ObjectJournalView
|
from utilities.urls import get_model_urls
|
||||||
from . import views
|
from . import views
|
||||||
from .models import *
|
|
||||||
|
|
||||||
app_name = 'dcim'
|
app_name = 'dcim'
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -13,10 +12,7 @@ urlpatterns = [
|
|||||||
path('regions/import/', views.RegionBulkImportView.as_view(), name='region_import'),
|
path('regions/import/', views.RegionBulkImportView.as_view(), name='region_import'),
|
||||||
path('regions/edit/', views.RegionBulkEditView.as_view(), name='region_bulk_edit'),
|
path('regions/edit/', views.RegionBulkEditView.as_view(), name='region_bulk_edit'),
|
||||||
path('regions/delete/', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
|
path('regions/delete/', views.RegionBulkDeleteView.as_view(), name='region_bulk_delete'),
|
||||||
path('regions/<int:pk>/', views.RegionView.as_view(), name='region'),
|
path('regions/<int:pk>/', include(get_model_urls('dcim', 'region'))),
|
||||||
path('regions/<int:pk>/edit/', views.RegionEditView.as_view(), name='region_edit'),
|
|
||||||
path('regions/<int:pk>/delete/', views.RegionDeleteView.as_view(), name='region_delete'),
|
|
||||||
path('regions/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='region_changelog', kwargs={'model': Region}),
|
|
||||||
|
|
||||||
# Site groups
|
# Site groups
|
||||||
path('site-groups/', views.SiteGroupListView.as_view(), name='sitegroup_list'),
|
path('site-groups/', views.SiteGroupListView.as_view(), name='sitegroup_list'),
|
||||||
@ -24,10 +20,7 @@ urlpatterns = [
|
|||||||
path('site-groups/import/', views.SiteGroupBulkImportView.as_view(), name='sitegroup_import'),
|
path('site-groups/import/', views.SiteGroupBulkImportView.as_view(), name='sitegroup_import'),
|
||||||
path('site-groups/edit/', views.SiteGroupBulkEditView.as_view(), name='sitegroup_bulk_edit'),
|
path('site-groups/edit/', views.SiteGroupBulkEditView.as_view(), name='sitegroup_bulk_edit'),
|
||||||
path('site-groups/delete/', views.SiteGroupBulkDeleteView.as_view(), name='sitegroup_bulk_delete'),
|
path('site-groups/delete/', views.SiteGroupBulkDeleteView.as_view(), name='sitegroup_bulk_delete'),
|
||||||
path('site-groups/<int:pk>/', views.SiteGroupView.as_view(), name='sitegroup'),
|
path('site-groups/<int:pk>/', include(get_model_urls('dcim', 'sitegroup'))),
|
||||||
path('site-groups/<int:pk>/edit/', views.SiteGroupEditView.as_view(), name='sitegroup_edit'),
|
|
||||||
path('site-groups/<int:pk>/delete/', views.SiteGroupDeleteView.as_view(), name='sitegroup_delete'),
|
|
||||||
path('site-groups/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='sitegroup_changelog', kwargs={'model': SiteGroup}),
|
|
||||||
|
|
||||||
# Sites
|
# Sites
|
||||||
path('sites/', views.SiteListView.as_view(), name='site_list'),
|
path('sites/', views.SiteListView.as_view(), name='site_list'),
|
||||||
@ -35,11 +28,7 @@ urlpatterns = [
|
|||||||
path('sites/import/', views.SiteBulkImportView.as_view(), name='site_import'),
|
path('sites/import/', views.SiteBulkImportView.as_view(), name='site_import'),
|
||||||
path('sites/edit/', views.SiteBulkEditView.as_view(), name='site_bulk_edit'),
|
path('sites/edit/', views.SiteBulkEditView.as_view(), name='site_bulk_edit'),
|
||||||
path('sites/delete/', views.SiteBulkDeleteView.as_view(), name='site_bulk_delete'),
|
path('sites/delete/', views.SiteBulkDeleteView.as_view(), name='site_bulk_delete'),
|
||||||
path('sites/<int:pk>/', views.SiteView.as_view(), name='site'),
|
path('sites/<int:pk>/', include(get_model_urls('dcim', 'site'))),
|
||||||
path('sites/<int:pk>/edit/', views.SiteEditView.as_view(), name='site_edit'),
|
|
||||||
path('sites/<int:pk>/delete/', views.SiteDeleteView.as_view(), name='site_delete'),
|
|
||||||
path('sites/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='site_changelog', kwargs={'model': Site}),
|
|
||||||
path('sites/<int:pk>/journal/', ObjectJournalView.as_view(), name='site_journal', kwargs={'model': Site}),
|
|
||||||
|
|
||||||
# Locations
|
# Locations
|
||||||
path('locations/', views.LocationListView.as_view(), name='location_list'),
|
path('locations/', views.LocationListView.as_view(), name='location_list'),
|
||||||
@ -47,10 +36,7 @@ urlpatterns = [
|
|||||||
path('locations/import/', views.LocationBulkImportView.as_view(), name='location_import'),
|
path('locations/import/', views.LocationBulkImportView.as_view(), name='location_import'),
|
||||||
path('locations/edit/', views.LocationBulkEditView.as_view(), name='location_bulk_edit'),
|
path('locations/edit/', views.LocationBulkEditView.as_view(), name='location_bulk_edit'),
|
||||||
path('locations/delete/', views.LocationBulkDeleteView.as_view(), name='location_bulk_delete'),
|
path('locations/delete/', views.LocationBulkDeleteView.as_view(), name='location_bulk_delete'),
|
||||||
path('locations/<int:pk>/', views.LocationView.as_view(), name='location'),
|
path('locations/<int:pk>/', include(get_model_urls('dcim', 'location'))),
|
||||||
path('locations/<int:pk>/edit/', views.LocationEditView.as_view(), name='location_edit'),
|
|
||||||
path('locations/<int:pk>/delete/', views.LocationDeleteView.as_view(), name='location_delete'),
|
|
||||||
path('locations/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='location_changelog', kwargs={'model': Location}),
|
|
||||||
|
|
||||||
# Rack roles
|
# Rack roles
|
||||||
path('rack-roles/', views.RackRoleListView.as_view(), name='rackrole_list'),
|
path('rack-roles/', views.RackRoleListView.as_view(), name='rackrole_list'),
|
||||||
@ -58,10 +44,7 @@ urlpatterns = [
|
|||||||
path('rack-roles/import/', views.RackRoleBulkImportView.as_view(), name='rackrole_import'),
|
path('rack-roles/import/', views.RackRoleBulkImportView.as_view(), name='rackrole_import'),
|
||||||
path('rack-roles/edit/', views.RackRoleBulkEditView.as_view(), name='rackrole_bulk_edit'),
|
path('rack-roles/edit/', views.RackRoleBulkEditView.as_view(), name='rackrole_bulk_edit'),
|
||||||
path('rack-roles/delete/', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
|
path('rack-roles/delete/', views.RackRoleBulkDeleteView.as_view(), name='rackrole_bulk_delete'),
|
||||||
path('rack-roles/<int:pk>/', views.RackRoleView.as_view(), name='rackrole'),
|
path('rack-roles/<int:pk>/', include(get_model_urls('dcim', 'rackrole'))),
|
||||||
path('rack-roles/<int:pk>/edit/', views.RackRoleEditView.as_view(), name='rackrole_edit'),
|
|
||||||
path('rack-roles/<int:pk>/delete/', views.RackRoleDeleteView.as_view(), name='rackrole_delete'),
|
|
||||||
path('rack-roles/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rackrole_changelog', kwargs={'model': RackRole}),
|
|
||||||
|
|
||||||
# Rack reservations
|
# Rack reservations
|
||||||
path('rack-reservations/', views.RackReservationListView.as_view(), name='rackreservation_list'),
|
path('rack-reservations/', views.RackReservationListView.as_view(), name='rackreservation_list'),
|
||||||
@ -69,11 +52,7 @@ urlpatterns = [
|
|||||||
path('rack-reservations/import/', views.RackReservationImportView.as_view(), name='rackreservation_import'),
|
path('rack-reservations/import/', views.RackReservationImportView.as_view(), name='rackreservation_import'),
|
||||||
path('rack-reservations/edit/', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'),
|
path('rack-reservations/edit/', views.RackReservationBulkEditView.as_view(), name='rackreservation_bulk_edit'),
|
||||||
path('rack-reservations/delete/', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'),
|
path('rack-reservations/delete/', views.RackReservationBulkDeleteView.as_view(), name='rackreservation_bulk_delete'),
|
||||||
path('rack-reservations/<int:pk>/', views.RackReservationView.as_view(), name='rackreservation'),
|
path('rack-reservations/<int:pk>/', include(get_model_urls('dcim', 'rackreservation'))),
|
||||||
path('rack-reservations/<int:pk>/edit/', views.RackReservationEditView.as_view(), name='rackreservation_edit'),
|
|
||||||
path('rack-reservations/<int:pk>/delete/', views.RackReservationDeleteView.as_view(), name='rackreservation_delete'),
|
|
||||||
path('rack-reservations/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rackreservation_changelog', kwargs={'model': RackReservation}),
|
|
||||||
path('rack-reservations/<int:pk>/journal/', ObjectJournalView.as_view(), name='rackreservation_journal', kwargs={'model': RackReservation}),
|
|
||||||
|
|
||||||
# Racks
|
# Racks
|
||||||
path('racks/', views.RackListView.as_view(), name='rack_list'),
|
path('racks/', views.RackListView.as_view(), name='rack_list'),
|
||||||
@ -82,11 +61,7 @@ urlpatterns = [
|
|||||||
path('racks/import/', views.RackBulkImportView.as_view(), name='rack_import'),
|
path('racks/import/', views.RackBulkImportView.as_view(), name='rack_import'),
|
||||||
path('racks/edit/', views.RackBulkEditView.as_view(), name='rack_bulk_edit'),
|
path('racks/edit/', views.RackBulkEditView.as_view(), name='rack_bulk_edit'),
|
||||||
path('racks/delete/', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'),
|
path('racks/delete/', views.RackBulkDeleteView.as_view(), name='rack_bulk_delete'),
|
||||||
path('racks/<int:pk>/', views.RackView.as_view(), name='rack'),
|
path('racks/<int:pk>/', include(get_model_urls('dcim', 'rack'))),
|
||||||
path('racks/<int:pk>/edit/', views.RackEditView.as_view(), name='rack_edit'),
|
|
||||||
path('racks/<int:pk>/delete/', views.RackDeleteView.as_view(), name='rack_delete'),
|
|
||||||
path('racks/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rack_changelog', kwargs={'model': Rack}),
|
|
||||||
path('racks/<int:pk>/journal/', ObjectJournalView.as_view(), name='rack_journal', kwargs={'model': Rack}),
|
|
||||||
|
|
||||||
# Manufacturers
|
# Manufacturers
|
||||||
path('manufacturers/', views.ManufacturerListView.as_view(), name='manufacturer_list'),
|
path('manufacturers/', views.ManufacturerListView.as_view(), name='manufacturer_list'),
|
||||||
@ -94,10 +69,7 @@ urlpatterns = [
|
|||||||
path('manufacturers/import/', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'),
|
path('manufacturers/import/', views.ManufacturerBulkImportView.as_view(), name='manufacturer_import'),
|
||||||
path('manufacturers/edit/', views.ManufacturerBulkEditView.as_view(), name='manufacturer_bulk_edit'),
|
path('manufacturers/edit/', views.ManufacturerBulkEditView.as_view(), name='manufacturer_bulk_edit'),
|
||||||
path('manufacturers/delete/', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
|
path('manufacturers/delete/', views.ManufacturerBulkDeleteView.as_view(), name='manufacturer_bulk_delete'),
|
||||||
path('manufacturers/<int:pk>/', views.ManufacturerView.as_view(), name='manufacturer'),
|
path('manufacturers/<int:pk>/', include(get_model_urls('dcim', 'manufacturer'))),
|
||||||
path('manufacturers/<int:pk>/edit/', views.ManufacturerEditView.as_view(), name='manufacturer_edit'),
|
|
||||||
path('manufacturers/<int:pk>/delete/', views.ManufacturerDeleteView.as_view(), name='manufacturer_delete'),
|
|
||||||
path('manufacturers/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='manufacturer_changelog', kwargs={'model': Manufacturer}),
|
|
||||||
|
|
||||||
# Device types
|
# Device types
|
||||||
path('device-types/', views.DeviceTypeListView.as_view(), name='devicetype_list'),
|
path('device-types/', views.DeviceTypeListView.as_view(), name='devicetype_list'),
|
||||||
@ -105,21 +77,7 @@ urlpatterns = [
|
|||||||
path('device-types/import/', views.DeviceTypeImportView.as_view(), name='devicetype_import'),
|
path('device-types/import/', views.DeviceTypeImportView.as_view(), name='devicetype_import'),
|
||||||
path('device-types/edit/', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'),
|
path('device-types/edit/', views.DeviceTypeBulkEditView.as_view(), name='devicetype_bulk_edit'),
|
||||||
path('device-types/delete/', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'),
|
path('device-types/delete/', views.DeviceTypeBulkDeleteView.as_view(), name='devicetype_bulk_delete'),
|
||||||
path('device-types/<int:pk>/', views.DeviceTypeView.as_view(), name='devicetype'),
|
path('device-types/<int:pk>/', include(get_model_urls('dcim', 'devicetype'))),
|
||||||
path('device-types/<int:pk>/console-ports/', views.DeviceTypeConsolePortsView.as_view(), name='devicetype_consoleports'),
|
|
||||||
path('device-types/<int:pk>/console-server-ports/', views.DeviceTypeConsoleServerPortsView.as_view(), name='devicetype_consoleserverports'),
|
|
||||||
path('device-types/<int:pk>/power-ports/', views.DeviceTypePowerPortsView.as_view(), name='devicetype_powerports'),
|
|
||||||
path('device-types/<int:pk>/power-outlets/', views.DeviceTypePowerOutletsView.as_view(), name='devicetype_poweroutlets'),
|
|
||||||
path('device-types/<int:pk>/interfaces/', views.DeviceTypeInterfacesView.as_view(), name='devicetype_interfaces'),
|
|
||||||
path('device-types/<int:pk>/front-ports/', views.DeviceTypeFrontPortsView.as_view(), name='devicetype_frontports'),
|
|
||||||
path('device-types/<int:pk>/rear-ports/', views.DeviceTypeRearPortsView.as_view(), name='devicetype_rearports'),
|
|
||||||
path('device-types/<int:pk>/module-bays/', views.DeviceTypeModuleBaysView.as_view(), name='devicetype_modulebays'),
|
|
||||||
path('device-types/<int:pk>/device-bays/', views.DeviceTypeDeviceBaysView.as_view(), name='devicetype_devicebays'),
|
|
||||||
path('device-types/<int:pk>/inventory-items/', views.DeviceTypeInventoryItemsView.as_view(), name='devicetype_inventoryitems'),
|
|
||||||
path('device-types/<int:pk>/edit/', views.DeviceTypeEditView.as_view(), name='devicetype_edit'),
|
|
||||||
path('device-types/<int:pk>/delete/', views.DeviceTypeDeleteView.as_view(), name='devicetype_delete'),
|
|
||||||
path('device-types/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='devicetype_changelog', kwargs={'model': DeviceType}),
|
|
||||||
path('device-types/<int:pk>/journal/', ObjectJournalView.as_view(), name='devicetype_journal', kwargs={'model': DeviceType}),
|
|
||||||
|
|
||||||
# Module types
|
# Module types
|
||||||
path('module-types/', views.ModuleTypeListView.as_view(), name='moduletype_list'),
|
path('module-types/', views.ModuleTypeListView.as_view(), name='moduletype_list'),
|
||||||
@ -127,98 +85,77 @@ urlpatterns = [
|
|||||||
path('module-types/import/', views.ModuleTypeImportView.as_view(), name='moduletype_import'),
|
path('module-types/import/', views.ModuleTypeImportView.as_view(), name='moduletype_import'),
|
||||||
path('module-types/edit/', views.ModuleTypeBulkEditView.as_view(), name='moduletype_bulk_edit'),
|
path('module-types/edit/', views.ModuleTypeBulkEditView.as_view(), name='moduletype_bulk_edit'),
|
||||||
path('module-types/delete/', views.ModuleTypeBulkDeleteView.as_view(), name='moduletype_bulk_delete'),
|
path('module-types/delete/', views.ModuleTypeBulkDeleteView.as_view(), name='moduletype_bulk_delete'),
|
||||||
path('module-types/<int:pk>/', views.ModuleTypeView.as_view(), name='moduletype'),
|
path('module-types/<int:pk>/', include(get_model_urls('dcim', 'moduletype'))),
|
||||||
path('module-types/<int:pk>/console-ports/', views.ModuleTypeConsolePortsView.as_view(), name='moduletype_consoleports'),
|
|
||||||
path('module-types/<int:pk>/console-server-ports/', views.ModuleTypeConsoleServerPortsView.as_view(), name='moduletype_consoleserverports'),
|
|
||||||
path('module-types/<int:pk>/power-ports/', views.ModuleTypePowerPortsView.as_view(), name='moduletype_powerports'),
|
|
||||||
path('module-types/<int:pk>/power-outlets/', views.ModuleTypePowerOutletsView.as_view(), name='moduletype_poweroutlets'),
|
|
||||||
path('module-types/<int:pk>/interfaces/', views.ModuleTypeInterfacesView.as_view(), name='moduletype_interfaces'),
|
|
||||||
path('module-types/<int:pk>/front-ports/', views.ModuleTypeFrontPortsView.as_view(), name='moduletype_frontports'),
|
|
||||||
path('module-types/<int:pk>/rear-ports/', views.ModuleTypeRearPortsView.as_view(), name='moduletype_rearports'),
|
|
||||||
path('module-types/<int:pk>/edit/', views.ModuleTypeEditView.as_view(), name='moduletype_edit'),
|
|
||||||
path('module-types/<int:pk>/delete/', views.ModuleTypeDeleteView.as_view(), name='moduletype_delete'),
|
|
||||||
path('module-types/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='moduletype_changelog', kwargs={'model': ModuleType}),
|
|
||||||
path('module-types/<int:pk>/journal/', ObjectJournalView.as_view(), name='moduletype_journal', kwargs={'model': ModuleType}),
|
|
||||||
|
|
||||||
# Console port templates
|
# Console port templates
|
||||||
path('console-port-templates/add/', views.ConsolePortTemplateCreateView.as_view(), name='consoleporttemplate_add'),
|
path('console-port-templates/add/', views.ConsolePortTemplateCreateView.as_view(), name='consoleporttemplate_add'),
|
||||||
path('console-port-templates/edit/', views.ConsolePortTemplateBulkEditView.as_view(), name='consoleporttemplate_bulk_edit'),
|
path('console-port-templates/edit/', views.ConsolePortTemplateBulkEditView.as_view(), name='consoleporttemplate_bulk_edit'),
|
||||||
path('console-port-templates/rename/', views.ConsolePortTemplateBulkRenameView.as_view(), name='consoleporttemplate_bulk_rename'),
|
path('console-port-templates/rename/', views.ConsolePortTemplateBulkRenameView.as_view(), name='consoleporttemplate_bulk_rename'),
|
||||||
path('console-port-templates/delete/', views.ConsolePortTemplateBulkDeleteView.as_view(), name='consoleporttemplate_bulk_delete'),
|
path('console-port-templates/delete/', views.ConsolePortTemplateBulkDeleteView.as_view(), name='consoleporttemplate_bulk_delete'),
|
||||||
path('console-port-templates/<int:pk>/edit/', views.ConsolePortTemplateEditView.as_view(), name='consoleporttemplate_edit'),
|
path('console-port-templates/<int:pk>/', include(get_model_urls('dcim', 'consoleporttemplate'))),
|
||||||
path('console-port-templates/<int:pk>/delete/', views.ConsolePortTemplateDeleteView.as_view(), name='consoleporttemplate_delete'),
|
|
||||||
|
|
||||||
# Console server port templates
|
# Console server port templates
|
||||||
path('console-server-port-templates/add/', views.ConsoleServerPortTemplateCreateView.as_view(), name='consoleserverporttemplate_add'),
|
path('console-server-port-templates/add/', views.ConsoleServerPortTemplateCreateView.as_view(), name='consoleserverporttemplate_add'),
|
||||||
path('console-server-port-templates/edit/', views.ConsoleServerPortTemplateBulkEditView.as_view(), name='consoleserverporttemplate_bulk_edit'),
|
path('console-server-port-templates/edit/', views.ConsoleServerPortTemplateBulkEditView.as_view(), name='consoleserverporttemplate_bulk_edit'),
|
||||||
path('console-server-port-templates/rename/', views.ConsoleServerPortTemplateBulkRenameView.as_view(), name='consoleserverporttemplate_bulk_rename'),
|
path('console-server-port-templates/rename/', views.ConsoleServerPortTemplateBulkRenameView.as_view(), name='consoleserverporttemplate_bulk_rename'),
|
||||||
path('console-server-port-templates/delete/', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='consoleserverporttemplate_bulk_delete'),
|
path('console-server-port-templates/delete/', views.ConsoleServerPortTemplateBulkDeleteView.as_view(), name='consoleserverporttemplate_bulk_delete'),
|
||||||
path('console-server-port-templates/<int:pk>/edit/', views.ConsoleServerPortTemplateEditView.as_view(), name='consoleserverporttemplate_edit'),
|
path('console-server-port-templates/<int:pk>/', include(get_model_urls('dcim', 'consoleserverporttemplate'))),
|
||||||
path('console-server-port-templates/<int:pk>/delete/', views.ConsoleServerPortTemplateDeleteView.as_view(), name='consoleserverporttemplate_delete'),
|
|
||||||
|
|
||||||
# Power port templates
|
# Power port templates
|
||||||
path('power-port-templates/add/', views.PowerPortTemplateCreateView.as_view(), name='powerporttemplate_add'),
|
path('power-port-templates/add/', views.PowerPortTemplateCreateView.as_view(), name='powerporttemplate_add'),
|
||||||
path('power-port-templates/edit/', views.PowerPortTemplateBulkEditView.as_view(), name='powerporttemplate_bulk_edit'),
|
path('power-port-templates/edit/', views.PowerPortTemplateBulkEditView.as_view(), name='powerporttemplate_bulk_edit'),
|
||||||
path('power-port-templates/rename/', views.PowerPortTemplateBulkRenameView.as_view(), name='powerporttemplate_bulk_rename'),
|
path('power-port-templates/rename/', views.PowerPortTemplateBulkRenameView.as_view(), name='powerporttemplate_bulk_rename'),
|
||||||
path('power-port-templates/delete/', views.PowerPortTemplateBulkDeleteView.as_view(), name='powerporttemplate_bulk_delete'),
|
path('power-port-templates/delete/', views.PowerPortTemplateBulkDeleteView.as_view(), name='powerporttemplate_bulk_delete'),
|
||||||
path('power-port-templates/<int:pk>/edit/', views.PowerPortTemplateEditView.as_view(), name='powerporttemplate_edit'),
|
path('power-port-templates/<int:pk>/', include(get_model_urls('dcim', 'powerporttemplate'))),
|
||||||
path('power-port-templates/<int:pk>/delete/', views.PowerPortTemplateDeleteView.as_view(), name='powerporttemplate_delete'),
|
|
||||||
|
|
||||||
# Power outlet templates
|
# Power outlet templates
|
||||||
path('power-outlet-templates/add/', views.PowerOutletTemplateCreateView.as_view(), name='poweroutlettemplate_add'),
|
path('power-outlet-templates/add/', views.PowerOutletTemplateCreateView.as_view(), name='poweroutlettemplate_add'),
|
||||||
path('power-outlet-templates/edit/', views.PowerOutletTemplateBulkEditView.as_view(), name='poweroutlettemplate_bulk_edit'),
|
path('power-outlet-templates/edit/', views.PowerOutletTemplateBulkEditView.as_view(), name='poweroutlettemplate_bulk_edit'),
|
||||||
path('power-outlet-templates/rename/', views.PowerOutletTemplateBulkRenameView.as_view(), name='poweroutlettemplate_bulk_rename'),
|
path('power-outlet-templates/rename/', views.PowerOutletTemplateBulkRenameView.as_view(), name='poweroutlettemplate_bulk_rename'),
|
||||||
path('power-outlet-templates/delete/', views.PowerOutletTemplateBulkDeleteView.as_view(), name='poweroutlettemplate_bulk_delete'),
|
path('power-outlet-templates/delete/', views.PowerOutletTemplateBulkDeleteView.as_view(), name='poweroutlettemplate_bulk_delete'),
|
||||||
path('power-outlet-templates/<int:pk>/edit/', views.PowerOutletTemplateEditView.as_view(), name='poweroutlettemplate_edit'),
|
path('power-outlet-templates/<int:pk>/', include(get_model_urls('dcim', 'poweroutlettemplate'))),
|
||||||
path('power-outlet-templates/<int:pk>/delete/', views.PowerOutletTemplateDeleteView.as_view(), name='poweroutlettemplate_delete'),
|
|
||||||
|
|
||||||
# Interface templates
|
# Interface templates
|
||||||
path('interface-templates/add/', views.InterfaceTemplateCreateView.as_view(), name='interfacetemplate_add'),
|
path('interface-templates/add/', views.InterfaceTemplateCreateView.as_view(), name='interfacetemplate_add'),
|
||||||
path('interface-templates/edit/', views.InterfaceTemplateBulkEditView.as_view(), name='interfacetemplate_bulk_edit'),
|
path('interface-templates/edit/', views.InterfaceTemplateBulkEditView.as_view(), name='interfacetemplate_bulk_edit'),
|
||||||
path('interface-templates/rename/', views.InterfaceTemplateBulkRenameView.as_view(), name='interfacetemplate_bulk_rename'),
|
path('interface-templates/rename/', views.InterfaceTemplateBulkRenameView.as_view(), name='interfacetemplate_bulk_rename'),
|
||||||
path('interface-templates/delete/', views.InterfaceTemplateBulkDeleteView.as_view(), name='interfacetemplate_bulk_delete'),
|
path('interface-templates/delete/', views.InterfaceTemplateBulkDeleteView.as_view(), name='interfacetemplate_bulk_delete'),
|
||||||
path('interface-templates/<int:pk>/edit/', views.InterfaceTemplateEditView.as_view(), name='interfacetemplate_edit'),
|
path('interface-templates/<int:pk>/', include(get_model_urls('dcim', 'interfacetemplate'))),
|
||||||
path('interface-templates/<int:pk>/delete/', views.InterfaceTemplateDeleteView.as_view(), name='interfacetemplate_delete'),
|
|
||||||
|
|
||||||
# Front port templates
|
# Front port templates
|
||||||
path('front-port-templates/add/', views.FrontPortTemplateCreateView.as_view(), name='frontporttemplate_add'),
|
path('front-port-templates/add/', views.FrontPortTemplateCreateView.as_view(), name='frontporttemplate_add'),
|
||||||
path('front-port-templates/edit/', views.FrontPortTemplateBulkEditView.as_view(), name='frontporttemplate_bulk_edit'),
|
path('front-port-templates/edit/', views.FrontPortTemplateBulkEditView.as_view(), name='frontporttemplate_bulk_edit'),
|
||||||
path('front-port-templates/rename/', views.FrontPortTemplateBulkRenameView.as_view(), name='frontporttemplate_bulk_rename'),
|
path('front-port-templates/rename/', views.FrontPortTemplateBulkRenameView.as_view(), name='frontporttemplate_bulk_rename'),
|
||||||
path('front-port-templates/delete/', views.FrontPortTemplateBulkDeleteView.as_view(), name='frontporttemplate_bulk_delete'),
|
path('front-port-templates/delete/', views.FrontPortTemplateBulkDeleteView.as_view(), name='frontporttemplate_bulk_delete'),
|
||||||
path('front-port-templates/<int:pk>/edit/', views.FrontPortTemplateEditView.as_view(), name='frontporttemplate_edit'),
|
path('front-port-templates/<int:pk>/', include(get_model_urls('dcim', 'frontporttemplate'))),
|
||||||
path('front-port-templates/<int:pk>/delete/', views.FrontPortTemplateDeleteView.as_view(), name='frontporttemplate_delete'),
|
|
||||||
|
|
||||||
# Rear port templates
|
# Rear port templates
|
||||||
path('rear-port-templates/add/', views.RearPortTemplateCreateView.as_view(), name='rearporttemplate_add'),
|
path('rear-port-templates/add/', views.RearPortTemplateCreateView.as_view(), name='rearporttemplate_add'),
|
||||||
path('rear-port-templates/edit/', views.RearPortTemplateBulkEditView.as_view(), name='rearporttemplate_bulk_edit'),
|
path('rear-port-templates/edit/', views.RearPortTemplateBulkEditView.as_view(), name='rearporttemplate_bulk_edit'),
|
||||||
path('rear-port-templates/rename/', views.RearPortTemplateBulkRenameView.as_view(), name='rearporttemplate_bulk_rename'),
|
path('rear-port-templates/rename/', views.RearPortTemplateBulkRenameView.as_view(), name='rearporttemplate_bulk_rename'),
|
||||||
path('rear-port-templates/delete/', views.RearPortTemplateBulkDeleteView.as_view(), name='rearporttemplate_bulk_delete'),
|
path('rear-port-templates/delete/', views.RearPortTemplateBulkDeleteView.as_view(), name='rearporttemplate_bulk_delete'),
|
||||||
path('rear-port-templates/<int:pk>/edit/', views.RearPortTemplateEditView.as_view(), name='rearporttemplate_edit'),
|
path('rear-port-templates/<int:pk>/', include(get_model_urls('dcim', 'rearporttemplate'))),
|
||||||
path('rear-port-templates/<int:pk>/delete/', views.RearPortTemplateDeleteView.as_view(), name='rearporttemplate_delete'),
|
|
||||||
|
|
||||||
# Device bay templates
|
# Device bay templates
|
||||||
path('device-bay-templates/add/', views.DeviceBayTemplateCreateView.as_view(), name='devicebaytemplate_add'),
|
path('device-bay-templates/add/', views.DeviceBayTemplateCreateView.as_view(), name='devicebaytemplate_add'),
|
||||||
path('device-bay-templates/edit/', views.DeviceBayTemplateBulkEditView.as_view(), name='devicebaytemplate_bulk_edit'),
|
path('device-bay-templates/edit/', views.DeviceBayTemplateBulkEditView.as_view(), name='devicebaytemplate_bulk_edit'),
|
||||||
path('device-bay-templates/rename/', views.DeviceBayTemplateBulkRenameView.as_view(), name='devicebaytemplate_bulk_rename'),
|
path('device-bay-templates/rename/', views.DeviceBayTemplateBulkRenameView.as_view(), name='devicebaytemplate_bulk_rename'),
|
||||||
path('device-bay-templates/delete/', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicebaytemplate_bulk_delete'),
|
path('device-bay-templates/delete/', views.DeviceBayTemplateBulkDeleteView.as_view(), name='devicebaytemplate_bulk_delete'),
|
||||||
path('device-bay-templates/<int:pk>/edit/', views.DeviceBayTemplateEditView.as_view(), name='devicebaytemplate_edit'),
|
path('device-bay-templates/<int:pk>/', include(get_model_urls('dcim', 'devicebaytemplate'))),
|
||||||
path('device-bay-templates/<int:pk>/delete/', views.DeviceBayTemplateDeleteView.as_view(), name='devicebaytemplate_delete'),
|
|
||||||
|
|
||||||
# Module bay templates
|
# Module bay templates
|
||||||
path('module-bay-templates/add/', views.ModuleBayTemplateCreateView.as_view(), name='modulebaytemplate_add'),
|
path('module-bay-templates/add/', views.ModuleBayTemplateCreateView.as_view(), name='modulebaytemplate_add'),
|
||||||
path('module-bay-templates/edit/', views.ModuleBayTemplateBulkEditView.as_view(), name='modulebaytemplate_bulk_edit'),
|
path('module-bay-templates/edit/', views.ModuleBayTemplateBulkEditView.as_view(), name='modulebaytemplate_bulk_edit'),
|
||||||
path('module-bay-templates/rename/', views.ModuleBayTemplateBulkRenameView.as_view(), name='modulebaytemplate_bulk_rename'),
|
path('module-bay-templates/rename/', views.ModuleBayTemplateBulkRenameView.as_view(), name='modulebaytemplate_bulk_rename'),
|
||||||
path('module-bay-templates/delete/', views.ModuleBayTemplateBulkDeleteView.as_view(), name='modulebaytemplate_bulk_delete'),
|
path('module-bay-templates/delete/', views.ModuleBayTemplateBulkDeleteView.as_view(), name='modulebaytemplate_bulk_delete'),
|
||||||
path('module-bay-templates/<int:pk>/edit/', views.ModuleBayTemplateEditView.as_view(), name='modulebaytemplate_edit'),
|
path('module-bay-templates/<int:pk>/', include(get_model_urls('dcim', 'modulebaytemplate'))),
|
||||||
path('module-bay-templates/<int:pk>/delete/', views.ModuleBayTemplateDeleteView.as_view(), name='modulebaytemplate_delete'),
|
|
||||||
|
|
||||||
# Inventory item templates
|
# Inventory item templates
|
||||||
path('inventory-item-templates/add/', views.InventoryItemTemplateCreateView.as_view(), name='inventoryitemtemplate_add'),
|
path('inventory-item-templates/add/', views.InventoryItemTemplateCreateView.as_view(), name='inventoryitemtemplate_add'),
|
||||||
path('inventory-item-templates/edit/', views.InventoryItemTemplateBulkEditView.as_view(), name='inventoryitemtemplate_bulk_edit'),
|
path('inventory-item-templates/edit/', views.InventoryItemTemplateBulkEditView.as_view(), name='inventoryitemtemplate_bulk_edit'),
|
||||||
path('inventory-item-templates/rename/', views.InventoryItemTemplateBulkRenameView.as_view(), name='inventoryitemtemplate_bulk_rename'),
|
path('inventory-item-templates/rename/', views.InventoryItemTemplateBulkRenameView.as_view(), name='inventoryitemtemplate_bulk_rename'),
|
||||||
path('inventory-item-templates/delete/', views.InventoryItemTemplateBulkDeleteView.as_view(), name='inventoryitemtemplate_bulk_delete'),
|
path('inventory-item-templates/delete/', views.InventoryItemTemplateBulkDeleteView.as_view(), name='inventoryitemtemplate_bulk_delete'),
|
||||||
path('inventory-item-templates/<int:pk>/edit/', views.InventoryItemTemplateEditView.as_view(), name='inventoryitemtemplate_edit'),
|
path('inventory-item-templates/<int:pk>/', include(get_model_urls('dcim', 'inventoryitemtemplate'))),
|
||||||
path('inventory-item-templates/<int:pk>/delete/', views.InventoryItemTemplateDeleteView.as_view(), name='inventoryitemtemplate_delete'),
|
|
||||||
|
|
||||||
# Device roles
|
# Device roles
|
||||||
path('device-roles/', views.DeviceRoleListView.as_view(), name='devicerole_list'),
|
path('device-roles/', views.DeviceRoleListView.as_view(), name='devicerole_list'),
|
||||||
@ -226,10 +163,7 @@ urlpatterns = [
|
|||||||
path('device-roles/import/', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'),
|
path('device-roles/import/', views.DeviceRoleBulkImportView.as_view(), name='devicerole_import'),
|
||||||
path('device-roles/edit/', views.DeviceRoleBulkEditView.as_view(), name='devicerole_bulk_edit'),
|
path('device-roles/edit/', views.DeviceRoleBulkEditView.as_view(), name='devicerole_bulk_edit'),
|
||||||
path('device-roles/delete/', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
|
path('device-roles/delete/', views.DeviceRoleBulkDeleteView.as_view(), name='devicerole_bulk_delete'),
|
||||||
path('device-roles/<int:pk>/', views.DeviceRoleView.as_view(), name='devicerole'),
|
path('device-roles/<int:pk>/', include(get_model_urls('dcim', 'devicerole'))),
|
||||||
path('device-roles/<int:pk>/edit/', views.DeviceRoleEditView.as_view(), name='devicerole_edit'),
|
|
||||||
path('device-roles/<int:pk>/delete/', views.DeviceRoleDeleteView.as_view(), name='devicerole_delete'),
|
|
||||||
path('device-roles/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='devicerole_changelog', kwargs={'model': DeviceRole}),
|
|
||||||
|
|
||||||
# Platforms
|
# Platforms
|
||||||
path('platforms/', views.PlatformListView.as_view(), name='platform_list'),
|
path('platforms/', views.PlatformListView.as_view(), name='platform_list'),
|
||||||
@ -237,10 +171,7 @@ urlpatterns = [
|
|||||||
path('platforms/import/', views.PlatformBulkImportView.as_view(), name='platform_import'),
|
path('platforms/import/', views.PlatformBulkImportView.as_view(), name='platform_import'),
|
||||||
path('platforms/edit/', views.PlatformBulkEditView.as_view(), name='platform_bulk_edit'),
|
path('platforms/edit/', views.PlatformBulkEditView.as_view(), name='platform_bulk_edit'),
|
||||||
path('platforms/delete/', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
|
path('platforms/delete/', views.PlatformBulkDeleteView.as_view(), name='platform_bulk_delete'),
|
||||||
path('platforms/<int:pk>/', views.PlatformView.as_view(), name='platform'),
|
path('platforms/<int:pk>/', include(get_model_urls('dcim', 'platform'))),
|
||||||
path('platforms/<int:pk>/edit/', views.PlatformEditView.as_view(), name='platform_edit'),
|
|
||||||
path('platforms/<int:pk>/delete/', views.PlatformDeleteView.as_view(), name='platform_delete'),
|
|
||||||
path('platforms/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='platform_changelog', kwargs={'model': Platform}),
|
|
||||||
|
|
||||||
# Devices
|
# Devices
|
||||||
path('devices/', views.DeviceListView.as_view(), name='device_list'),
|
path('devices/', views.DeviceListView.as_view(), name='device_list'),
|
||||||
@ -250,25 +181,7 @@ urlpatterns = [
|
|||||||
path('devices/edit/', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'),
|
path('devices/edit/', views.DeviceBulkEditView.as_view(), name='device_bulk_edit'),
|
||||||
path('devices/rename/', views.DeviceBulkRenameView.as_view(), name='device_bulk_rename'),
|
path('devices/rename/', views.DeviceBulkRenameView.as_view(), name='device_bulk_rename'),
|
||||||
path('devices/delete/', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'),
|
path('devices/delete/', views.DeviceBulkDeleteView.as_view(), name='device_bulk_delete'),
|
||||||
path('devices/<int:pk>/', views.DeviceView.as_view(), name='device'),
|
path('devices/<int:pk>/', include(get_model_urls('dcim', 'device'))),
|
||||||
path('devices/<int:pk>/edit/', views.DeviceEditView.as_view(), name='device_edit'),
|
|
||||||
path('devices/<int:pk>/delete/', views.DeviceDeleteView.as_view(), name='device_delete'),
|
|
||||||
path('devices/<int:pk>/console-ports/', views.DeviceConsolePortsView.as_view(), name='device_consoleports'),
|
|
||||||
path('devices/<int:pk>/console-server-ports/', views.DeviceConsoleServerPortsView.as_view(), name='device_consoleserverports'),
|
|
||||||
path('devices/<int:pk>/power-ports/', views.DevicePowerPortsView.as_view(), name='device_powerports'),
|
|
||||||
path('devices/<int:pk>/power-outlets/', views.DevicePowerOutletsView.as_view(), name='device_poweroutlets'),
|
|
||||||
path('devices/<int:pk>/interfaces/', views.DeviceInterfacesView.as_view(), name='device_interfaces'),
|
|
||||||
path('devices/<int:pk>/front-ports/', views.DeviceFrontPortsView.as_view(), name='device_frontports'),
|
|
||||||
path('devices/<int:pk>/rear-ports/', views.DeviceRearPortsView.as_view(), name='device_rearports'),
|
|
||||||
path('devices/<int:pk>/module-bays/', views.DeviceModuleBaysView.as_view(), name='device_modulebays'),
|
|
||||||
path('devices/<int:pk>/device-bays/', views.DeviceDeviceBaysView.as_view(), name='device_devicebays'),
|
|
||||||
path('devices/<int:pk>/inventory/', views.DeviceInventoryView.as_view(), name='device_inventory'),
|
|
||||||
path('devices/<int:pk>/config-context/', views.DeviceConfigContextView.as_view(), name='device_configcontext'),
|
|
||||||
path('devices/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='device_changelog', kwargs={'model': Device}),
|
|
||||||
path('devices/<int:pk>/journal/', ObjectJournalView.as_view(), name='device_journal', kwargs={'model': Device}),
|
|
||||||
path('devices/<int:pk>/status/', views.DeviceStatusView.as_view(), name='device_status'),
|
|
||||||
path('devices/<int:pk>/lldp-neighbors/', views.DeviceLLDPNeighborsView.as_view(), name='device_lldp_neighbors'),
|
|
||||||
path('devices/<int:pk>/config/', views.DeviceConfigView.as_view(), name='device_config'),
|
|
||||||
|
|
||||||
# Modules
|
# Modules
|
||||||
path('modules/', views.ModuleListView.as_view(), name='module_list'),
|
path('modules/', views.ModuleListView.as_view(), name='module_list'),
|
||||||
@ -276,11 +189,7 @@ urlpatterns = [
|
|||||||
path('modules/import/', views.ModuleBulkImportView.as_view(), name='module_import'),
|
path('modules/import/', views.ModuleBulkImportView.as_view(), name='module_import'),
|
||||||
path('modules/edit/', views.ModuleBulkEditView.as_view(), name='module_bulk_edit'),
|
path('modules/edit/', views.ModuleBulkEditView.as_view(), name='module_bulk_edit'),
|
||||||
path('modules/delete/', views.ModuleBulkDeleteView.as_view(), name='module_bulk_delete'),
|
path('modules/delete/', views.ModuleBulkDeleteView.as_view(), name='module_bulk_delete'),
|
||||||
path('modules/<int:pk>/', views.ModuleView.as_view(), name='module'),
|
path('modules/<int:pk>/', include(get_model_urls('dcim', 'module'))),
|
||||||
path('modules/<int:pk>/edit/', views.ModuleEditView.as_view(), name='module_edit'),
|
|
||||||
path('modules/<int:pk>/delete/', views.ModuleDeleteView.as_view(), name='module_delete'),
|
|
||||||
path('modules/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='module_changelog', kwargs={'model': Module}),
|
|
||||||
path('modules/<int:pk>/journal/', ObjectJournalView.as_view(), name='module_journal', kwargs={'model': Module}),
|
|
||||||
|
|
||||||
# Console ports
|
# Console ports
|
||||||
path('console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'),
|
path('console-ports/', views.ConsolePortListView.as_view(), name='consoleport_list'),
|
||||||
@ -290,11 +199,7 @@ urlpatterns = [
|
|||||||
path('console-ports/rename/', views.ConsolePortBulkRenameView.as_view(), name='consoleport_bulk_rename'),
|
path('console-ports/rename/', views.ConsolePortBulkRenameView.as_view(), name='consoleport_bulk_rename'),
|
||||||
path('console-ports/disconnect/', views.ConsolePortBulkDisconnectView.as_view(), name='consoleport_bulk_disconnect'),
|
path('console-ports/disconnect/', views.ConsolePortBulkDisconnectView.as_view(), name='consoleport_bulk_disconnect'),
|
||||||
path('console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
|
path('console-ports/delete/', views.ConsolePortBulkDeleteView.as_view(), name='consoleport_bulk_delete'),
|
||||||
path('console-ports/<int:pk>/', views.ConsolePortView.as_view(), name='consoleport'),
|
path('console-ports/<int:pk>/', include(get_model_urls('dcim', 'consoleport'))),
|
||||||
path('console-ports/<int:pk>/edit/', views.ConsolePortEditView.as_view(), name='consoleport_edit'),
|
|
||||||
path('console-ports/<int:pk>/delete/', views.ConsolePortDeleteView.as_view(), name='consoleport_delete'),
|
|
||||||
path('console-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='consoleport_changelog', kwargs={'model': ConsolePort}),
|
|
||||||
path('console-ports/<int:pk>/trace/', views.PathTraceView.as_view(), name='consoleport_trace', kwargs={'model': ConsolePort}),
|
|
||||||
path('devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
|
path('devices/console-ports/add/', views.DeviceBulkAddConsolePortView.as_view(), name='device_bulk_add_consoleport'),
|
||||||
|
|
||||||
# Console server ports
|
# Console server ports
|
||||||
@ -305,11 +210,7 @@ urlpatterns = [
|
|||||||
path('console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'),
|
path('console-server-ports/rename/', views.ConsoleServerPortBulkRenameView.as_view(), name='consoleserverport_bulk_rename'),
|
||||||
path('console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
|
path('console-server-ports/disconnect/', views.ConsoleServerPortBulkDisconnectView.as_view(), name='consoleserverport_bulk_disconnect'),
|
||||||
path('console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
|
path('console-server-ports/delete/', views.ConsoleServerPortBulkDeleteView.as_view(), name='consoleserverport_bulk_delete'),
|
||||||
path('console-server-ports/<int:pk>/', views.ConsoleServerPortView.as_view(), name='consoleserverport'),
|
path('console-server-ports/<int:pk>/', include(get_model_urls('dcim', 'consoleserverport'))),
|
||||||
path('console-server-ports/<int:pk>/edit/', views.ConsoleServerPortEditView.as_view(), name='consoleserverport_edit'),
|
|
||||||
path('console-server-ports/<int:pk>/delete/', views.ConsoleServerPortDeleteView.as_view(), name='consoleserverport_delete'),
|
|
||||||
path('console-server-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='consoleserverport_changelog', kwargs={'model': ConsoleServerPort}),
|
|
||||||
path('console-server-ports/<int:pk>/trace/', views.PathTraceView.as_view(), name='consoleserverport_trace', kwargs={'model': ConsoleServerPort}),
|
|
||||||
path('devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
|
path('devices/console-server-ports/add/', views.DeviceBulkAddConsoleServerPortView.as_view(), name='device_bulk_add_consoleserverport'),
|
||||||
|
|
||||||
# Power ports
|
# Power ports
|
||||||
@ -320,11 +221,7 @@ urlpatterns = [
|
|||||||
path('power-ports/rename/', views.PowerPortBulkRenameView.as_view(), name='powerport_bulk_rename'),
|
path('power-ports/rename/', views.PowerPortBulkRenameView.as_view(), name='powerport_bulk_rename'),
|
||||||
path('power-ports/disconnect/', views.PowerPortBulkDisconnectView.as_view(), name='powerport_bulk_disconnect'),
|
path('power-ports/disconnect/', views.PowerPortBulkDisconnectView.as_view(), name='powerport_bulk_disconnect'),
|
||||||
path('power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
|
path('power-ports/delete/', views.PowerPortBulkDeleteView.as_view(), name='powerport_bulk_delete'),
|
||||||
path('power-ports/<int:pk>/', views.PowerPortView.as_view(), name='powerport'),
|
path('power-ports/<int:pk>/', include(get_model_urls('dcim', 'powerport'))),
|
||||||
path('power-ports/<int:pk>/edit/', views.PowerPortEditView.as_view(), name='powerport_edit'),
|
|
||||||
path('power-ports/<int:pk>/delete/', views.PowerPortDeleteView.as_view(), name='powerport_delete'),
|
|
||||||
path('power-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='powerport_changelog', kwargs={'model': PowerPort}),
|
|
||||||
path('power-ports/<int:pk>/trace/', views.PathTraceView.as_view(), name='powerport_trace', kwargs={'model': PowerPort}),
|
|
||||||
path('devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
|
path('devices/power-ports/add/', views.DeviceBulkAddPowerPortView.as_view(), name='device_bulk_add_powerport'),
|
||||||
|
|
||||||
# Power outlets
|
# Power outlets
|
||||||
@ -335,11 +232,7 @@ urlpatterns = [
|
|||||||
path('power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'),
|
path('power-outlets/rename/', views.PowerOutletBulkRenameView.as_view(), name='poweroutlet_bulk_rename'),
|
||||||
path('power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
|
path('power-outlets/disconnect/', views.PowerOutletBulkDisconnectView.as_view(), name='poweroutlet_bulk_disconnect'),
|
||||||
path('power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
|
path('power-outlets/delete/', views.PowerOutletBulkDeleteView.as_view(), name='poweroutlet_bulk_delete'),
|
||||||
path('power-outlets/<int:pk>/', views.PowerOutletView.as_view(), name='poweroutlet'),
|
path('power-outlets/<int:pk>/', include(get_model_urls('dcim', 'poweroutlet'))),
|
||||||
path('power-outlets/<int:pk>/edit/', views.PowerOutletEditView.as_view(), name='poweroutlet_edit'),
|
|
||||||
path('power-outlets/<int:pk>/delete/', views.PowerOutletDeleteView.as_view(), name='poweroutlet_delete'),
|
|
||||||
path('power-outlets/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='poweroutlet_changelog', kwargs={'model': PowerOutlet}),
|
|
||||||
path('power-outlets/<int:pk>/trace/', views.PathTraceView.as_view(), name='poweroutlet_trace', kwargs={'model': PowerOutlet}),
|
|
||||||
path('devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
|
path('devices/power-outlets/add/', views.DeviceBulkAddPowerOutletView.as_view(), name='device_bulk_add_poweroutlet'),
|
||||||
|
|
||||||
# Interfaces
|
# Interfaces
|
||||||
@ -350,11 +243,7 @@ urlpatterns = [
|
|||||||
path('interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'),
|
path('interfaces/rename/', views.InterfaceBulkRenameView.as_view(), name='interface_bulk_rename'),
|
||||||
path('interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
|
path('interfaces/disconnect/', views.InterfaceBulkDisconnectView.as_view(), name='interface_bulk_disconnect'),
|
||||||
path('interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
|
path('interfaces/delete/', views.InterfaceBulkDeleteView.as_view(), name='interface_bulk_delete'),
|
||||||
path('interfaces/<int:pk>/', views.InterfaceView.as_view(), name='interface'),
|
path('interfaces/<int:pk>/', include(get_model_urls('dcim', 'interface'))),
|
||||||
path('interfaces/<int:pk>/edit/', views.InterfaceEditView.as_view(), name='interface_edit'),
|
|
||||||
path('interfaces/<int:pk>/delete/', views.InterfaceDeleteView.as_view(), name='interface_delete'),
|
|
||||||
path('interfaces/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='interface_changelog', kwargs={'model': Interface}),
|
|
||||||
path('interfaces/<int:pk>/trace/', views.PathTraceView.as_view(), name='interface_trace', kwargs={'model': Interface}),
|
|
||||||
path('devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
|
path('devices/interfaces/add/', views.DeviceBulkAddInterfaceView.as_view(), name='device_bulk_add_interface'),
|
||||||
|
|
||||||
# Front ports
|
# Front ports
|
||||||
@ -365,11 +254,7 @@ urlpatterns = [
|
|||||||
path('front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'),
|
path('front-ports/rename/', views.FrontPortBulkRenameView.as_view(), name='frontport_bulk_rename'),
|
||||||
path('front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'),
|
path('front-ports/disconnect/', views.FrontPortBulkDisconnectView.as_view(), name='frontport_bulk_disconnect'),
|
||||||
path('front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'),
|
path('front-ports/delete/', views.FrontPortBulkDeleteView.as_view(), name='frontport_bulk_delete'),
|
||||||
path('front-ports/<int:pk>/', views.FrontPortView.as_view(), name='frontport'),
|
path('front-ports/<int:pk>/', include(get_model_urls('dcim', 'frontport'))),
|
||||||
path('front-ports/<int:pk>/edit/', views.FrontPortEditView.as_view(), name='frontport_edit'),
|
|
||||||
path('front-ports/<int:pk>/delete/', views.FrontPortDeleteView.as_view(), name='frontport_delete'),
|
|
||||||
path('front-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='frontport_changelog', kwargs={'model': FrontPort}),
|
|
||||||
path('front-ports/<int:pk>/trace/', views.PathTraceView.as_view(), name='frontport_trace', kwargs={'model': FrontPort}),
|
|
||||||
# path('devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'),
|
# path('devices/front-ports/add/', views.DeviceBulkAddFrontPortView.as_view(), name='device_bulk_add_frontport'),
|
||||||
|
|
||||||
# Rear ports
|
# Rear ports
|
||||||
@ -380,11 +265,7 @@ urlpatterns = [
|
|||||||
path('rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'),
|
path('rear-ports/rename/', views.RearPortBulkRenameView.as_view(), name='rearport_bulk_rename'),
|
||||||
path('rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'),
|
path('rear-ports/disconnect/', views.RearPortBulkDisconnectView.as_view(), name='rearport_bulk_disconnect'),
|
||||||
path('rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'),
|
path('rear-ports/delete/', views.RearPortBulkDeleteView.as_view(), name='rearport_bulk_delete'),
|
||||||
path('rear-ports/<int:pk>/', views.RearPortView.as_view(), name='rearport'),
|
path('rear-ports/<int:pk>/', include(get_model_urls('dcim', 'rearport'))),
|
||||||
path('rear-ports/<int:pk>/edit/', views.RearPortEditView.as_view(), name='rearport_edit'),
|
|
||||||
path('rear-ports/<int:pk>/delete/', views.RearPortDeleteView.as_view(), name='rearport_delete'),
|
|
||||||
path('rear-ports/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='rearport_changelog', kwargs={'model': RearPort}),
|
|
||||||
path('rear-ports/<int:pk>/trace/', views.PathTraceView.as_view(), name='rearport_trace', kwargs={'model': RearPort}),
|
|
||||||
path('devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'),
|
path('devices/rear-ports/add/', views.DeviceBulkAddRearPortView.as_view(), name='device_bulk_add_rearport'),
|
||||||
|
|
||||||
# Module bays
|
# Module bays
|
||||||
@ -394,10 +275,7 @@ urlpatterns = [
|
|||||||
path('module-bays/edit/', views.ModuleBayBulkEditView.as_view(), name='modulebay_bulk_edit'),
|
path('module-bays/edit/', views.ModuleBayBulkEditView.as_view(), name='modulebay_bulk_edit'),
|
||||||
path('module-bays/rename/', views.ModuleBayBulkRenameView.as_view(), name='modulebay_bulk_rename'),
|
path('module-bays/rename/', views.ModuleBayBulkRenameView.as_view(), name='modulebay_bulk_rename'),
|
||||||
path('module-bays/delete/', views.ModuleBayBulkDeleteView.as_view(), name='modulebay_bulk_delete'),
|
path('module-bays/delete/', views.ModuleBayBulkDeleteView.as_view(), name='modulebay_bulk_delete'),
|
||||||
path('module-bays/<int:pk>/', views.ModuleBayView.as_view(), name='modulebay'),
|
path('module-bays/<int:pk>/', include(get_model_urls('dcim', 'modulebay'))),
|
||||||
path('module-bays/<int:pk>/edit/', views.ModuleBayEditView.as_view(), name='modulebay_edit'),
|
|
||||||
path('module-bays/<int:pk>/delete/', views.ModuleBayDeleteView.as_view(), name='modulebay_delete'),
|
|
||||||
path('module-bays/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='modulebay_changelog', kwargs={'model': ModuleBay}),
|
|
||||||
path('devices/module-bays/add/', views.DeviceBulkAddModuleBayView.as_view(), name='device_bulk_add_modulebay'),
|
path('devices/module-bays/add/', views.DeviceBulkAddModuleBayView.as_view(), name='device_bulk_add_modulebay'),
|
||||||
|
|
||||||
# Device bays
|
# Device bays
|
||||||
@ -407,12 +285,7 @@ urlpatterns = [
|
|||||||
path('device-bays/edit/', views.DeviceBayBulkEditView.as_view(), name='devicebay_bulk_edit'),
|
path('device-bays/edit/', views.DeviceBayBulkEditView.as_view(), name='devicebay_bulk_edit'),
|
||||||
path('device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'),
|
path('device-bays/rename/', views.DeviceBayBulkRenameView.as_view(), name='devicebay_bulk_rename'),
|
||||||
path('device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
|
path('device-bays/delete/', views.DeviceBayBulkDeleteView.as_view(), name='devicebay_bulk_delete'),
|
||||||
path('device-bays/<int:pk>/', views.DeviceBayView.as_view(), name='devicebay'),
|
path('device-bays/<int:pk>/', include(get_model_urls('dcim', 'devicebay'))),
|
||||||
path('device-bays/<int:pk>/edit/', views.DeviceBayEditView.as_view(), name='devicebay_edit'),
|
|
||||||
path('device-bays/<int:pk>/delete/', views.DeviceBayDeleteView.as_view(), name='devicebay_delete'),
|
|
||||||
path('device-bays/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='devicebay_changelog', kwargs={'model': DeviceBay}),
|
|
||||||
path('device-bays/<int:pk>/populate/', views.DeviceBayPopulateView.as_view(), name='devicebay_populate'),
|
|
||||||
path('device-bays/<int:pk>/depopulate/', views.DeviceBayDepopulateView.as_view(), name='devicebay_depopulate'),
|
|
||||||
path('devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
|
path('devices/device-bays/add/', views.DeviceBulkAddDeviceBayView.as_view(), name='device_bulk_add_devicebay'),
|
||||||
|
|
||||||
# Inventory items
|
# Inventory items
|
||||||
@ -422,22 +295,16 @@ urlpatterns = [
|
|||||||
path('inventory-items/edit/', views.InventoryItemBulkEditView.as_view(), name='inventoryitem_bulk_edit'),
|
path('inventory-items/edit/', views.InventoryItemBulkEditView.as_view(), name='inventoryitem_bulk_edit'),
|
||||||
path('inventory-items/rename/', views.InventoryItemBulkRenameView.as_view(), name='inventoryitem_bulk_rename'),
|
path('inventory-items/rename/', views.InventoryItemBulkRenameView.as_view(), name='inventoryitem_bulk_rename'),
|
||||||
path('inventory-items/delete/', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'),
|
path('inventory-items/delete/', views.InventoryItemBulkDeleteView.as_view(), name='inventoryitem_bulk_delete'),
|
||||||
path('inventory-items/<int:pk>/', views.InventoryItemView.as_view(), name='inventoryitem'),
|
path('inventory-items/<int:pk>/', include(get_model_urls('dcim', 'inventoryitem'))),
|
||||||
path('inventory-items/<int:pk>/edit/', views.InventoryItemEditView.as_view(), name='inventoryitem_edit'),
|
|
||||||
path('inventory-items/<int:pk>/delete/', views.InventoryItemDeleteView.as_view(), name='inventoryitem_delete'),
|
|
||||||
path('inventory-items/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='inventoryitem_changelog', kwargs={'model': InventoryItem}),
|
|
||||||
path('devices/inventory-items/add/', views.DeviceBulkAddInventoryItemView.as_view(), name='device_bulk_add_inventoryitem'),
|
path('devices/inventory-items/add/', views.DeviceBulkAddInventoryItemView.as_view(), name='device_bulk_add_inventoryitem'),
|
||||||
|
|
||||||
# Device roles
|
# Inventory item roles
|
||||||
path('inventory-item-roles/', views.InventoryItemRoleListView.as_view(), name='inventoryitemrole_list'),
|
path('inventory-item-roles/', views.InventoryItemRoleListView.as_view(), name='inventoryitemrole_list'),
|
||||||
path('inventory-item-roles/add/', views.InventoryItemRoleEditView.as_view(), name='inventoryitemrole_add'),
|
path('inventory-item-roles/add/', views.InventoryItemRoleEditView.as_view(), name='inventoryitemrole_add'),
|
||||||
path('inventory-item-roles/import/', views.InventoryItemRoleBulkImportView.as_view(), name='inventoryitemrole_import'),
|
path('inventory-item-roles/import/', views.InventoryItemRoleBulkImportView.as_view(), name='inventoryitemrole_import'),
|
||||||
path('inventory-item-roles/edit/', views.InventoryItemRoleBulkEditView.as_view(), name='inventoryitemrole_bulk_edit'),
|
path('inventory-item-roles/edit/', views.InventoryItemRoleBulkEditView.as_view(), name='inventoryitemrole_bulk_edit'),
|
||||||
path('inventory-item-roles/delete/', views.InventoryItemRoleBulkDeleteView.as_view(), name='inventoryitemrole_bulk_delete'),
|
path('inventory-item-roles/delete/', views.InventoryItemRoleBulkDeleteView.as_view(), name='inventoryitemrole_bulk_delete'),
|
||||||
path('inventory-item-roles/<int:pk>/', views.InventoryItemRoleView.as_view(), name='inventoryitemrole'),
|
path('inventory-item-roles/<int:pk>/', include(get_model_urls('dcim', 'inventoryitemrole'))),
|
||||||
path('inventory-item-roles/<int:pk>/edit/', views.InventoryItemRoleEditView.as_view(), name='inventoryitemrole_edit'),
|
|
||||||
path('inventory-item-roles/<int:pk>/delete/', views.InventoryItemRoleDeleteView.as_view(), name='inventoryitemrole_delete'),
|
|
||||||
path('inventory-item-roles/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='inventoryitemrole_changelog', kwargs={'model': InventoryItemRole}),
|
|
||||||
|
|
||||||
# Cables
|
# Cables
|
||||||
path('cables/', views.CableListView.as_view(), name='cable_list'),
|
path('cables/', views.CableListView.as_view(), name='cable_list'),
|
||||||
@ -445,11 +312,7 @@ urlpatterns = [
|
|||||||
path('cables/import/', views.CableBulkImportView.as_view(), name='cable_import'),
|
path('cables/import/', views.CableBulkImportView.as_view(), name='cable_import'),
|
||||||
path('cables/edit/', views.CableBulkEditView.as_view(), name='cable_bulk_edit'),
|
path('cables/edit/', views.CableBulkEditView.as_view(), name='cable_bulk_edit'),
|
||||||
path('cables/delete/', views.CableBulkDeleteView.as_view(), name='cable_bulk_delete'),
|
path('cables/delete/', views.CableBulkDeleteView.as_view(), name='cable_bulk_delete'),
|
||||||
path('cables/<int:pk>/', views.CableView.as_view(), name='cable'),
|
path('cables/<int:pk>/', include(get_model_urls('dcim', 'cable'))),
|
||||||
path('cables/<int:pk>/edit/', views.CableEditView.as_view(), name='cable_edit'),
|
|
||||||
path('cables/<int:pk>/delete/', views.CableDeleteView.as_view(), name='cable_delete'),
|
|
||||||
path('cables/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='cable_changelog', kwargs={'model': Cable}),
|
|
||||||
path('cables/<int:pk>/journal/', ObjectJournalView.as_view(), name='cable_journal', kwargs={'model': Cable}),
|
|
||||||
|
|
||||||
# Console/power/interface connections (read-only)
|
# Console/power/interface connections (read-only)
|
||||||
path('console-connections/', views.ConsoleConnectionsListView.as_view(), name='console_connections_list'),
|
path('console-connections/', views.ConsoleConnectionsListView.as_view(), name='console_connections_list'),
|
||||||
@ -462,12 +325,7 @@ urlpatterns = [
|
|||||||
path('virtual-chassis/import/', views.VirtualChassisBulkImportView.as_view(), name='virtualchassis_import'),
|
path('virtual-chassis/import/', views.VirtualChassisBulkImportView.as_view(), name='virtualchassis_import'),
|
||||||
path('virtual-chassis/edit/', views.VirtualChassisBulkEditView.as_view(), name='virtualchassis_bulk_edit'),
|
path('virtual-chassis/edit/', views.VirtualChassisBulkEditView.as_view(), name='virtualchassis_bulk_edit'),
|
||||||
path('virtual-chassis/delete/', views.VirtualChassisBulkDeleteView.as_view(), name='virtualchassis_bulk_delete'),
|
path('virtual-chassis/delete/', views.VirtualChassisBulkDeleteView.as_view(), name='virtualchassis_bulk_delete'),
|
||||||
path('virtual-chassis/<int:pk>/', views.VirtualChassisView.as_view(), name='virtualchassis'),
|
path('virtual-chassis/<int:pk>/', include(get_model_urls('dcim', 'virtualchassis'))),
|
||||||
path('virtual-chassis/<int:pk>/edit/', views.VirtualChassisEditView.as_view(), name='virtualchassis_edit'),
|
|
||||||
path('virtual-chassis/<int:pk>/delete/', views.VirtualChassisDeleteView.as_view(), name='virtualchassis_delete'),
|
|
||||||
path('virtual-chassis/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='virtualchassis_changelog', kwargs={'model': VirtualChassis}),
|
|
||||||
path('virtual-chassis/<int:pk>/journal/', ObjectJournalView.as_view(), name='virtualchassis_journal', kwargs={'model': VirtualChassis}),
|
|
||||||
path('virtual-chassis/<int:pk>/add-member/', views.VirtualChassisAddMemberView.as_view(), name='virtualchassis_add_member'),
|
|
||||||
path('virtual-chassis-members/<int:pk>/delete/', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'),
|
path('virtual-chassis-members/<int:pk>/delete/', views.VirtualChassisRemoveMemberView.as_view(), name='virtualchassis_remove_member'),
|
||||||
|
|
||||||
# Power panels
|
# Power panels
|
||||||
@ -476,11 +334,7 @@ urlpatterns = [
|
|||||||
path('power-panels/import/', views.PowerPanelBulkImportView.as_view(), name='powerpanel_import'),
|
path('power-panels/import/', views.PowerPanelBulkImportView.as_view(), name='powerpanel_import'),
|
||||||
path('power-panels/edit/', views.PowerPanelBulkEditView.as_view(), name='powerpanel_bulk_edit'),
|
path('power-panels/edit/', views.PowerPanelBulkEditView.as_view(), name='powerpanel_bulk_edit'),
|
||||||
path('power-panels/delete/', views.PowerPanelBulkDeleteView.as_view(), name='powerpanel_bulk_delete'),
|
path('power-panels/delete/', views.PowerPanelBulkDeleteView.as_view(), name='powerpanel_bulk_delete'),
|
||||||
path('power-panels/<int:pk>/', views.PowerPanelView.as_view(), name='powerpanel'),
|
path('power-panels/<int:pk>/', include(get_model_urls('dcim', 'powerpanel'))),
|
||||||
path('power-panels/<int:pk>/edit/', views.PowerPanelEditView.as_view(), name='powerpanel_edit'),
|
|
||||||
path('power-panels/<int:pk>/delete/', views.PowerPanelDeleteView.as_view(), name='powerpanel_delete'),
|
|
||||||
path('power-panels/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='powerpanel_changelog', kwargs={'model': PowerPanel}),
|
|
||||||
path('power-panels/<int:pk>/journal/', ObjectJournalView.as_view(), name='powerpanel_journal', kwargs={'model': PowerPanel}),
|
|
||||||
|
|
||||||
# Power feeds
|
# Power feeds
|
||||||
path('power-feeds/', views.PowerFeedListView.as_view(), name='powerfeed_list'),
|
path('power-feeds/', views.PowerFeedListView.as_view(), name='powerfeed_list'),
|
||||||
@ -489,11 +343,6 @@ urlpatterns = [
|
|||||||
path('power-feeds/edit/', views.PowerFeedBulkEditView.as_view(), name='powerfeed_bulk_edit'),
|
path('power-feeds/edit/', views.PowerFeedBulkEditView.as_view(), name='powerfeed_bulk_edit'),
|
||||||
path('power-feeds/disconnect/', views.PowerFeedBulkDisconnectView.as_view(), name='powerfeed_bulk_disconnect'),
|
path('power-feeds/disconnect/', views.PowerFeedBulkDisconnectView.as_view(), name='powerfeed_bulk_disconnect'),
|
||||||
path('power-feeds/delete/', views.PowerFeedBulkDeleteView.as_view(), name='powerfeed_bulk_delete'),
|
path('power-feeds/delete/', views.PowerFeedBulkDeleteView.as_view(), name='powerfeed_bulk_delete'),
|
||||||
path('power-feeds/<int:pk>/', views.PowerFeedView.as_view(), name='powerfeed'),
|
path('power-feeds/<int:pk>/', include(get_model_urls('dcim', 'powerfeed'))),
|
||||||
path('power-feeds/<int:pk>/edit/', views.PowerFeedEditView.as_view(), name='powerfeed_edit'),
|
|
||||||
path('power-feeds/<int:pk>/delete/', views.PowerFeedDeleteView.as_view(), name='powerfeed_delete'),
|
|
||||||
path('power-feeds/<int:pk>/trace/', views.PathTraceView.as_view(), name='powerfeed_trace', kwargs={'model': PowerFeed}),
|
|
||||||
path('power-feeds/<int:pk>/changelog/', ObjectChangeLogView.as_view(), name='powerfeed_changelog', kwargs={'model': PowerFeed}),
|
|
||||||
path('power-feeds/<int:pk>/journal/', ObjectJournalView.as_view(), name='powerfeed_journal', kwargs={'model': PowerFeed}),
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -131,24 +131,3 @@ class ConfigRevisionAdmin(admin.ModelAdmin):
|
|||||||
})
|
})
|
||||||
|
|
||||||
return TemplateResponse(request, 'admin/extras/configrevision/restore.html', context)
|
return TemplateResponse(request, 'admin/extras/configrevision/restore.html', context)
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# Reports & scripts
|
|
||||||
#
|
|
||||||
|
|
||||||
@admin.register(JobResult)
|
|
||||||
class JobResultAdmin(admin.ModelAdmin):
|
|
||||||
list_display = [
|
|
||||||
'obj_type', 'name', 'created', 'completed', 'user', 'status',
|
|
||||||
]
|
|
||||||
fields = [
|
|
||||||
'obj_type', 'name', 'created', 'completed', 'user', 'status', 'data', 'job_id'
|
|
||||||
]
|
|
||||||
list_filter = [
|
|
||||||
'status',
|
|
||||||
]
|
|
||||||
readonly_fields = fields
|
|
||||||
|
|
||||||
def has_add_permission(self, request):
|
|
||||||
return False
|
|
||||||
|
@ -13,6 +13,7 @@ __all__ = [
|
|||||||
'NestedImageAttachmentSerializer',
|
'NestedImageAttachmentSerializer',
|
||||||
'NestedJobResultSerializer',
|
'NestedJobResultSerializer',
|
||||||
'NestedJournalEntrySerializer',
|
'NestedJournalEntrySerializer',
|
||||||
|
'NestedSavedFilterSerializer',
|
||||||
'NestedTagSerializer', # Defined in netbox.api.serializers
|
'NestedTagSerializer', # Defined in netbox.api.serializers
|
||||||
'NestedWebhookSerializer',
|
'NestedWebhookSerializer',
|
||||||
]
|
]
|
||||||
@ -58,6 +59,14 @@ class NestedExportTemplateSerializer(WritableNestedSerializer):
|
|||||||
fields = ['id', 'url', 'display', 'name']
|
fields = ['id', 'url', 'display', 'name']
|
||||||
|
|
||||||
|
|
||||||
|
class NestedSavedFilterSerializer(WritableNestedSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:savedfilter-detail')
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.SavedFilter
|
||||||
|
fields = ['id', 'url', 'display', 'name']
|
||||||
|
|
||||||
|
|
||||||
class NestedImageAttachmentSerializer(WritableNestedSerializer):
|
class NestedImageAttachmentSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='extras-api:imageattachment-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='extras-api:imageattachment-detail')
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user