7025 circuitgroupassignment

This commit is contained in:
Arthur Hanson 2024-07-19 11:19:19 +07:00
parent 291d158c7a
commit 3ae84b11e1
11 changed files with 251 additions and 16 deletions

View File

@ -13,6 +13,7 @@ from .models import *
__all__ = (
'CircuitFilterSet',
'CircuitGroupAssignmentFilterSet',
'CircuitGroupFilterSet',
'CircuitTerminationFilterSet',
'CircuitTypeFilterSet',
@ -319,3 +320,30 @@ class CircuitGroupFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
Q(name__icontains=value) |
Q(comments__icontains=value)
).distinct()
class CircuitGroupAssignmentFilterSet(NetBoxModelFilterSet):
q = django_filters.CharFilter(
method='search',
label=_('Search'),
)
circuit_id = django_filters.ModelMultipleChoiceFilter(
queryset=Circuit.objects.all(),
label=_('Circuit'),
)
group_id = django_filters.ModelMultipleChoiceFilter(
queryset=CircuitGroup.objects.all(),
label=_('Circuit group (ID)'),
)
class Meta:
model = CircuitGroupAssignment
fields = ('id', 'circuit', 'group', 'priority')
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(circuit__cid__icontains=value) |
Q(group__name__icontains=value)
)

View File

