mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-26 09:16:10 -06:00
12552 initial removal of mptt
This commit is contained in:
parent
4208b79514
commit
da0c459e73
@ -26,9 +26,9 @@ django-filter
|
|||||||
# https://github.com/flavors/django-graphiql-debug-toolbar/blob/main/CHANGES.rst
|
# https://github.com/flavors/django-graphiql-debug-toolbar/blob/main/CHANGES.rst
|
||||||
django-graphiql-debug-toolbar
|
django-graphiql-debug-toolbar
|
||||||
|
|
||||||
# Modified Preorder Tree Traversal (recursive nesting of objects)
|
# Adjacency-list trees for Django using recursive common table expressions.
|
||||||
# https://github.com/django-mptt/django-mptt/blob/main/CHANGELOG.rst
|
# https://github.com/matthiask/django-tree-queries/blob/main/CHANGELOG.rst
|
||||||
django-mptt
|
django-tree-queries
|
||||||
|
|
||||||
# Context managers for PostgreSQL advisory locks
|
# Context managers for PostgreSQL advisory locks
|
||||||
# https://github.com/Xof/django-pglocks/blob/master/CHANGES.txt
|
# https://github.com/Xof/django-pglocks/blob/master/CHANGES.txt
|
||||||
|
@ -60,7 +60,7 @@ __all__ = [
|
|||||||
class NestedRegionSerializer(WritableNestedSerializer):
|
class NestedRegionSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
|
||||||
site_count = serializers.IntegerField(read_only=True)
|
site_count = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Region
|
model = models.Region
|
||||||
@ -73,7 +73,7 @@ class NestedRegionSerializer(WritableNestedSerializer):
|
|||||||
class NestedSiteGroupSerializer(WritableNestedSerializer):
|
class NestedSiteGroupSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:sitegroup-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:sitegroup-detail')
|
||||||
site_count = serializers.IntegerField(read_only=True)
|
site_count = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.SiteGroup
|
model = models.SiteGroup
|
||||||
@ -98,7 +98,7 @@ class NestedSiteSerializer(WritableNestedSerializer):
|
|||||||
class NestedLocationSerializer(WritableNestedSerializer):
|
class NestedLocationSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:location-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:location-detail')
|
||||||
rack_count = serializers.IntegerField(read_only=True)
|
rack_count = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.Location
|
model = models.Location
|
||||||
@ -258,7 +258,7 @@ class NestedDeviceBayTemplateSerializer(WritableNestedSerializer):
|
|||||||
|
|
||||||
class NestedInventoryItemTemplateSerializer(WritableNestedSerializer):
|
class NestedInventoryItemTemplateSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemtemplate-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemtemplate-detail')
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.InventoryItemTemplate
|
model = models.InventoryItemTemplate
|
||||||
@ -433,7 +433,7 @@ class NestedDeviceBaySerializer(WritableNestedSerializer):
|
|||||||
class NestedInventoryItemSerializer(WritableNestedSerializer):
|
class NestedInventoryItemSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
|
||||||
device = NestedDeviceSerializer(read_only=True)
|
device = NestedDeviceSerializer(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.InventoryItem
|
model = models.InventoryItem
|
||||||
|
@ -589,7 +589,7 @@ class InventoryItemTemplateSerializer(ValidatedModelSerializer):
|
|||||||
allow_null=True
|
allow_null=True
|
||||||
)
|
)
|
||||||
component = serializers.SerializerMethodField(read_only=True)
|
component = serializers.SerializerMethodField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItemTemplate
|
model = InventoryItemTemplate
|
||||||
@ -1023,7 +1023,7 @@ class InventoryItemSerializer(NetBoxModelSerializer):
|
|||||||
allow_null=True
|
allow_null=True
|
||||||
)
|
)
|
||||||
component = serializers.SerializerMethodField(read_only=True)
|
component = serializers.SerializerMethodField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
|
@ -99,13 +99,14 @@ class PassThroughPortMixin(object):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RegionViewSet(NetBoxModelViewSet):
|
class RegionViewSet(NetBoxModelViewSet):
|
||||||
queryset = Region.objects.add_related_count(
|
queryset = Region.objects.all().prefetch_related('tags')
|
||||||
Region.objects.all(),
|
# queryset = Region.objects.add_related_count(
|
||||||
Site,
|
# Region.objects.all(),
|
||||||
'region',
|
# Site,
|
||||||
'site_count',
|
# 'region',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
).prefetch_related('tags')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('tags')
|
||||||
serializer_class = serializers.RegionSerializer
|
serializer_class = serializers.RegionSerializer
|
||||||
filterset_class = filtersets.RegionFilterSet
|
filterset_class = filtersets.RegionFilterSet
|
||||||
|
|
||||||
@ -115,13 +116,14 @@ class RegionViewSet(NetBoxModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SiteGroupViewSet(NetBoxModelViewSet):
|
class SiteGroupViewSet(NetBoxModelViewSet):
|
||||||
queryset = SiteGroup.objects.add_related_count(
|
queryset = SiteGroup.objects.all().prefetch_related('tags')
|
||||||
SiteGroup.objects.all(),
|
# queryset = SiteGroup.objects.add_related_count(
|
||||||
Site,
|
# SiteGroup.objects.all(),
|
||||||
'group',
|
# Site,
|
||||||
'site_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
).prefetch_related('tags')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('tags')
|
||||||
serializer_class = serializers.SiteGroupSerializer
|
serializer_class = serializers.SiteGroupSerializer
|
||||||
filterset_class = filtersets.SiteGroupFilterSet
|
filterset_class = filtersets.SiteGroupFilterSet
|
||||||
|
|
||||||
@ -150,19 +152,20 @@ class SiteViewSet(NetBoxModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class LocationViewSet(NetBoxModelViewSet):
|
class LocationViewSet(NetBoxModelViewSet):
|
||||||
queryset = Location.objects.add_related_count(
|
queryset = Location.objects.all().prefetch_related('site', 'tags')
|
||||||
Location.objects.add_related_count(
|
# queryset = Location.objects.add_related_count(
|
||||||
Location.objects.all(),
|
# Location.objects.add_related_count(
|
||||||
Device,
|
# Location.objects.all(),
|
||||||
'location',
|
# Device,
|
||||||
'device_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'device_count',
|
||||||
),
|
# cumulative=True
|
||||||
Rack,
|
# ),
|
||||||
'location',
|
# Rack,
|
||||||
'rack_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'rack_count',
|
||||||
).prefetch_related('site', 'tags')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('site', 'tags')
|
||||||
serializer_class = serializers.LocationSerializer
|
serializer_class = serializers.LocationSerializer
|
||||||
filterset_class = filtersets.LocationFilterSet
|
filterset_class = filtersets.LocationFilterSet
|
||||||
|
|
||||||
|
@ -0,0 +1,148 @@
|
|||||||
|
# Generated by Django 4.1.8 on 2023-05-18 20:20
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('dcim', '0173_remove_napalm_fields'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitemtemplate',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitemtemplate',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitemtemplate',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='inventoryitemtemplate',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='location',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='location',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='location',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='location',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='region',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='region',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='region',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='region',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='sitegroup',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='sitegroup',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='sitegroup',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='sitegroup',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='inventoryitem',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='dcim.inventoryitem',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='inventoryitemtemplate',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='dcim.inventoryitemtemplate',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='location',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='dcim.location',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='region',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='dcim.region',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='sitegroup',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='dcim.sitegroup',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -4,14 +4,14 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from tree_queries.models import TreeNode
|
||||||
|
|
||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
from netbox.models import ChangeLoggedModel
|
from netbox.models import ChangeLoggedModel
|
||||||
from utilities.fields import ColorField, NaturalOrderingField
|
from utilities.fields import ColorField, NaturalOrderingField
|
||||||
from utilities.mptt import TreeManager
|
|
||||||
from utilities.ordering import naturalize_interface
|
from utilities.ordering import naturalize_interface
|
||||||
|
from utilities.tree_queries import TreeManager
|
||||||
from .device_components import (
|
from .device_components import (
|
||||||
ConsolePort, ConsoleServerPort, DeviceBay, FrontPort, Interface, InventoryItem, ModuleBay, PowerOutlet, PowerPort,
|
ConsolePort, ConsoleServerPort, DeviceBay, FrontPort, Interface, InventoryItem, ModuleBay, PowerOutlet, PowerPort,
|
||||||
RearPort,
|
RearPort,
|
||||||
@ -618,18 +618,10 @@ class DeviceBayTemplate(ComponentTemplateModel):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemTemplate(MPTTModel, ComponentTemplateModel):
|
class InventoryItemTemplate(TreeNode, ComponentTemplateModel):
|
||||||
"""
|
"""
|
||||||
A template for an InventoryItem to be created for a new parent Device.
|
A template for an InventoryItem to be created for a new parent Device.
|
||||||
"""
|
"""
|
||||||
parent = TreeForeignKey(
|
|
||||||
to='self',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='child_items',
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
db_index=True
|
|
||||||
)
|
|
||||||
component_type = models.ForeignKey(
|
component_type = models.ForeignKey(
|
||||||
to=ContentType,
|
to=ContentType,
|
||||||
limit_choices_to=MODULAR_COMPONENT_TEMPLATE_MODELS,
|
limit_choices_to=MODULAR_COMPONENT_TEMPLATE_MODELS,
|
||||||
|
@ -8,7 +8,7 @@ from django.db import models
|
|||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from tree_queries.models import TreeNode
|
||||||
|
|
||||||
from dcim.choices import *
|
from dcim.choices import *
|
||||||
from dcim.constants import *
|
from dcim.constants import *
|
||||||
@ -16,9 +16,9 @@ from dcim.fields import MACAddressField, WWNField
|
|||||||
from netbox.models import OrganizationalModel, NetBoxModel
|
from netbox.models import OrganizationalModel, NetBoxModel
|
||||||
from utilities.choices import ColorChoices
|
from utilities.choices import ColorChoices
|
||||||
from utilities.fields import ColorField, NaturalOrderingField
|
from utilities.fields import ColorField, NaturalOrderingField
|
||||||
from utilities.mptt import TreeManager
|
|
||||||
from utilities.ordering import naturalize_interface
|
from utilities.ordering import naturalize_interface
|
||||||
from utilities.query_functions import CollateAsChar
|
from utilities.query_functions import CollateAsChar
|
||||||
|
from utilities.tree_queries import TreeManager
|
||||||
from wireless.choices import *
|
from wireless.choices import *
|
||||||
from wireless.utils import get_channel_attr
|
from wireless.utils import get_channel_attr
|
||||||
|
|
||||||
@ -1064,19 +1064,11 @@ class InventoryItemRole(OrganizationalModel):
|
|||||||
return reverse('dcim:inventoryitemrole', args=[self.pk])
|
return reverse('dcim:inventoryitemrole', args=[self.pk])
|
||||||
|
|
||||||
|
|
||||||
class InventoryItem(MPTTModel, ComponentModel):
|
class InventoryItem(TreeNode, ComponentModel):
|
||||||
"""
|
"""
|
||||||
An InventoryItem represents a serialized piece of hardware within a Device, such as a line card or power supply.
|
An InventoryItem represents a serialized piece of hardware within a Device, such as a line card or power supply.
|
||||||
InventoryItems are used only for inventory purposes.
|
InventoryItems are used only for inventory purposes.
|
||||||
"""
|
"""
|
||||||
parent = TreeForeignKey(
|
|
||||||
to='self',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='child_items',
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
db_index=True
|
|
||||||
)
|
|
||||||
component_type = models.ForeignKey(
|
component_type = models.ForeignKey(
|
||||||
to=ContentType,
|
to=ContentType,
|
||||||
limit_choices_to=MODULAR_COMPONENT_MODELS,
|
limit_choices_to=MODULAR_COMPONENT_MODELS,
|
||||||
|
@ -198,13 +198,14 @@ class PathTraceView(generic.ObjectView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class RegionListView(generic.ObjectListView):
|
class RegionListView(generic.ObjectListView):
|
||||||
queryset = Region.objects.add_related_count(
|
queryset = Region.objects.all()
|
||||||
Region.objects.all(),
|
# queryset = Region.objects.add_related_count(
|
||||||
Site,
|
# Region.objects.all(),
|
||||||
'region',
|
# Site,
|
||||||
'site_count',
|
# 'region',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.RegionFilterSet
|
filterset = filtersets.RegionFilterSet
|
||||||
filterset_form = forms.RegionFilterForm
|
filterset_form = forms.RegionFilterForm
|
||||||
table = tables.RegionTable
|
table = tables.RegionTable
|
||||||
@ -244,26 +245,28 @@ class RegionBulkImportView(generic.BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class RegionBulkEditView(generic.BulkEditView):
|
class RegionBulkEditView(generic.BulkEditView):
|
||||||
queryset = Region.objects.add_related_count(
|
queryset = Region.objects.all()
|
||||||
Region.objects.all(),
|
# queryset = Region.objects.add_related_count(
|
||||||
Site,
|
# Region.objects.all(),
|
||||||
'region',
|
# Site,
|
||||||
'site_count',
|
# 'region',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.RegionFilterSet
|
filterset = filtersets.RegionFilterSet
|
||||||
table = tables.RegionTable
|
table = tables.RegionTable
|
||||||
form = forms.RegionBulkEditForm
|
form = forms.RegionBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class RegionBulkDeleteView(generic.BulkDeleteView):
|
class RegionBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = Region.objects.add_related_count(
|
queryset = Region.objects.all()
|
||||||
Region.objects.all(),
|
# queryset = Region.objects.add_related_count(
|
||||||
Site,
|
# Region.objects.all(),
|
||||||
'region',
|
# Site,
|
||||||
'site_count',
|
# 'region',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.RegionFilterSet
|
filterset = filtersets.RegionFilterSet
|
||||||
table = tables.RegionTable
|
table = tables.RegionTable
|
||||||
|
|
||||||
@ -278,13 +281,14 @@ class RegionContactsView(ObjectContactsView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class SiteGroupListView(generic.ObjectListView):
|
class SiteGroupListView(generic.ObjectListView):
|
||||||
queryset = SiteGroup.objects.add_related_count(
|
queryset = SiteGroup.objects.all()
|
||||||
SiteGroup.objects.all(),
|
# queryset = SiteGroup.objects.add_related_count(
|
||||||
Site,
|
# SiteGroup.objects.all(),
|
||||||
'group',
|
# Site,
|
||||||
'site_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.SiteGroupFilterSet
|
filterset = filtersets.SiteGroupFilterSet
|
||||||
filterset_form = forms.SiteGroupFilterForm
|
filterset_form = forms.SiteGroupFilterForm
|
||||||
table = tables.SiteGroupTable
|
table = tables.SiteGroupTable
|
||||||
@ -324,26 +328,28 @@ class SiteGroupBulkImportView(generic.BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class SiteGroupBulkEditView(generic.BulkEditView):
|
class SiteGroupBulkEditView(generic.BulkEditView):
|
||||||
queryset = SiteGroup.objects.add_related_count(
|
queryset = SiteGroup.objects.all()
|
||||||
SiteGroup.objects.all(),
|
# queryset = SiteGroup.objects.add_related_count(
|
||||||
Site,
|
# SiteGroup.objects.all(),
|
||||||
'group',
|
# Site,
|
||||||
'site_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.SiteGroupFilterSet
|
filterset = filtersets.SiteGroupFilterSet
|
||||||
table = tables.SiteGroupTable
|
table = tables.SiteGroupTable
|
||||||
form = forms.SiteGroupBulkEditForm
|
form = forms.SiteGroupBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class SiteGroupBulkDeleteView(generic.BulkDeleteView):
|
class SiteGroupBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = SiteGroup.objects.add_related_count(
|
queryset = SiteGroup.objects.all()
|
||||||
SiteGroup.objects.all(),
|
# queryset = SiteGroup.objects.add_related_count(
|
||||||
Site,
|
# SiteGroup.objects.all(),
|
||||||
'group',
|
# Site,
|
||||||
'site_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'site_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.SiteGroupFilterSet
|
filterset = filtersets.SiteGroupFilterSet
|
||||||
table = tables.SiteGroupTable
|
table = tables.SiteGroupTable
|
||||||
|
|
||||||
@ -388,20 +394,21 @@ class SiteView(generic.ObjectView):
|
|||||||
(Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct(), 'site_id'),
|
(Circuit.objects.restrict(request.user, 'view').filter(terminations__site=instance).distinct(), 'site_id'),
|
||||||
)
|
)
|
||||||
|
|
||||||
locations = Location.objects.add_related_count(
|
locations = Location.objects.all().restrict(request.user, 'view').filter(site=instance)
|
||||||
Location.objects.all(),
|
# locations = Location.objects.add_related_count(
|
||||||
Rack,
|
# Location.objects.all(),
|
||||||
'location',
|
# Rack,
|
||||||
'rack_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'rack_count',
|
||||||
)
|
# cumulative=True
|
||||||
locations = Location.objects.add_related_count(
|
# )
|
||||||
locations,
|
# locations = Location.objects.add_related_count(
|
||||||
Device,
|
# locations,
|
||||||
'location',
|
# Device,
|
||||||
'device_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'device_count',
|
||||||
).restrict(request.user, 'view').filter(site=instance)
|
# cumulative=True
|
||||||
|
# ).restrict(request.user, 'view').filter(site=instance)
|
||||||
|
|
||||||
nonracked_devices = Device.objects.filter(
|
nonracked_devices = Device.objects.filter(
|
||||||
site=instance,
|
site=instance,
|
||||||
@ -456,19 +463,20 @@ class SiteContactsView(ObjectContactsView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class LocationListView(generic.ObjectListView):
|
class LocationListView(generic.ObjectListView):
|
||||||
queryset = Location.objects.add_related_count(
|
queryset = Location.objects.all()
|
||||||
Location.objects.add_related_count(
|
# queryset = Location.objects.add_related_count(
|
||||||
Location.objects.all(),
|
# Location.objects.add_related_count(
|
||||||
Device,
|
# Location.objects.all(),
|
||||||
'location',
|
# Device,
|
||||||
'device_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'device_count',
|
||||||
),
|
# cumulative=True
|
||||||
Rack,
|
# ),
|
||||||
'location',
|
# Rack,
|
||||||
'rack_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'rack_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.LocationFilterSet
|
filterset = filtersets.LocationFilterSet
|
||||||
filterset_form = forms.LocationFilterForm
|
filterset_form = forms.LocationFilterForm
|
||||||
table = tables.LocationTable
|
table = tables.LocationTable
|
||||||
@ -515,26 +523,28 @@ class LocationBulkImportView(generic.BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class LocationBulkEditView(generic.BulkEditView):
|
class LocationBulkEditView(generic.BulkEditView):
|
||||||
queryset = Location.objects.add_related_count(
|
queryset = Location.objects.all()
|
||||||
Location.objects.all(),
|
# queryset = Location.objects.add_related_count(
|
||||||
Rack,
|
# Location.objects.all(),
|
||||||
'location',
|
# Rack,
|
||||||
'rack_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'rack_count',
|
||||||
).prefetch_related('site')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('site')
|
||||||
filterset = filtersets.LocationFilterSet
|
filterset = filtersets.LocationFilterSet
|
||||||
table = tables.LocationTable
|
table = tables.LocationTable
|
||||||
form = forms.LocationBulkEditForm
|
form = forms.LocationBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class LocationBulkDeleteView(generic.BulkDeleteView):
|
class LocationBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = Location.objects.add_related_count(
|
queryset = Location.objects.all()
|
||||||
Location.objects.all(),
|
# queryset = Location.objects.add_related_count(
|
||||||
Rack,
|
# Location.objects.all(),
|
||||||
'location',
|
# Rack,
|
||||||
'rack_count',
|
# 'location',
|
||||||
cumulative=True
|
# 'rack_count',
|
||||||
).prefetch_related('site')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('site')
|
||||||
filterset = filtersets.LocationFilterSet
|
filterset = filtersets.LocationFilterSet
|
||||||
table = tables.LocationTable
|
table = tables.LocationTable
|
||||||
|
|
||||||
|
@ -130,10 +130,11 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
|
|||||||
region_field = 'cluster__site__region'
|
region_field = 'cluster__site__region'
|
||||||
sitegroup_field = 'cluster__site__group'
|
sitegroup_field = 'cluster__site__group'
|
||||||
|
|
||||||
|
"""
|
||||||
base_query.add(
|
base_query.add(
|
||||||
(Q(
|
(Q(
|
||||||
regions__tree_id=OuterRef(f'{region_field}__tree_id'),
|
regions__tree_id=OuterRef(f'{region_field}__tree_id'),
|
||||||
regions__level__lte=OuterRef(f'{region_field}__level'),
|
regions__tree_depth__lte=OuterRef(f'{region_field}__tree_depth'),
|
||||||
regions__lft__lte=OuterRef(f'{region_field}__lft'),
|
regions__lft__lte=OuterRef(f'{region_field}__lft'),
|
||||||
regions__rght__gte=OuterRef(f'{region_field}__rght'),
|
regions__rght__gte=OuterRef(f'{region_field}__rght'),
|
||||||
) | Q(regions=None)),
|
) | Q(regions=None)),
|
||||||
@ -143,11 +144,12 @@ class ConfigContextModelQuerySet(RestrictedQuerySet):
|
|||||||
base_query.add(
|
base_query.add(
|
||||||
(Q(
|
(Q(
|
||||||
site_groups__tree_id=OuterRef(f'{sitegroup_field}__tree_id'),
|
site_groups__tree_id=OuterRef(f'{sitegroup_field}__tree_id'),
|
||||||
site_groups__level__lte=OuterRef(f'{sitegroup_field}__level'),
|
site_groups__tree_depth__lte=OuterRef(f'{sitegroup_field}__tree_depth'),
|
||||||
site_groups__lft__lte=OuterRef(f'{sitegroup_field}__lft'),
|
site_groups__lft__lte=OuterRef(f'{sitegroup_field}__lft'),
|
||||||
site_groups__rght__gte=OuterRef(f'{sitegroup_field}__rght'),
|
site_groups__rght__gte=OuterRef(f'{sitegroup_field}__rght'),
|
||||||
) | Q(site_groups=None)),
|
) | Q(site_groups=None)),
|
||||||
Q.AND
|
Q.AND
|
||||||
)
|
)
|
||||||
|
"""
|
||||||
|
|
||||||
return base_query
|
return base_query
|
||||||
|
@ -21,7 +21,7 @@ class NestedGroupModelSerializer(NetBoxModelSerializer):
|
|||||||
"""
|
"""
|
||||||
Extends PrimaryModelSerializer to include MPTT support.
|
Extends PrimaryModelSerializer to include MPTT support.
|
||||||
"""
|
"""
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
|
|
||||||
class BulkOperationSerializer(serializers.Serializer):
|
class BulkOperationSerializer(serializers.Serializer):
|
||||||
|
@ -2,11 +2,11 @@ from django.conf import settings
|
|||||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||||
from django.core.validators import ValidationError
|
from django.core.validators import ValidationError
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from tree_queries.models import TreeNode
|
||||||
|
|
||||||
from netbox.models.features import *
|
from netbox.models.features import *
|
||||||
from utilities.mptt import TreeManager
|
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from utilities.querysets import RestrictedQuerySet
|
||||||
|
from utilities.tree_queries import TreeManager
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ChangeLoggedModel',
|
'ChangeLoggedModel',
|
||||||
@ -103,19 +103,11 @@ class PrimaryModel(NetBoxModel):
|
|||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class NestedGroupModel(CloningMixin, NetBoxFeatureSet, MPTTModel):
|
class NestedGroupModel(CloningMixin, NetBoxFeatureSet, TreeNode):
|
||||||
"""
|
"""
|
||||||
Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest
|
Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest
|
||||||
recursively using MPTT. Within each parent, each child instance must have a unique name.
|
recursively using MPTT. Within each parent, each child instance must have a unique name.
|
||||||
"""
|
"""
|
||||||
parent = TreeForeignKey(
|
|
||||||
to='self',
|
|
||||||
on_delete=models.CASCADE,
|
|
||||||
related_name='children',
|
|
||||||
blank=True,
|
|
||||||
null=True,
|
|
||||||
db_index=True
|
|
||||||
)
|
|
||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=100
|
max_length=100
|
||||||
)
|
)
|
||||||
@ -131,9 +123,7 @@ class NestedGroupModel(CloningMixin, NetBoxFeatureSet, MPTTModel):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
ordering = ("name",)
|
||||||
class MPTTMeta:
|
|
||||||
order_insertion_by = ('name',)
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
@ -24,7 +24,7 @@ __all__ = [
|
|||||||
class NestedTenantGroupSerializer(WritableNestedSerializer):
|
class NestedTenantGroupSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:tenantgroup-detail')
|
||||||
tenant_count = serializers.IntegerField(read_only=True)
|
tenant_count = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
@ -49,7 +49,7 @@ class NestedTenantSerializer(WritableNestedSerializer):
|
|||||||
class NestedContactGroupSerializer(WritableNestedSerializer):
|
class NestedContactGroupSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactgroup-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='tenancy-api:contactgroup-detail')
|
||||||
contact_count = serializers.IntegerField(read_only=True)
|
contact_count = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ContactGroup
|
model = ContactGroup
|
||||||
|
@ -24,13 +24,14 @@ class TenancyRootView(APIRootView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class TenantGroupViewSet(NetBoxModelViewSet):
|
class TenantGroupViewSet(NetBoxModelViewSet):
|
||||||
queryset = TenantGroup.objects.add_related_count(
|
queryset = TenantGroup.objects.all().prefetch_related('tags')
|
||||||
TenantGroup.objects.all(),
|
# queryset = TenantGroup.objects.add_related_count(
|
||||||
Tenant,
|
# TenantGroup.objects.all(),
|
||||||
'group',
|
# Tenant,
|
||||||
'tenant_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'tenant_count',
|
||||||
).prefetch_related('tags')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('tags')
|
||||||
serializer_class = serializers.TenantGroupSerializer
|
serializer_class = serializers.TenantGroupSerializer
|
||||||
filterset_class = filtersets.TenantGroupFilterSet
|
filterset_class = filtersets.TenantGroupFilterSet
|
||||||
|
|
||||||
@ -59,13 +60,14 @@ class TenantViewSet(NetBoxModelViewSet):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ContactGroupViewSet(NetBoxModelViewSet):
|
class ContactGroupViewSet(NetBoxModelViewSet):
|
||||||
queryset = ContactGroup.objects.add_related_count(
|
queryset = ContactGroup.objects.all().prefetch_related('tags')
|
||||||
ContactGroup.objects.all(),
|
# queryset = ContactGroup.objects.add_related_count(
|
||||||
Contact,
|
# ContactGroup.objects.all(),
|
||||||
'group',
|
# Contact,
|
||||||
'contact_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'contact_count',
|
||||||
).prefetch_related('tags')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('tags')
|
||||||
serializer_class = serializers.ContactGroupSerializer
|
serializer_class = serializers.ContactGroupSerializer
|
||||||
filterset_class = filtersets.ContactGroupFilterSet
|
filterset_class = filtersets.ContactGroupFilterSet
|
||||||
|
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
# Generated by Django 4.1.8 on 2023-05-18 20:20
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('tenancy', '0010_tenant_relax_uniqueness'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contactgroup',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contactgroup',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contactgroup',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='contactgroup',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='tenantgroup',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='tenantgroup',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='tenantgroup',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='tenantgroup',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='contactgroup',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='tenancy.contactgroup',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='tenantgroup',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='tenancy.tenantgroup',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -42,13 +42,14 @@ class ObjectContactsView(generic.ObjectChildrenView):
|
|||||||
|
|
||||||
|
|
||||||
class TenantGroupListView(generic.ObjectListView):
|
class TenantGroupListView(generic.ObjectListView):
|
||||||
queryset = TenantGroup.objects.add_related_count(
|
queryset = TenantGroup.objects.all()
|
||||||
TenantGroup.objects.all(),
|
# queryset = TenantGroup.objects.add_related_count(
|
||||||
Tenant,
|
# TenantGroup.objects.all(),
|
||||||
'group',
|
# Tenant,
|
||||||
'tenant_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'tenant_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.TenantGroupFilterSet
|
filterset = filtersets.TenantGroupFilterSet
|
||||||
filterset_form = forms.TenantGroupFilterForm
|
filterset_form = forms.TenantGroupFilterForm
|
||||||
table = tables.TenantGroupTable
|
table = tables.TenantGroupTable
|
||||||
@ -86,26 +87,28 @@ class TenantGroupBulkImportView(generic.BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class TenantGroupBulkEditView(generic.BulkEditView):
|
class TenantGroupBulkEditView(generic.BulkEditView):
|
||||||
queryset = TenantGroup.objects.add_related_count(
|
queryset = TenantGroup.objects.all()
|
||||||
TenantGroup.objects.all(),
|
# queryset = TenantGroup.objects.add_related_count(
|
||||||
Tenant,
|
# TenantGroup.objects.all(),
|
||||||
'group',
|
# Tenant,
|
||||||
'tenant_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'tenant_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.TenantGroupFilterSet
|
filterset = filtersets.TenantGroupFilterSet
|
||||||
table = tables.TenantGroupTable
|
table = tables.TenantGroupTable
|
||||||
form = forms.TenantGroupBulkEditForm
|
form = forms.TenantGroupBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class TenantGroupBulkDeleteView(generic.BulkDeleteView):
|
class TenantGroupBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = TenantGroup.objects.add_related_count(
|
queryset = TenantGroup.objects.all()
|
||||||
TenantGroup.objects.all(),
|
# queryset = TenantGroup.objects.add_related_count(
|
||||||
Tenant,
|
# TenantGroup.objects.all(),
|
||||||
'group',
|
# Tenant,
|
||||||
'tenant_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'tenant_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.TenantGroupFilterSet
|
filterset = filtersets.TenantGroupFilterSet
|
||||||
table = tables.TenantGroupTable
|
table = tables.TenantGroupTable
|
||||||
|
|
||||||
@ -198,13 +201,14 @@ class TenantContactsView(ObjectContactsView):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class ContactGroupListView(generic.ObjectListView):
|
class ContactGroupListView(generic.ObjectListView):
|
||||||
queryset = ContactGroup.objects.add_related_count(
|
queryset = ContactGroup.objects.all()
|
||||||
ContactGroup.objects.all(),
|
# queryset = ContactGroup.objects.add_related_count(
|
||||||
Contact,
|
# ContactGroup.objects.all(),
|
||||||
'group',
|
# Contact,
|
||||||
'contact_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'contact_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.ContactGroupFilterSet
|
filterset = filtersets.ContactGroupFilterSet
|
||||||
filterset_form = forms.ContactGroupFilterForm
|
filterset_form = forms.ContactGroupFilterForm
|
||||||
table = tables.ContactGroupTable
|
table = tables.ContactGroupTable
|
||||||
@ -242,26 +246,28 @@ class ContactGroupBulkImportView(generic.BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class ContactGroupBulkEditView(generic.BulkEditView):
|
class ContactGroupBulkEditView(generic.BulkEditView):
|
||||||
queryset = ContactGroup.objects.add_related_count(
|
queryset = ContactGroup.objects.all()
|
||||||
ContactGroup.objects.all(),
|
# queryset = ContactGroup.objects.add_related_count(
|
||||||
Contact,
|
# ContactGroup.objects.all(),
|
||||||
'group',
|
# Contact,
|
||||||
'contact_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'contact_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.ContactGroupFilterSet
|
filterset = filtersets.ContactGroupFilterSet
|
||||||
table = tables.ContactGroupTable
|
table = tables.ContactGroupTable
|
||||||
form = forms.ContactGroupBulkEditForm
|
form = forms.ContactGroupBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class ContactGroupBulkDeleteView(generic.BulkDeleteView):
|
class ContactGroupBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = ContactGroup.objects.add_related_count(
|
queryset = ContactGroup.objects.all()
|
||||||
ContactGroup.objects.all(),
|
# queryset = ContactGroup.objects.add_related_count(
|
||||||
Contact,
|
# ContactGroup.objects.all(),
|
||||||
'group',
|
# Contact,
|
||||||
'contact_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'contact_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.ContactGroupFilterSet
|
filterset = filtersets.ContactGroupFilterSet
|
||||||
table = tables.ContactGroupTable
|
table = tables.ContactGroupTable
|
||||||
|
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
from mptt.managers import TreeManager as TreeManager_
|
|
||||||
from mptt.querysets import TreeQuerySet as TreeQuerySet_
|
|
||||||
|
|
||||||
from django.db.models import Manager
|
|
||||||
from .querysets import RestrictedQuerySet
|
|
||||||
|
|
||||||
__all__ = (
|
|
||||||
'TreeManager',
|
|
||||||
'TreeQuerySet',
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TreeQuerySet(TreeQuerySet_, RestrictedQuerySet):
|
|
||||||
"""
|
|
||||||
Mate django-mptt's TreeQuerySet with our RestrictedQuerySet for permissions enforcement.
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class TreeManager(Manager.from_queryset(TreeQuerySet), TreeManager_):
|
|
||||||
"""
|
|
||||||
Extend django-mptt's TreeManager to incorporate RestrictedQuerySet().
|
|
||||||
"""
|
|
||||||
pass
|
|
25
netbox/utilities/tree_queries.py
Normal file
25
netbox/utilities/tree_queries.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
from tree_queries.query import TreeManager as TreeManager_
|
||||||
|
from tree_queries.query import TreeQuerySet as TreeQuerySet_
|
||||||
|
|
||||||
|
from django.db.models import Manager
|
||||||
|
from .querysets import RestrictedQuerySet
|
||||||
|
|
||||||
|
__all__ = (
|
||||||
|
'TreeManager',
|
||||||
|
'TreeQuerySet',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TreeQuerySet(TreeQuerySet_, RestrictedQuerySet):
|
||||||
|
"""
|
||||||
|
Mate django-tree-queries TreeQuerySet with our RestrictedQuerySet for permissions enforcement.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class TreeManager(Manager.from_queryset(TreeQuerySet), TreeManager_):
|
||||||
|
"""
|
||||||
|
Extend django-tree-queries TreeManager to incorporate RestrictedQuerySet().
|
||||||
|
"""
|
||||||
|
|
||||||
|
_with_tree_fields = True
|
@ -15,7 +15,7 @@ from django.utils.html import escape
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.timezone import localtime
|
from django.utils.timezone import localtime
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
from mptt.models import MPTTModel
|
from tree_queries.models import TreeNode
|
||||||
|
|
||||||
from dcim.choices import CableLengthUnitChoices, WeightUnitChoices
|
from dcim.choices import CableLengthUnitChoices, WeightUnitChoices
|
||||||
from extras.plugins import PluginConfig
|
from extras.plugins import PluginConfig
|
||||||
@ -153,8 +153,8 @@ def serialize_object(obj, resolve_tags=True, extra=None):
|
|||||||
json_str = serializers.serialize('json', [obj])
|
json_str = serializers.serialize('json', [obj])
|
||||||
data = json.loads(json_str)[0]['fields']
|
data = json.loads(json_str)[0]['fields']
|
||||||
|
|
||||||
# Exclude any MPTTModel fields
|
# Exclude any TreeNode fields
|
||||||
if issubclass(obj.__class__, MPTTModel):
|
if issubclass(obj.__class__, TreeNode):
|
||||||
for field in ['level', 'lft', 'rght', 'tree_id']:
|
for field in ['level', 'lft', 'rght', 'tree_id']:
|
||||||
data.pop(field)
|
data.pop(field)
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ __all__ = (
|
|||||||
class NestedWirelessLANGroupSerializer(WritableNestedSerializer):
|
class NestedWirelessLANGroupSerializer(WritableNestedSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslangroup-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslangroup-detail')
|
||||||
wirelesslan_count = serializers.IntegerField(read_only=True)
|
wirelesslan_count = serializers.IntegerField(read_only=True)
|
||||||
_depth = serializers.IntegerField(source='level', read_only=True)
|
_depth = serializers.IntegerField(source='tree_depth', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLANGroup
|
model = WirelessLANGroup
|
||||||
|
@ -15,13 +15,14 @@ class WirelessRootView(APIRootView):
|
|||||||
|
|
||||||
|
|
||||||
class WirelessLANGroupViewSet(NetBoxModelViewSet):
|
class WirelessLANGroupViewSet(NetBoxModelViewSet):
|
||||||
queryset = WirelessLANGroup.objects.add_related_count(
|
queryset = WirelessLANGroup.objects.all()
|
||||||
WirelessLANGroup.objects.all(),
|
# queryset = WirelessLANGroup.objects.add_related_count(
|
||||||
WirelessLAN,
|
# WirelessLANGroup.objects.all(),
|
||||||
'group',
|
# WirelessLAN,
|
||||||
'wirelesslan_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'wirelesslan_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
serializer_class = serializers.WirelessLANGroupSerializer
|
serializer_class = serializers.WirelessLANGroupSerializer
|
||||||
filterset_class = filtersets.WirelessLANGroupFilterSet
|
filterset_class = filtersets.WirelessLANGroupFilterSet
|
||||||
|
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
# Generated by Django 4.1.8 on 2023-05-18 20:20
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
('wireless', '0008_wirelesslan_status'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wirelesslangroup',
|
||||||
|
name='level',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wirelesslangroup',
|
||||||
|
name='lft',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wirelesslangroup',
|
||||||
|
name='rght',
|
||||||
|
),
|
||||||
|
migrations.RemoveField(
|
||||||
|
model_name='wirelesslangroup',
|
||||||
|
name='tree_id',
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='wirelesslangroup',
|
||||||
|
name='parent',
|
||||||
|
field=models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
related_name='children',
|
||||||
|
to='wireless.wirelesslangroup',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
@ -1,7 +1,6 @@
|
|||||||
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 MPTTModel
|
|
||||||
|
|
||||||
from dcim.choices import LinkStatusChoices
|
from dcim.choices import LinkStatusChoices
|
||||||
from dcim.constants import WIRELESS_IFACE_TYPES
|
from dcim.constants import WIRELESS_IFACE_TYPES
|
||||||
|
@ -11,13 +11,14 @@ from .models import *
|
|||||||
#
|
#
|
||||||
|
|
||||||
class WirelessLANGroupListView(generic.ObjectListView):
|
class WirelessLANGroupListView(generic.ObjectListView):
|
||||||
queryset = WirelessLANGroup.objects.add_related_count(
|
queryset = WirelessLANGroup.objects.all().prefetch_related('tags')
|
||||||
WirelessLANGroup.objects.all(),
|
# queryset = WirelessLANGroup.objects.add_related_count(
|
||||||
WirelessLAN,
|
# WirelessLANGroup.objects.all(),
|
||||||
'group',
|
# WirelessLAN,
|
||||||
'wirelesslan_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'wirelesslan_count',
|
||||||
).prefetch_related('tags')
|
# cumulative=True
|
||||||
|
# ).prefetch_related('tags')
|
||||||
filterset = filtersets.WirelessLANGroupFilterSet
|
filterset = filtersets.WirelessLANGroupFilterSet
|
||||||
filterset_form = forms.WirelessLANGroupFilterForm
|
filterset_form = forms.WirelessLANGroupFilterForm
|
||||||
table = tables.WirelessLANGroupTable
|
table = tables.WirelessLANGroupTable
|
||||||
@ -55,26 +56,28 @@ class WirelessLANGroupBulkImportView(generic.BulkImportView):
|
|||||||
|
|
||||||
|
|
||||||
class WirelessLANGroupBulkEditView(generic.BulkEditView):
|
class WirelessLANGroupBulkEditView(generic.BulkEditView):
|
||||||
queryset = WirelessLANGroup.objects.add_related_count(
|
queryset = WirelessLANGroup.objects.all()
|
||||||
WirelessLANGroup.objects.all(),
|
# queryset = WirelessLANGroup.objects.add_related_count(
|
||||||
WirelessLAN,
|
# WirelessLANGroup.objects.all(),
|
||||||
'group',
|
# WirelessLAN,
|
||||||
'wirelesslan_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'wirelesslan_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.WirelessLANGroupFilterSet
|
filterset = filtersets.WirelessLANGroupFilterSet
|
||||||
table = tables.WirelessLANGroupTable
|
table = tables.WirelessLANGroupTable
|
||||||
form = forms.WirelessLANGroupBulkEditForm
|
form = forms.WirelessLANGroupBulkEditForm
|
||||||
|
|
||||||
|
|
||||||
class WirelessLANGroupBulkDeleteView(generic.BulkDeleteView):
|
class WirelessLANGroupBulkDeleteView(generic.BulkDeleteView):
|
||||||
queryset = WirelessLANGroup.objects.add_related_count(
|
queryset = WirelessLANGroup.objects.all()
|
||||||
WirelessLANGroup.objects.all(),
|
# queryset = WirelessLANGroup.objects.add_related_count(
|
||||||
WirelessLAN,
|
# WirelessLANGroup.objects.all(),
|
||||||
'group',
|
# WirelessLAN,
|
||||||
'wirelesslan_count',
|
# 'group',
|
||||||
cumulative=True
|
# 'wirelesslan_count',
|
||||||
)
|
# cumulative=True
|
||||||
|
# )
|
||||||
filterset = filtersets.WirelessLANGroupFilterSet
|
filterset = filtersets.WirelessLANGroupFilterSet
|
||||||
table = tables.WirelessLANGroupTable
|
table = tables.WirelessLANGroupTable
|
||||||
|
|
||||||
|
@ -5,7 +5,6 @@ django-cors-headers==3.14.0
|
|||||||
django-debug-toolbar==4.0.0
|
django-debug-toolbar==4.0.0
|
||||||
django-filter==23.2
|
django-filter==23.2
|
||||||
django-graphiql-debug-toolbar==0.2.0
|
django-graphiql-debug-toolbar==0.2.0
|
||||||
django-mptt==0.14
|
|
||||||
django-pglocks==1.0.4
|
django-pglocks==1.0.4
|
||||||
django-prometheus==2.3.1
|
django-prometheus==2.3.1
|
||||||
django-redis==5.2.0
|
django-redis==5.2.0
|
||||||
@ -14,6 +13,7 @@ django-rq==2.8.0
|
|||||||
django-tables2==2.5.3
|
django-tables2==2.5.3
|
||||||
django-taggit==4.0.0
|
django-taggit==4.0.0
|
||||||
django-timezone-field==5.0
|
django-timezone-field==5.0
|
||||||
|
django-tree-queries==0.14.0
|
||||||
djangorestframework==3.14.0
|
djangorestframework==3.14.0
|
||||||
drf-spectacular==0.26.2
|
drf-spectacular==0.26.2
|
||||||
drf-spectacular-sidecar==2023.5.1
|
drf-spectacular-sidecar==2023.5.1
|
||||||
|
Loading…
Reference in New Issue
Block a user