mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Add termination FKs on Circuit model
This commit is contained in:
@ -48,8 +48,7 @@ class CircuitTypeViewSet(CustomFieldModelViewSet):
|
||||
|
||||
class CircuitViewSet(CustomFieldModelViewSet):
|
||||
queryset = Circuit.objects.prefetch_related(
|
||||
Prefetch('terminations', queryset=CircuitTermination.objects.prefetch_related('site')),
|
||||
'type', 'tenant', 'provider',
|
||||
'type', 'tenant', 'provider', 'termination_a', 'termination_z'
|
||||
).prefetch_related('tags')
|
||||
serializer_class = serializers.CircuitSerializer
|
||||
filterset_class = filters.CircuitFilterSet
|
||||
|
@ -12,6 +12,7 @@ class Migration(migrations.Migration):
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Create the new Cloud model
|
||||
migrations.CreateModel(
|
||||
name='Cloud',
|
||||
fields=[
|
||||
@ -37,6 +38,8 @@ class Migration(migrations.Migration):
|
||||
name='cloud',
|
||||
unique_together={('provider', 'name')},
|
||||
),
|
||||
|
||||
# Add cloud FK to CircuitTermination
|
||||
migrations.AddField(
|
||||
model_name='circuittermination',
|
||||
name='cloud',
|
||||
@ -47,4 +50,16 @@ class Migration(migrations.Migration):
|
||||
name='site',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_terminations', to='dcim.site'),
|
||||
),
|
||||
|
||||
# Add FKs to CircuitTermination on Circuit
|
||||
migrations.AddField(
|
||||
model_name='circuit',
|
||||
name='termination_a',
|
||||
field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='circuits.circuittermination'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='circuit',
|
||||
name='termination_z',
|
||||
field=models.ForeignKey(blank=True, editable=False, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='circuits.circuittermination'),
|
||||
),
|
||||
]
|
||||
|
@ -0,0 +1,37 @@
|
||||
import sys
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def cache_circuit_terminations(apps, schema_editor):
|
||||
Circuit = apps.get_model('circuits', 'Circuit')
|
||||
CircuitTermination = apps.get_model('circuits', 'CircuitTermination')
|
||||
|
||||
if 'test' not in sys.argv:
|
||||
print(f"\n Caching circuit terminations...", flush=True)
|
||||
|
||||
a_terminations = {
|
||||
ct.circuit_id: ct.pk for ct in CircuitTermination.objects.filter(term_side='A')
|
||||
}
|
||||
z_terminations = {
|
||||
ct.circuit_id: ct.pk for ct in CircuitTermination.objects.filter(term_side='Z')
|
||||
}
|
||||
for circuit in Circuit.objects.all():
|
||||
Circuit.objects.filter(pk=circuit.pk).update(
|
||||
termination_a_id=a_terminations.get(circuit.pk),
|
||||
termination_z_id=z_terminations.get(circuit.pk),
|
||||
)
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('circuits', '0027_cloud'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(
|
||||
code=cache_circuit_terminations,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
@ -9,7 +9,6 @@ from extras.utils import extras_features
|
||||
from netbox.models import BigIDModel, ChangeLoggedModel, OrganizationalModel, PrimaryModel
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
from .choices import *
|
||||
from .querysets import CircuitQuerySet
|
||||
|
||||
|
||||
__all__ = (
|
||||
@ -236,7 +235,25 @@ class Circuit(PrimaryModel):
|
||||
blank=True
|
||||
)
|
||||
|
||||
objects = CircuitQuerySet.as_manager()
|
||||
# Cache associated CircuitTerminations
|
||||
termination_a = models.ForeignKey(
|
||||
to='circuits.CircuitTermination',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='+',
|
||||
editable=False,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
termination_z = models.ForeignKey(
|
||||
to='circuits.CircuitTermination',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='+',
|
||||
editable=False,
|
||||
blank=True,
|
||||
null=True
|
||||
)
|
||||
|
||||
objects = RestrictedQuerySet.as_manager()
|
||||
|
||||
csv_headers = [
|
||||
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
|
||||
@ -271,20 +288,6 @@ class Circuit(PrimaryModel):
|
||||
def get_status_class(self):
|
||||
return CircuitStatusChoices.CSS_CLASSES.get(self.status)
|
||||
|
||||
def _get_termination(self, side):
|
||||
for ct in self.terminations.all():
|
||||
if ct.term_side == side:
|
||||
return ct
|
||||
return None
|
||||
|
||||
@property
|
||||
def termination_a(self):
|
||||
return self._get_termination('A')
|
||||
|
||||
@property
|
||||
def termination_z(self):
|
||||
return self._get_termination('Z')
|
||||
|
||||
|
||||
@extras_features('webhooks')
|
||||
class CircuitTermination(ChangeLoggedModel, PathEndpoint, CableTermination):
|
||||
@ -345,6 +348,9 @@ class CircuitTermination(ChangeLoggedModel, PathEndpoint, CableTermination):
|
||||
unique_together = ['circuit', 'term_side']
|
||||
|
||||
def __str__(self):
|
||||
if self.site:
|
||||
return str(self.site)
|
||||
return str(self.cloud)
|
||||
return f"Side {self.get_term_side_display()}"
|
||||
|
||||
def clean(self):
|
||||
|
@ -1,17 +0,0 @@
|
||||
from django.db.models import OuterRef, Subquery
|
||||
|
||||
from utilities.querysets import RestrictedQuerySet
|
||||
|
||||
|
||||
class CircuitQuerySet(RestrictedQuerySet):
|
||||
|
||||
def annotate_sites(self):
|
||||
"""
|
||||
Annotate the A and Z termination site names for ordering.
|
||||
"""
|
||||
from circuits.models import CircuitTermination
|
||||
_terminations = CircuitTermination.objects.filter(circuit=OuterRef('pk'))
|
||||
return self.annotate(
|
||||
a_side=Subquery(_terminations.filter(term_side='A').values('site__name')[:1]),
|
||||
z_side=Subquery(_terminations.filter(term_side='Z').values('site__name')[:1]),
|
||||
)
|
@ -1,17 +1,17 @@
|
||||
from django.db.models.signals import post_delete, post_save
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import Circuit, CircuitTermination
|
||||
|
||||
|
||||
@receiver((post_save, post_delete), sender=CircuitTermination)
|
||||
@receiver(post_save, sender=CircuitTermination)
|
||||
def update_circuit(instance, **kwargs):
|
||||
"""
|
||||
When a CircuitTermination has been modified, update the last_updated time of its parent Circuit.
|
||||
When a CircuitTermination has been modified, update its parent Circuit.
|
||||
"""
|
||||
circuits = Circuit.objects.filter(pk=instance.circuit_id)
|
||||
time = timezone.now()
|
||||
for circuit in circuits:
|
||||
circuit.last_updated = time
|
||||
circuit.save()
|
||||
fields = {
|
||||
'last_updated': timezone.now(),
|
||||
f'termination_{instance.term_side.lower()}': instance.pk,
|
||||
}
|
||||
Circuit.objects.filter(pk=instance.circuit_id).update(**fields)
|
||||
|
@ -83,11 +83,11 @@ class CircuitTable(BaseTable):
|
||||
)
|
||||
status = ChoiceFieldColumn()
|
||||
tenant = TenantColumn()
|
||||
a_side = tables.Column(
|
||||
verbose_name='A Side'
|
||||
termination_a = tables.Column(
|
||||
verbose_name='Side A'
|
||||
)
|
||||
z_side = tables.Column(
|
||||
verbose_name='Z Side'
|
||||
termination_z = tables.Column(
|
||||
verbose_name='Side Z'
|
||||
)
|
||||
tags = TagColumn(
|
||||
url_name='circuits:circuit_list'
|
||||
@ -96,7 +96,9 @@ class CircuitTable(BaseTable):
|
||||
class Meta(BaseTable.Meta):
|
||||
model = Circuit
|
||||
fields = (
|
||||
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'a_side', 'z_side', 'install_date', 'commit_rate',
|
||||
'description', 'tags',
|
||||
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'install_date',
|
||||
'commit_rate', 'description', 'tags',
|
||||
)
|
||||
default_columns = (
|
||||
'pk', 'cid', 'provider', 'type', 'status', 'tenant', 'termination_a', 'termination_z', 'description',
|
||||
)
|
||||
default_columns = ('pk', 'cid', 'provider', 'type', 'status', 'tenant', 'a_side', 'z_side', 'description')
|
||||
|
@ -33,7 +33,7 @@ class ProviderView(generic.ObjectView):
|
||||
provider=instance
|
||||
).prefetch_related(
|
||||
'type', 'tenant', 'terminations__site'
|
||||
).annotate_sites()
|
||||
)
|
||||
|
||||
circuits_table = tables.CircuitTable(circuits)
|
||||
circuits_table.columns.hide('provider')
|
||||
@ -172,8 +172,8 @@ class CircuitTypeBulkDeleteView(generic.BulkDeleteView):
|
||||
|
||||
class CircuitListView(generic.ObjectListView):
|
||||
queryset = Circuit.objects.prefetch_related(
|
||||
'provider', 'type', 'tenant', 'terminations'
|
||||
).annotate_sites()
|
||||
'provider', 'type', 'tenant', 'termination_a', 'termination_z'
|
||||
)
|
||||
filterset = filters.CircuitFilterSet
|
||||
filterset_form = forms.CircuitFilterForm
|
||||
table = tables.CircuitTable
|
||||
|
@ -40,7 +40,7 @@ SEARCH_TYPES = OrderedDict((
|
||||
('circuit', {
|
||||
'queryset': Circuit.objects.prefetch_related(
|
||||
'type', 'provider', 'tenant', 'terminations__site'
|
||||
).annotate_sites(),
|
||||
),
|
||||
'filterset': CircuitFilterSet,
|
||||
'table': CircuitTable,
|
||||
'url': 'circuits:circuit_list',
|
||||
|
Reference in New Issue
Block a user