@ -1,7 +1,7 @@
from django import forms
from django.utils.translation import gettext_lazy as _
from circuits.choices import CircuitCommitRateChoices, CircuitStatusChoices
from circuits.choices import CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices
from circuits.models import *
from dcim.models import Site
from ipam.models import ASN
@ -14,6 +14,7 @@ from utilities.forms.widgets import BulkEditNullBooleanSelect, DatePicker, Numbe
__all__ = (
'CircuitBulkEditForm',
'CircuitGroupAssignmentBulkEditForm',
'CircuitGroupBulkEditForm',
'CircuitTerminationBulkEditForm',
'CircuitTypeBulkEditForm',
@ -237,3 +238,22 @@ class CircuitGroupBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = (
'tenant', 'comments',
)
class CircuitGroupAssignmentBulkEditForm(NetBoxModelBulkEditForm):
circuit = DynamicModelChoiceField(
label=_('Circuit'),
queryset=Circuit.objects.all(),
required=False
)
priority = forms.ChoiceField(
label=_('Priority'),
choices=add_blank_choice(CircuitPriorityChoices),
required=False
)
model = CircuitGroupAssignment
fieldsets = (
FieldSet('circuit', 'priority'),
)
nullable_fields = ('priority',)

View File

@ -11,6 +11,7 @@ from utilities.forms.fields import CSVChoiceField, CSVModelChoiceField, SlugFiel
__all__ = (
'CircuitImportForm',
'CircuitGroupAssignmentImportForm',
'CircuitGroupImportForm',
'CircuitTerminationImportForm',
'CircuitTerminationImportRelatedForm',
@ -165,3 +166,10 @@ class CircuitGroupImportForm(NetBoxModelImportForm):
class Meta:
model = CircuitGroup
fields = ('name', 'tenant', 'tags')
class CircuitGroupAssignmentImportForm(NetBoxModelImportForm):
class Meta:
model = CircuitGroupAssignment
fields = ('circuit', 'group', 'priority')

View File

@ -1,7 +1,7 @@
from django import forms
from django.utils.translation import gettext as _
from circuits.choices import CircuitCommitRateChoices, CircuitStatusChoices, CircuitTerminationSideChoices
from circuits.choices import CircuitCommitRateChoices, CircuitPriorityChoices, CircuitStatusChoices, CircuitTerminationSideChoices
from circuits.models import *
from dcim.models import Region, Site, SiteGroup
from ipam.models import ASN
@ -13,6 +13,7 @@ from utilities.forms.widgets import DatePicker, NumberWithOptions
__all__ = (
'CircuitFilterForm',
'CircuitGroupAssignmentFilterForm',
'CircuitGroupFilterForm',
'CircuitTerminationFilterForm',
'CircuitTypeFilterForm',
@ -241,3 +242,27 @@ class CircuitGroupFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
)
selector_fields = ('filter_id', 'q', )
tag = TagFilterField(model)
class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm):
model = CircuitGroupAssignment
fieldsets = (
FieldSet('q', 'filter_id', 'tag'),
FieldSet('circuit_id', 'group_id', 'priority', name=_('Assignment')),
)
circuit_id = DynamicModelMultipleChoiceField(
queryset=Circuit.objects.all(),
required=False,
label=_('Circuit')
)
group_id = DynamicModelMultipleChoiceField(
queryset=CircuitGroup.objects.all(),
required=False,
label=_('Group')
)
priority = forms.MultipleChoiceField(
label=_('Priority'),
choices=CircuitPriorityChoices,
required=False
)
tag = TagFilterField(model)

View File

@ -12,6 +12,7 @@ from utilities.forms.widgets import DatePicker, NumberWithOptions
__all__ = (
'CircuitForm',
'CircuitGroupAssignmentForm',
'CircuitGroupForm',
'CircuitTerminationForm',
'CircuitTypeForm',
@ -183,3 +184,29 @@ class CircuitGroupForm(TenancyForm, NetBoxModelForm):
'name', 'tenant_group', 'tenant',
'comments', 'tags',
]
class CircuitGroupAssignmentForm(NetBoxModelForm):
group = DynamicModelChoiceField(
label=_('Group'),
queryset=CircuitGroup.objects.all(),
required=False,
initial_params={
'groups': '$group'
}
)
circuit = DynamicModelChoiceField(
label=_('Circuit'),
queryset=Circuit.objects.all(),
required=False,
initial_params={
'circuits': '$circuit'
}
)
class Meta:
model = CircuitGroupAssignment
fields = [
'group', 'circuit', 'priority',
'tags',
]

View File

@ -1,4 +1,4 @@
# Generated by Django 5.0.7 on 2024-07-17 14:08
# Generated by Django 5.0.7 on 2024-07-19 04:18
import django.db.models.deletion
import taggit.managers
@ -51,14 +51,39 @@ class Migration(migrations.Migration):
name='CircuitGroupAssignment',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)),
('created', models.DateTimeField(auto_now_add=True, null=True)),
('last_updated', models.DateTimeField(auto_now=True, null=True)),
(
'custom_field_data',
models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder),
),
('priority', models.CharField(blank=True, max_length=50)),
('circuit', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='circuits.circuit')),
(
'circuit',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='circuit_group_assignments',
to='circuits.circuit',
),
),
('group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='circuits.circuitgroup')),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
],
options={
'verbose_name': 'Circuit group assignment',
'verbose_name_plural': 'Circuit group assignments',
'ordering': ('circuit', 'priority', 'pk'),
},
),
migrations.AddField(
model_name='circuitgroup',
name='circuits',
field=models.ManyToManyField(through='circuits.CircuitGroupAssignment', to='circuits.circuit'),
),
migrations.AddConstraint(
model_name='circuitgroupassignment',
constraint=models.UniqueConstraint(
fields=('circuit', 'group'), name='circuits_circuitgroupassignment_unique_circuit_assignment'
),
),
]

View File

