mirror of
https://github.com/netbox-community/netbox.git
synced 2026-03-07 23:10:05 +01:00
Compare commits
7 Commits
21518-cf-d
...
21025-pre-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb99199340 | ||
|
|
7ec656bc7c | ||
|
|
06bbae0f84 | ||
|
|
8ff9fd26d1 | ||
|
|
a0e23ac3c9 | ||
|
|
071d4a63aa | ||
|
|
7db2739465 |
44
.github/workflows/claude-code-review.yml
vendored
Normal file
44
.github/workflows/claude-code-review.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Claude Code Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, ready_for_review, reopened]
|
||||
# Optional: Only run on specific file changes
|
||||
# paths:
|
||||
# - "src/**/*.ts"
|
||||
# - "src/**/*.tsx"
|
||||
# - "src/**/*.js"
|
||||
# - "src/**/*.jsx"
|
||||
|
||||
jobs:
|
||||
claude-review:
|
||||
# Optional: Filter by PR author
|
||||
# if: |
|
||||
# github.event.pull_request.user.login == 'external-contributor' ||
|
||||
# github.event.pull_request.user.login == 'new-developer' ||
|
||||
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code Review
|
||||
id: claude-review
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
|
||||
plugins: 'code-review@claude-code-plugins'
|
||||
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
|
||||
50
.github/workflows/claude.yml
vendored
Normal file
50
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Claude Code
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: read
|
||||
issues: read
|
||||
id-token: write
|
||||
actions: read # Required for Claude to read CI results on PRs
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
|
||||
# This is an optional setting that allows Claude to read CI results on PRs
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
|
||||
# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
|
||||
# prompt: 'Update the pull request description to include a summary of changes.'
|
||||
|
||||
# Optional: Add claude_args to customize behavior and configuration
|
||||
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
|
||||
# or https://code.claude.com/docs/en/cli-reference for available options
|
||||
# claude_args: '--allowed-tools Bash(gh pr:*)'
|
||||
|
||||
@@ -2,6 +2,7 @@ import re
|
||||
import typing
|
||||
from collections import OrderedDict
|
||||
|
||||
from drf_spectacular.contrib.django_filters import DjangoFilterExtension
|
||||
from drf_spectacular.extensions import OpenApiSerializerExtension, OpenApiSerializerFieldExtension, _SchemaType
|
||||
from drf_spectacular.openapi import AutoSchema
|
||||
from drf_spectacular.plumbing import (
|
||||
@@ -9,6 +10,7 @@ from drf_spectacular.plumbing import (
|
||||
build_choice_field,
|
||||
build_media_type_object,
|
||||
build_object_type,
|
||||
follow_field_source,
|
||||
get_doc,
|
||||
)
|
||||
from drf_spectacular.types import OpenApiTypes
|
||||
@@ -23,6 +25,29 @@ BULK_ACTIONS = ("bulk_destroy", "bulk_partial_update", "bulk_update")
|
||||
WRITABLE_ACTIONS = ("PATCH", "POST", "PUT")
|
||||
|
||||
|
||||
class NetBoxDjangoFilterExtension(DjangoFilterExtension):
|
||||
"""
|
||||
Overrides drf-spectacular's DjangoFilterExtension to fix a regression in v0.29.0 where
|
||||
_get_model_field() incorrectly double-appends to_field_name when field_name already ends
|
||||
with that value (e.g. field_name='tags__slug', to_field_name='slug' produces the invalid
|
||||
path ['tags', 'slug', 'slug']). This caused hundreds of spurious warnings during schema
|
||||
generation for filters such as TagFilter, TenancyFilterSet.tenant, and OwnerFilterMixin.owner.
|
||||
|
||||
See: https://github.com/netbox-community/netbox/issues/20787
|
||||
https://github.com/tfranzel/drf-spectacular/issues/1475
|
||||
"""
|
||||
priority = 1
|
||||
|
||||
def _get_model_field(self, filter_field, model):
|
||||
if not filter_field.field_name:
|
||||
return None
|
||||
path = filter_field.field_name.split('__')
|
||||
to_field_name = filter_field.extra.get('to_field_name')
|
||||
if to_field_name is not None and path[-1] != to_field_name:
|
||||
path.append(to_field_name)
|
||||
return follow_field_source(model, path, emit_warnings=False)
|
||||
|
||||
|
||||
class FixTimeZoneSerializerField(OpenApiSerializerFieldExtension):
|
||||
target_class = 'timezone_field.rest_framework.TimeZoneSerializerField'
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ from dcim import filtersets
|
||||
from dcim.constants import CABLE_TRACE_SVG_DEFAULT_WIDTH
|
||||
from dcim.models import *
|
||||
from dcim.svg import CableTraceSVG
|
||||
from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin
|
||||
from extras.api.mixins import RenderConfigMixin
|
||||
from netbox.api.authentication import IsAuthenticatedOrLoginNotRequired
|
||||
from netbox.api.metadata import ContentTypeMetadata
|
||||
from netbox.api.pagination import StripCountAnnotationsPaginator
|
||||
@@ -398,12 +398,7 @@ class PlatformViewSet(MPTTLockedMixin, NetBoxModelViewSet):
|
||||
# Devices/modules
|
||||
#
|
||||
|
||||
class DeviceViewSet(
|
||||
SequentialBulkCreatesMixin,
|
||||
ConfigContextQuerySetMixin,
|
||||
RenderConfigMixin,
|
||||
NetBoxModelViewSet
|
||||
):
|
||||
class DeviceViewSet(SequentialBulkCreatesMixin, RenderConfigMixin, NetBoxModelViewSet):
|
||||
queryset = Device.objects.prefetch_related(
|
||||
'parent_bay', # Referenced by DeviceSerializer.get_parent_device()
|
||||
)
|
||||
|
||||
21
netbox/dcim/migrations/0227_device_config_context_data.py
Normal file
21
netbox/dcim/migrations/0227_device_config_context_data.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('dcim', '0226_modulebay_rebuild_tree'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='device',
|
||||
name='config_context_data',
|
||||
field=models.JSONField(blank=True, editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='module',
|
||||
name='config_context_data',
|
||||
field=models.JSONField(blank=True, editable=False, null=True),
|
||||
),
|
||||
]
|
||||
@@ -2683,7 +2683,7 @@ class DeviceInventoryView(DeviceComponentsView):
|
||||
|
||||
@register_model_view(Device, 'configcontext', path='config-context')
|
||||
class DeviceConfigContextView(ObjectConfigContextView):
|
||||
queryset = Device.objects.annotate_config_context_data()
|
||||
queryset = Device.objects.all()
|
||||
base_template = 'dcim/device/base.html'
|
||||
tab = ViewTab(
|
||||
label=_('Config Context'),
|
||||
|
||||
@@ -10,34 +10,11 @@ from netbox.api.renderers import TextRenderer
|
||||
from .serializers import ConfigTemplateSerializer
|
||||
|
||||
__all__ = (
|
||||
'ConfigContextQuerySetMixin',
|
||||
'ConfigTemplateRenderMixin',
|
||||
'RenderConfigMixin',
|
||||
)
|
||||
|
||||
|
||||
class ConfigContextQuerySetMixin:
|
||||
"""
|
||||
Used by views that work with config context models (device and virtual machine).
|
||||
Provides a get_queryset() method which deals with adding the config context
|
||||
data annotation or not.
|
||||
"""
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Build the proper queryset based on the request context
|
||||
|
||||
If the `brief` query param equates to True or the `exclude` query param
|
||||
includes `config_context` as a value, return the base queryset.
|
||||
|
||||
Else, return the queryset annotated with config context data
|
||||
"""
|
||||
queryset = super().get_queryset()
|
||||
request = self.get_serializer_context()['request']
|
||||
if self.brief or 'config_context' in request.query_params.get('exclude', []):
|
||||
return queryset
|
||||
return queryset.annotate_config_context_data()
|
||||
|
||||
|
||||
class ConfigTemplateRenderMixin:
|
||||
"""
|
||||
Provides a method to return a rendered ConfigTemplate as REST API data.
|
||||
|
||||
@@ -22,19 +22,7 @@ if TYPE_CHECKING:
|
||||
@strawberry.type
|
||||
class ConfigContextMixin:
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cls, queryset, info: Info, **kwargs):
|
||||
queryset = super().get_queryset(queryset, info, **kwargs)
|
||||
|
||||
# If `config_context` is requested, call annotate_config_context_data() on the queryset
|
||||
selected = {f.name for f in info.selected_fields[0].selections}
|
||||
if 'config_context' in selected and hasattr(queryset, 'annotate_config_context_data'):
|
||||
return queryset.annotate_config_context_data()
|
||||
|
||||
return queryset
|
||||
|
||||
# Ensure `local_context_data` is fetched when `config_context` is requested
|
||||
@strawberry_django.field(only=['local_context_data'])
|
||||
@strawberry_django.field(only=['config_context_data', 'local_context_data'])
|
||||
def config_context(self) -> strawberry.scalars.JSON:
|
||||
return self.get_config_context()
|
||||
|
||||
|
||||
40
netbox/extras/management/commands/rebuild_config_context.py
Normal file
40
netbox/extras/management/commands/rebuild_config_context.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db import connection
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Rebuild pre-rendered config context data for all devices and/or virtual machines'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
'--devices-only',
|
||||
action='store_true',
|
||||
help='Only rebuild config context data for devices',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--vms-only',
|
||||
action='store_true',
|
||||
help='Only rebuild config context data for virtual machines',
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
devices_only = options['devices_only']
|
||||
vms_only = options['vms_only']
|
||||
|
||||
with connection.cursor() as cursor:
|
||||
if not vms_only:
|
||||
self.stdout.write('Rebuilding config context data for devices...')
|
||||
cursor.execute(
|
||||
'UPDATE dcim_device SET config_context_data = compute_config_context_for_device(id)'
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f' Updated {cursor.rowcount} devices'))
|
||||
|
||||
if not devices_only:
|
||||
self.stdout.write('Rebuilding config context data for virtual machines...')
|
||||
cursor.execute(
|
||||
'UPDATE virtualization_virtualmachine '
|
||||
'SET config_context_data = compute_config_context_for_vm(id)'
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f' Updated {cursor.rowcount} virtual machines'))
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Done.'))
|
||||
1112
netbox/extras/migrations/0135_config_context_triggers.py
Normal file
1112
netbox/extras/migrations/0135_config_context_triggers.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -225,6 +225,11 @@ class ConfigContextModel(models.Model):
|
||||
"Local config context data takes precedence over source contexts in the final rendered config context"
|
||||
)
|
||||
)
|
||||
config_context_data = models.JSONField(
|
||||
blank=True,
|
||||
null=True,
|
||||
editable=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -234,19 +239,21 @@ class ConfigContextModel(models.Model):
|
||||
Compile all config data, overwriting lower-weight values with higher-weight values where a collision occurs.
|
||||
Return the rendered configuration context for a device or VM.
|
||||
"""
|
||||
data = {}
|
||||
# Use pre-rendered cached field if available
|
||||
if self.config_context_data is not None:
|
||||
return self.config_context_data
|
||||
|
||||
if not hasattr(self, 'config_context_data'):
|
||||
# The annotation is not available, so we fall back to manually querying for the config context objects
|
||||
config_context_data = ConfigContext.objects.get_for_object(self, aggregate_data=True) or []
|
||||
# Fall back to annotation if queryset was annotated
|
||||
data = {}
|
||||
if hasattr(self, '_annotated_config_context_data'):
|
||||
config_context_data = self._annotated_config_context_data or []
|
||||
else:
|
||||
# The attribute may exist, but the annotated value could be None if there is no config context data
|
||||
config_context_data = self.config_context_data or []
|
||||
# Last resort: compute on-the-fly
|
||||
config_context_data = ConfigContext.objects.get_for_object(self, aggregate_data=True) or []
|
||||
|
||||
for context in config_context_data:
|
||||
data = deepmerge(data, context)
|
||||
|
||||
# If the object has local config context data defined, merge it last
|
||||
if self.local_context_data:
|
||||
data = deepmerge(data, self.local_context_data)
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
|
||||
"""
|
||||
from extras.models import ConfigContext
|
||||
return self.annotate(
|
||||
config_context_data=Subquery(
|
||||
_annotated_config_context_data=Subquery(
|
||||
ConfigContext.objects.filter(
|
||||
self._get_config_context_filters()
|
||||
).annotate(
|
||||
|
||||
@@ -206,6 +206,7 @@ class ConfigContextTest(TestCase):
|
||||
"b": 456,
|
||||
"c": 777
|
||||
}
|
||||
device.refresh_from_db()
|
||||
self.assertEqual(device.get_config_context(), expected_data)
|
||||
|
||||
def test_name_ordering_after_weight(self):
|
||||
@@ -235,6 +236,7 @@ class ConfigContextTest(TestCase):
|
||||
"b": 456,
|
||||
"c": 789
|
||||
}
|
||||
device.refresh_from_db()
|
||||
self.assertEqual(device.get_config_context(), expected_data)
|
||||
|
||||
def test_schema_validation(self):
|
||||
@@ -303,6 +305,7 @@ class ConfigContextTest(TestCase):
|
||||
)
|
||||
ConfigContext.objects.bulk_create([context1, context2, context3, context4])
|
||||
|
||||
device.refresh_from_db()
|
||||
annotated_queryset = Device.objects.filter(name=device.name).annotate_config_context_data()
|
||||
self.assertEqual(device.get_config_context(), annotated_queryset[0].get_config_context())
|
||||
|
||||
@@ -666,7 +669,7 @@ class ConfigContextTest(TestCase):
|
||||
self.assertFalse(queryset.query.distinct)
|
||||
|
||||
# Check that tag subqueries DO use DISTINCT by inspecting the annotation
|
||||
config_annotation = queryset.query.annotations.get('config_context_data')
|
||||
config_annotation = queryset.query.annotations.get('_annotated_config_context_data')
|
||||
self.assertIsNotNone(config_annotation)
|
||||
|
||||
def find_tag_subqueries(where_node):
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
{% load i18n %}
|
||||
<a href="{{ value.get_absolute_url }}"{% if name %} id="attr_{{ name }}"{% endif %}>{{ value.address.ip }}</a>
|
||||
{% if value.nat_inside %}
|
||||
({% trans "NAT for" %} <a href="{{ value.nat_inside.get_absolute_url }}">{{ value.nat_inside.address.ip }}</a>)
|
||||
{% elif value.nat_outside.exists %}
|
||||
({% trans "NAT" %}: {% for nat in value.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
|
||||
{% endif %}
|
||||
<span>
|
||||
<a href="{{ value.get_absolute_url }}"{% if name %} id="attr_{{ name }}"{% endif %}>{{ value.address.ip }}</a>
|
||||
{% if value.nat_inside %}
|
||||
({% trans "NAT for" %} <a href="{{ value.nat_inside.get_absolute_url }}">{{ value.nat_inside.address.ip }}</a>)
|
||||
{% elif value.nat_outside.exists %}
|
||||
({% trans "NAT" %}: {% for nat in value.nat_outside.all %}<a href="{{ nat.get_absolute_url }}">{{ nat.address.ip }}</a>{% if not forloop.last %}, {% endif %}{% endfor %})
|
||||
{% endif %}
|
||||
</span>
|
||||
<a class="btn btn-sm btn-primary copy-content" data-clipboard-target="#attr_{{ name }}" title="{% trans "Copy to clipboard" %}">
|
||||
<i class="mdi mdi-content-copy"></i>
|
||||
</a>
|
||||
|
||||
@@ -8,7 +8,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2026-02-21 05:16+0000\n"
|
||||
"POT-Creation-Date: 2026-02-28 05:11+0000\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
@@ -41,9 +41,9 @@ msgstr ""
|
||||
|
||||
#: netbox/circuits/choices.py:21 netbox/dcim/choices.py:20
|
||||
#: netbox/dcim/choices.py:102 netbox/dcim/choices.py:204
|
||||
#: netbox/dcim/choices.py:257 netbox/dcim/choices.py:1929
|
||||
#: netbox/dcim/choices.py:1987 netbox/dcim/choices.py:2054
|
||||
#: netbox/dcim/choices.py:2076 netbox/virtualization/choices.py:20
|
||||
#: netbox/dcim/choices.py:257 netbox/dcim/choices.py:1933
|
||||
#: netbox/dcim/choices.py:1991 netbox/dcim/choices.py:2058
|
||||
#: netbox/dcim/choices.py:2080 netbox/virtualization/choices.py:20
|
||||
#: netbox/virtualization/choices.py:46 netbox/vpn/choices.py:18
|
||||
#: netbox/vpn/choices.py:281
|
||||
msgid "Planned"
|
||||
@@ -57,8 +57,8 @@ msgstr ""
|
||||
#: netbox/core/tables/tasks.py:23 netbox/dcim/choices.py:22
|
||||
#: netbox/dcim/choices.py:103 netbox/dcim/choices.py:155
|
||||
#: netbox/dcim/choices.py:203 netbox/dcim/choices.py:256
|
||||
#: netbox/dcim/choices.py:1986 netbox/dcim/choices.py:2053
|
||||
#: netbox/dcim/choices.py:2075 netbox/extras/tables/tables.py:642
|
||||
#: netbox/dcim/choices.py:1990 netbox/dcim/choices.py:2057
|
||||
#: netbox/dcim/choices.py:2079 netbox/extras/tables/tables.py:642
|
||||
#: netbox/ipam/choices.py:31 netbox/ipam/choices.py:49
|
||||
#: netbox/ipam/choices.py:69 netbox/ipam/choices.py:154
|
||||
#: netbox/templates/extras/configcontext.html:29
|
||||
@@ -70,8 +70,8 @@ msgid "Active"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/circuits/choices.py:24 netbox/dcim/choices.py:202
|
||||
#: netbox/dcim/choices.py:255 netbox/dcim/choices.py:1985
|
||||
#: netbox/dcim/choices.py:2055 netbox/dcim/choices.py:2074
|
||||
#: netbox/dcim/choices.py:255 netbox/dcim/choices.py:1989
|
||||
#: netbox/dcim/choices.py:2059 netbox/dcim/choices.py:2078
|
||||
#: netbox/virtualization/choices.py:24 netbox/virtualization/choices.py:44
|
||||
msgid "Offline"
|
||||
msgstr ""
|
||||
@@ -84,7 +84,7 @@ msgstr ""
|
||||
msgid "Decommissioned"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/circuits/choices.py:90 netbox/dcim/choices.py:1998
|
||||
#: netbox/circuits/choices.py:90 netbox/dcim/choices.py:2002
|
||||
#: netbox/dcim/tables/devices.py:1208 netbox/templates/dcim/interface.html:148
|
||||
#: netbox/tenancy/choices.py:17
|
||||
msgid "Primary"
|
||||
@@ -1995,7 +1995,7 @@ msgstr ""
|
||||
#: netbox/core/choices.py:22 netbox/core/choices.py:59
|
||||
#: netbox/core/constants.py:21 netbox/core/tables/tasks.py:35
|
||||
#: netbox/dcim/choices.py:206 netbox/dcim/choices.py:259
|
||||
#: netbox/dcim/choices.py:1988 netbox/dcim/choices.py:2078
|
||||
#: netbox/dcim/choices.py:1992 netbox/dcim/choices.py:2082
|
||||
#: netbox/virtualization/choices.py:48
|
||||
msgid "Failed"
|
||||
msgstr ""
|
||||
@@ -2181,7 +2181,7 @@ msgid "User name"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/core/forms/bulk_edit.py:25 netbox/core/forms/filtersets.py:47
|
||||
#: netbox/core/tables/data.py:28 netbox/dcim/choices.py:2036
|
||||
#: netbox/core/tables/data.py:28 netbox/dcim/choices.py:2040
|
||||
#: netbox/dcim/forms/bulk_edit.py:1105 netbox/dcim/forms/bulk_edit.py:1386
|
||||
#: netbox/dcim/forms/filtersets.py:1619 netbox/dcim/forms/filtersets.py:1712
|
||||
#: netbox/dcim/tables/devices.py:581 netbox/dcim/tables/devicetypes.py:233
|
||||
@@ -2375,7 +2375,7 @@ msgstr ""
|
||||
msgid "Rack Elevations"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/core/forms/model_forms.py:160 netbox/dcim/choices.py:1907
|
||||
#: netbox/core/forms/model_forms.py:160 netbox/dcim/choices.py:1911
|
||||
#: netbox/dcim/forms/bulk_edit.py:944 netbox/dcim/forms/bulk_edit.py:1340
|
||||
#: netbox/dcim/forms/bulk_edit.py:1361 netbox/dcim/tables/racks.py:144
|
||||
#: netbox/netbox/navigation/menu.py:316 netbox/netbox/navigation/menu.py:320
|
||||
@@ -3041,8 +3041,8 @@ msgid "Staging"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:23 netbox/dcim/choices.py:208
|
||||
#: netbox/dcim/choices.py:260 netbox/dcim/choices.py:1930
|
||||
#: netbox/dcim/choices.py:2079 netbox/virtualization/choices.py:23
|
||||
#: netbox/dcim/choices.py:260 netbox/dcim/choices.py:1934
|
||||
#: netbox/dcim/choices.py:2083 netbox/virtualization/choices.py:23
|
||||
#: netbox/virtualization/choices.py:49 netbox/vpn/choices.py:282
|
||||
msgid "Decommissioning"
|
||||
msgstr ""
|
||||
@@ -3108,7 +3108,7 @@ msgstr ""
|
||||
msgid "Millimeters"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:115 netbox/dcim/choices.py:1952
|
||||
#: netbox/dcim/choices.py:115 netbox/dcim/choices.py:1956
|
||||
msgid "Inches"
|
||||
msgstr ""
|
||||
|
||||
@@ -3186,7 +3186,7 @@ msgid "Rear"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:205 netbox/dcim/choices.py:258
|
||||
#: netbox/dcim/choices.py:2077 netbox/virtualization/choices.py:47
|
||||
#: netbox/dcim/choices.py:2081 netbox/virtualization/choices.py:47
|
||||
msgid "Staged"
|
||||
msgstr ""
|
||||
|
||||
@@ -3219,7 +3219,7 @@ msgid "Top to bottom"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:235 netbox/dcim/choices.py:280
|
||||
#: netbox/dcim/choices.py:1562
|
||||
#: netbox/dcim/choices.py:1566
|
||||
msgid "Passive"
|
||||
msgstr ""
|
||||
|
||||
@@ -3248,8 +3248,8 @@ msgid "Proprietary"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:606 netbox/dcim/choices.py:853
|
||||
#: netbox/dcim/choices.py:1474 netbox/dcim/choices.py:1476
|
||||
#: netbox/dcim/choices.py:1712 netbox/dcim/choices.py:1714
|
||||
#: netbox/dcim/choices.py:1478 netbox/dcim/choices.py:1480
|
||||
#: netbox/dcim/choices.py:1716 netbox/dcim/choices.py:1718
|
||||
#: netbox/netbox/navigation/menu.py:212
|
||||
msgid "Other"
|
||||
msgstr ""
|
||||
@@ -3262,11 +3262,11 @@ msgstr ""
|
||||
msgid "Physical"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:884 netbox/dcim/choices.py:1151
|
||||
#: netbox/dcim/choices.py:884 netbox/dcim/choices.py:1153
|
||||
msgid "Virtual"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:885 netbox/dcim/choices.py:1351
|
||||
#: netbox/dcim/choices.py:885 netbox/dcim/choices.py:1355
|
||||
#: netbox/dcim/forms/bulk_edit.py:1546 netbox/dcim/forms/filtersets.py:1577
|
||||
#: netbox/dcim/forms/filtersets.py:1703 netbox/dcim/forms/model_forms.py:1125
|
||||
#: netbox/dcim/forms/model_forms.py:1589 netbox/netbox/navigation/menu.py:150
|
||||
@@ -3275,11 +3275,11 @@ msgstr ""
|
||||
msgid "Wireless"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1149
|
||||
#: netbox/dcim/choices.py:1151
|
||||
msgid "Virtual interfaces"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1152 netbox/dcim/forms/bulk_edit.py:1399
|
||||
#: netbox/dcim/choices.py:1154 netbox/dcim/forms/bulk_edit.py:1399
|
||||
#: netbox/dcim/forms/bulk_import.py:949 netbox/dcim/forms/model_forms.py:1107
|
||||
#: netbox/dcim/tables/devices.py:741 netbox/templates/dcim/interface.html:112
|
||||
#: netbox/virtualization/forms/bulk_edit.py:177
|
||||
@@ -3288,67 +3288,67 @@ msgstr ""
|
||||
msgid "Bridge"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1153
|
||||
#: netbox/dcim/choices.py:1155
|
||||
msgid "Link Aggregation Group (LAG)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1157
|
||||
#: netbox/dcim/choices.py:1159
|
||||
msgid "FastEthernet (100 Mbps)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1166
|
||||
#: netbox/dcim/choices.py:1168
|
||||
msgid "GigabitEthernet (1 Gbps)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1184
|
||||
#: netbox/dcim/choices.py:1186
|
||||
msgid "2.5/5 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1191
|
||||
#: netbox/dcim/choices.py:1193
|
||||
msgid "10 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1206
|
||||
#: netbox/dcim/choices.py:1209
|
||||
msgid "25 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1216
|
||||
#: netbox/dcim/choices.py:1219
|
||||
msgid "40 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1226
|
||||
#: netbox/dcim/choices.py:1230
|
||||
msgid "50 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1236
|
||||
#: netbox/dcim/choices.py:1240
|
||||
msgid "100 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1257
|
||||
#: netbox/dcim/choices.py:1261
|
||||
msgid "200 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1271
|
||||
#: netbox/dcim/choices.py:1275
|
||||
msgid "400 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1289
|
||||
#: netbox/dcim/choices.py:1293
|
||||
msgid "800 Gbps Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1298
|
||||
#: netbox/dcim/choices.py:1302
|
||||
msgid "Pluggable transceivers"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1335
|
||||
#: netbox/dcim/choices.py:1339
|
||||
msgid "Backplane Ethernet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1367
|
||||
#: netbox/dcim/choices.py:1371
|
||||
msgid "Cellular"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1419 netbox/dcim/forms/filtersets.py:425
|
||||
#: netbox/dcim/choices.py:1423 netbox/dcim/forms/filtersets.py:425
|
||||
#: netbox/dcim/forms/filtersets.py:911 netbox/dcim/forms/filtersets.py:1112
|
||||
#: netbox/dcim/forms/filtersets.py:1910
|
||||
#: netbox/templates/dcim/inventoryitem.html:56
|
||||
@@ -3356,255 +3356,255 @@ msgstr ""
|
||||
msgid "Serial"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1434
|
||||
#: netbox/dcim/choices.py:1438
|
||||
msgid "Coaxial"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1455
|
||||
#: netbox/dcim/choices.py:1459
|
||||
msgid "Stacking"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1507
|
||||
#: netbox/dcim/choices.py:1511
|
||||
msgid "Half"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1508
|
||||
#: netbox/dcim/choices.py:1512
|
||||
msgid "Full"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1509 netbox/netbox/preferences.py:32
|
||||
#: netbox/dcim/choices.py:1513 netbox/netbox/preferences.py:32
|
||||
#: netbox/wireless/choices.py:480
|
||||
msgid "Auto"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1521
|
||||
#: netbox/dcim/choices.py:1525
|
||||
msgid "Access"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1522 netbox/ipam/tables/vlans.py:150
|
||||
#: netbox/dcim/choices.py:1526 netbox/ipam/tables/vlans.py:150
|
||||
#: netbox/ipam/tables/vlans.py:210
|
||||
#: netbox/templates/dcim/inc/interface_vlans_table.html:7
|
||||
msgid "Tagged"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1523
|
||||
#: netbox/dcim/choices.py:1527
|
||||
msgid "Tagged (All)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1524 netbox/templates/ipam/vlan_edit.html:26
|
||||
#: netbox/dcim/choices.py:1528 netbox/templates/ipam/vlan_edit.html:26
|
||||
msgid "Q-in-Q (802.1ad)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1553
|
||||
#: netbox/dcim/choices.py:1557
|
||||
msgid "IEEE Standard"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1564
|
||||
#: netbox/dcim/choices.py:1568
|
||||
msgid "Passive 24V (2-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1565
|
||||
#: netbox/dcim/choices.py:1569
|
||||
msgid "Passive 24V (4-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1566
|
||||
#: netbox/dcim/choices.py:1570
|
||||
msgid "Passive 48V (2-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1567
|
||||
#: netbox/dcim/choices.py:1571
|
||||
msgid "Passive 48V (4-pair)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1640
|
||||
#: netbox/dcim/choices.py:1644
|
||||
msgid "Copper"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1663
|
||||
#: netbox/dcim/choices.py:1667
|
||||
msgid "Fiber Optic"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1699 netbox/dcim/choices.py:1913
|
||||
#: netbox/dcim/choices.py:1703 netbox/dcim/choices.py:1917
|
||||
msgid "USB"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1755
|
||||
#: netbox/dcim/choices.py:1759
|
||||
msgid "Single"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1757
|
||||
#: netbox/dcim/choices.py:1761
|
||||
msgid "1C1P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1758
|
||||
#: netbox/dcim/choices.py:1762
|
||||
msgid "1C2P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1759
|
||||
#: netbox/dcim/choices.py:1763
|
||||
msgid "1C4P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1760
|
||||
#: netbox/dcim/choices.py:1764
|
||||
msgid "1C6P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1761
|
||||
#: netbox/dcim/choices.py:1765
|
||||
msgid "1C8P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1762
|
||||
#: netbox/dcim/choices.py:1766
|
||||
msgid "1C12P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1763
|
||||
#: netbox/dcim/choices.py:1767
|
||||
msgid "1C16P"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1767
|
||||
#: netbox/dcim/choices.py:1771
|
||||
msgid "Trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1769
|
||||
#: netbox/dcim/choices.py:1773
|
||||
msgid "2C1P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1770
|
||||
#: netbox/dcim/choices.py:1774
|
||||
msgid "2C2P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1771
|
||||
#: netbox/dcim/choices.py:1775
|
||||
msgid "2C4P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1772
|
||||
#: netbox/dcim/choices.py:1776
|
||||
msgid "2C4P trunk (shuffle)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1773
|
||||
#: netbox/dcim/choices.py:1777
|
||||
msgid "2C6P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1774
|
||||
#: netbox/dcim/choices.py:1778
|
||||
msgid "2C8P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1775
|
||||
#: netbox/dcim/choices.py:1779
|
||||
msgid "2C12P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1776
|
||||
#: netbox/dcim/choices.py:1780
|
||||
msgid "4C1P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1777
|
||||
#: netbox/dcim/choices.py:1781
|
||||
msgid "4C2P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1778
|
||||
#: netbox/dcim/choices.py:1782
|
||||
msgid "4C4P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1779
|
||||
#: netbox/dcim/choices.py:1783
|
||||
msgid "4C4P trunk (shuffle)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1780
|
||||
#: netbox/dcim/choices.py:1784
|
||||
msgid "4C6P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1781
|
||||
#: netbox/dcim/choices.py:1785
|
||||
msgid "4C8P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1782
|
||||
#: netbox/dcim/choices.py:1786
|
||||
msgid "8C4P trunk"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1786
|
||||
#: netbox/dcim/choices.py:1790
|
||||
msgid "Breakout"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1788
|
||||
#: netbox/dcim/choices.py:1792
|
||||
msgid "1C4P:4C1P breakout"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1789
|
||||
#: netbox/dcim/choices.py:1793
|
||||
msgid "1C6P:6C1P breakout"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1790
|
||||
#: netbox/dcim/choices.py:1794
|
||||
msgid "2C4P:8C1P breakout (shuffle)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1848
|
||||
#: netbox/dcim/choices.py:1852
|
||||
msgid "Copper - Twisted Pair (UTP/STP)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1862
|
||||
#: netbox/dcim/choices.py:1866
|
||||
msgid "Copper - Twinax (DAC)"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1869
|
||||
#: netbox/dcim/choices.py:1873
|
||||
msgid "Copper - Coaxial"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1884
|
||||
#: netbox/dcim/choices.py:1888
|
||||
msgid "Fiber - Multimode"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1895
|
||||
#: netbox/dcim/choices.py:1899
|
||||
msgid "Fiber - Single-mode"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1903
|
||||
#: netbox/dcim/choices.py:1907
|
||||
msgid "Fiber - Other"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1928 netbox/dcim/forms/filtersets.py:1402
|
||||
#: netbox/dcim/choices.py:1932 netbox/dcim/forms/filtersets.py:1402
|
||||
msgid "Connected"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1947 netbox/netbox/choices.py:177
|
||||
#: netbox/dcim/choices.py:1951 netbox/netbox/choices.py:177
|
||||
msgid "Kilometers"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1948 netbox/netbox/choices.py:178
|
||||
#: netbox/dcim/choices.py:1952 netbox/netbox/choices.py:178
|
||||
#: netbox/templates/dcim/cable_trace.html:65
|
||||
msgid "Meters"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1949
|
||||
#: netbox/dcim/choices.py:1953
|
||||
msgid "Centimeters"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1950 netbox/netbox/choices.py:179
|
||||
#: netbox/dcim/choices.py:1954 netbox/netbox/choices.py:179
|
||||
msgid "Miles"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1951 netbox/netbox/choices.py:180
|
||||
#: netbox/dcim/choices.py:1955 netbox/netbox/choices.py:180
|
||||
#: netbox/templates/dcim/cable_trace.html:66
|
||||
msgid "Feet"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:1999
|
||||
#: netbox/dcim/choices.py:2003
|
||||
msgid "Redundant"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2020
|
||||
#: netbox/dcim/choices.py:2024
|
||||
msgid "Single phase"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2021
|
||||
#: netbox/dcim/choices.py:2025
|
||||
msgid "Three-phase"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2037 netbox/extras/choices.py:53
|
||||
#: netbox/dcim/choices.py:2041 netbox/extras/choices.py:53
|
||||
#: netbox/netbox/preferences.py:45 netbox/netbox/preferences.py:70
|
||||
#: netbox/templates/extras/customfield.html:78 netbox/vpn/choices.py:20
|
||||
#: netbox/wireless/choices.py:27
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/dcim/choices.py:2038
|
||||
#: netbox/dcim/choices.py:2042
|
||||
msgid "Faulty"
|
||||
msgstr ""
|
||||
|
||||
@@ -16677,7 +16677,7 @@ msgstr ""
|
||||
msgid "A column named {name} is already defined for table {table_name}"
|
||||
msgstr ""
|
||||
|
||||
#: netbox/utilities/templates/builtins/customfield_value.html:30
|
||||
#: netbox/utilities/templates/builtins/customfield_value.html:32
|
||||
msgid "Not defined"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
{% load i18n %}
|
||||
{% if customfield.type == 'integer' and value is not None %}
|
||||
{{ value }}
|
||||
{% elif customfield.type == 'decimal' and value is not None %}
|
||||
{{ value }}
|
||||
{% elif customfield.type == 'longtext' and value %}
|
||||
{{ value|markdown }}
|
||||
{% elif customfield.type == 'boolean' and value == True %}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from django.db.models import Sum
|
||||
from rest_framework.routers import APIRootView
|
||||
|
||||
from extras.api.mixins import ConfigContextQuerySetMixin, RenderConfigMixin
|
||||
from extras.api.mixins import RenderConfigMixin
|
||||
from netbox.api.viewsets import NetBoxModelViewSet
|
||||
from utilities.query_functions import CollateAsChar
|
||||
from virtualization import filtersets
|
||||
@@ -48,7 +48,7 @@ class ClusterViewSet(NetBoxModelViewSet):
|
||||
# Virtual machines
|
||||
#
|
||||
|
||||
class VirtualMachineViewSet(ConfigContextQuerySetMixin, RenderConfigMixin, NetBoxModelViewSet):
|
||||
class VirtualMachineViewSet(RenderConfigMixin, NetBoxModelViewSet):
|
||||
queryset = VirtualMachine.objects.all()
|
||||
filterset_class = filtersets.VirtualMachineFilterSet
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('virtualization', '0052_gfk_indexes'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='virtualmachine',
|
||||
name='config_context_data',
|
||||
field=models.JSONField(blank=True, editable=False, null=True),
|
||||
),
|
||||
]
|
||||
@@ -487,7 +487,7 @@ class VirtualMachineVirtualDisksView(generic.ObjectChildrenView):
|
||||
|
||||
@register_model_view(VirtualMachine, 'configcontext', path='config-context')
|
||||
class VirtualMachineConfigContextView(ObjectConfigContextView):
|
||||
queryset = VirtualMachine.objects.annotate_config_context_data()
|
||||
queryset = VirtualMachine.objects.all()
|
||||
base_template = 'virtualization/virtualmachine.html'
|
||||
tab = ViewTab(
|
||||
label=_('Config Context'),
|
||||
|
||||
Reference in New Issue
Block a user