@ -6,7 +6,7 @@ from django.utils.translation import gettext_lazy as _
from circuits.choices import *
from dcim.models import CabledObjectModel
from netbox.models import ChangeLoggedModel, OrganizationalModel, PrimaryModel
from netbox.models.features import ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ImageAttachmentsMixin, TagsMixin
from netbox.models.features import ContactsMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, ImageAttachmentsMixin, TagsMixin
from utilities.fields import ColorField
__all__ = (
@ -182,9 +182,16 @@ class CircuitGroup(PrimaryModel):
return reverse('circuits:circuitgroup', args=[self.pk])
class CircuitGroupAssignment(models.Model):
circuit = models.ForeignKey(Circuit, on_delete=models.CASCADE)
group = models.ForeignKey(CircuitGroup, on_delete=models.CASCADE)
class CircuitGroupAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel):
circuit = models.ForeignKey(
Circuit,
on_delete=models.CASCADE,
related_name='circuit_group_assignments'
)
group = models.ForeignKey(
CircuitGroup,
on_delete=models.CASCADE,
)
priority = models.CharField(
verbose_name=_('priority'),
max_length=50,
@ -192,6 +199,25 @@ class CircuitGroupAssignment(models.Model):
blank=True
)
class Meta:
ordering = ('circuit', 'priority', 'pk')
constraints = (
models.UniqueConstraint(
fields=('circuit', 'group',),
name='%(app_label)s_%(class)s_unique_circuit_assignment'
),
)
verbose_name = _('Circuit group assignment')
verbose_name_plural = _('Circuit group assignments')
def __str__(self):
if self.priority:
return f"{self.group} ({self.priority}) -> {self.circuit}"
return str(f"{self.group} -> {self.circuit}")
def get_absolute_url(self):
return reverse('circuits:circuitgroupassignment', args=[self.pk])
class CircuitTermination(
CustomFieldsMixin,

View File

@ -9,6 +9,7 @@ from netbox.tables import NetBoxTable, columns
from .columns import CommitRateColumn
__all__ = (
'CircuitGroupAssignmentTable',
'CircuitGroupTable',
'CircuitTable',
'CircuitTerminationTable',
@ -134,3 +135,24 @@ class CircuitGroupTable(NetBoxTable):
'pk', 'name', 'created', 'last_updated', 'actions',
)
default_columns = ('pk', 'name',)
class CircuitGroupAssignmentTable(NetBoxTable):
group = tables.Column(
verbose_name=_('Group'),
linkify=True
)
circuit = tables.Column(
verbose_name=_('Circuit'),
linkify=True
)
priority = tables.Column(
verbose_name=_('Priority'),
)
class Meta(NetBoxTable.Meta):
model = CircuitGroupAssignment
fields = (
'pk', 'id', 'group', 'circuit', 'priority', 'created', 'last_updated', 'actions',
)
default_columns = ('pk', 'group', 'circuit', 'priority')

View File

@ -55,11 +55,19 @@ urlpatterns = [
path('circuit-terminations/delete/', views.CircuitTerminationBulkDeleteView.as_view(), name='circuittermination_bulk_delete'),
path('circuit-terminations/<int:pk>/', include(get_model_urls('circuits', 'circuittermination'))),
# Circuit Redundacy Groups
path('circuit-redundancy-groups/', views.CircuitGroupListView.as_view(), name='circuitgroup_list'),
path('circuit-redundancy-groups/add/', views.CircuitGroupEditView.as_view(), name='circuitgroup_add'),
path('circuit-redundancy-groups/import/', views.CircuitGroupBulkImportView.as_view(), name='circuitgroup_import'),
path('circuit-redundancy-groups/edit/', views.CircuitGroupBulkEditView.as_view(), name='circuitgroup_bulk_edit'),
path('circuit-redundancy-groups/delete/', views.CircuitGroupBulkDeleteView.as_view(), name='circuitgroup_bulk_delete'),
path('circuit-redundancy-groups/<int:pk>/', include(get_model_urls('circuits', 'circuitgroup'))),
# Circuit Groups
path('circuit-groups/', views.CircuitGroupListView.as_view(), name='circuitgroup_list'),
path('circuit-groups/add/', views.CircuitGroupEditView.as_view(), name='circuitgroup_add'),
path('circuit-groups/import/', views.CircuitGroupBulkImportView.as_view(), name='circuitgroup_import'),
path('circuit-groups/edit/', views.CircuitGroupBulkEditView.as_view(), name='circuitgroup_bulk_edit'),
path('circuit-groups/delete/', views.CircuitGroupBulkDeleteView.as_view(), name='circuitgroup_bulk_delete'),
path('circuit-groups/<int:pk>/', include(get_model_urls('circuits', 'circuitgroup'))),
# Circuit Group Assignments
path('circuit-group-assignments/', views.CircuitGroupAssignmentListView.as_view(), name='circuitgroupassignment_list'),
path('circuit-group-assignments/add/', views.CircuitGroupAssignmentEditView.as_view(), name='circuitgroupassignment_add'),
path('circuit-group-assignments/import/', views.CircuitGroupAssignmentBulkImportView.as_view(), name='circuitgroupassignment_import'),
path('circuit-group-assignments/edit/', views.CircuitGroupAssignmentBulkEditView.as_view(), name='circuitgroupassignment_bulk_edit'),
path('circuit-group-assignments/delete/', views.CircuitGroupAssignmentBulkDeleteView.as_view(), name='circuitgroupassignment_bulk_delete'),
path('circuit-group-assignments/<int:pk>/', include(get_model_urls('circuits', 'circuitgroupassignment'))),
]

View File

@ -443,7 +443,7 @@ register_model_view(CircuitTermination, 'trace', kwargs={'model': CircuitTermina
#
# Circuit Redundacy Groups
# Circuit Groups
#
class CircuitGroupListView(generic.ObjectListView):
@ -485,3 +485,48 @@ class CircuitGroupBulkDeleteView(generic.BulkDeleteView):
queryset = CircuitGroup.objects.all()
filterset = filtersets.CircuitGroupFilterSet
table = tables.CircuitGroupTable
#
# Circuit Groups
#
class CircuitGroupAssignmentListView(generic.ObjectListView):
queryset = CircuitGroupAssignment.objects.all()
filterset = filtersets.CircuitGroupAssignmentFilterSet
filterset_form = forms.CircuitGroupAssignmentFilterForm
table = tables.CircuitGroupAssignmentTable
@register_model_view(CircuitGroup)
class CircuitGroupAssignmentView(generic.ObjectView):
queryset = CircuitGroupAssignment.objects.all()
@register_model_view(CircuitGroup, 'edit')
class CircuitGroupAssignmentEditView(generic.ObjectEditView):
queryset = CircuitGroupAssignment.objects.all()
form = forms.CircuitGroupAssignmentForm
@register_model_view(CircuitGroup, 'delete')
class CircuitGroupAssignmentDeleteView(generic.ObjectDeleteView):
queryset = CircuitGroupAssignment.objects.all()
class CircuitGroupAssignmentBulkImportView(generic.BulkImportView):
queryset = CircuitGroupAssignment.objects.all()
model_form = forms.CircuitGroupAssignmentImportForm
class CircuitGroupAssignmentBulkEditView(generic.BulkEditView):
queryset = CircuitGroupAssignment.objects.all()
filterset = filtersets.CircuitGroupAssignmentFilterSet
table = tables.CircuitGroupAssignmentTable
form = forms.CircuitGroupAssignmentBulkEditForm
class CircuitGroupAssignmentBulkDeleteView(generic.BulkDeleteView):
queryset = CircuitGroupAssignment.objects.all()
filterset = filtersets.CircuitGroupAssignmentFilterSet
table = tables.CircuitGroupAssignmentTable

View File

@ -261,6 +261,7 @@ CIRCUITS_MENU = Menu(
get_model_item('circuits', 'circuittype', _('Circuit Types')),
get_model_item('circuits', 'circuittermination', _('Circuit Terminations')),
get_model_item('circuits', 'circuitgroup', _('Circuit Groups')),
get_model_item('circuits', 'circuitgroupassignment', _('Circuit Group Assignments')),
),
),
MenuGroup(