#6732 - Swap ASN M2M to Site model and update some templates/filters

This commit is contained in:
Daniel Sheppard 2021-11-02 12:26:06 -05:00
parent 330c498fe4
commit 7625a2dd3c
12 changed files with 120 additions and 29 deletions

View File

@ -117,7 +117,7 @@ class SiteBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEd
required=False,
label='ASN'
)
asns = DynamicModelChoiceField(
asns = DynamicModelMultipleChoiceField(
queryset=ASN.objects.all(),
label=_('ASNs'),
required=False

View File

@ -172,17 +172,6 @@ class SiteForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
'longitude': "Longitude in decimal format (xx.yyyyyy)"
}
def __init__(self, data=None, instance=None, *args, **kwargs):
super().__init__(data=data, instance=instance, *args, **kwargs)
if self.instance and self.instance.pk is not None:
self.fields['asns'].initial = self.instance.asns.all().values_list('id', flat=True)
def save(self, *args, **kwargs):
instance = super().save(*args, **kwargs)
instance.asns.set(self.cleaned_data['asns'])
return instance
class LocationForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
region = DynamicModelChoiceField(

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.8 on 2021-11-02 16:16
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ipam', '0052_asn_model'),
('dcim', '0140_wireless'),
]
operations = [
migrations.AddField(
model_name='site',
name='asns',
field=models.ManyToManyField(blank=True, related_name='sites', to='ipam.ASN'),
),
]

View File

@ -195,6 +195,11 @@ class Site(PrimaryModel):
verbose_name='ASN',
help_text='32-bit autonomous system number'
)
asns = models.ManyToManyField(
to='ipam.ASN',
related_name='sites',
blank=True
)
time_zone = TimeZoneField(
blank=True
)

View File

@ -183,7 +183,7 @@ class SiteTestCase(TestCase, ChangeLoggedFilterSetTests):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_asns(self):
params = {'asns': [65001, 65002]}
params = {'asns': [64512, 65002]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_latitude(self):

View File

@ -310,7 +310,6 @@ class SiteView(generic.ObjectView):
def get_extra_context(self, request, instance):
stats = {
'asn_count': ASN.objects.restrict(request.user, 'view').filter(sites=instance).count(),
'rack_count': Rack.objects.restrict(request.user, 'view').filter(site=instance).count(),
'device_count': Device.objects.restrict(request.user, 'view').filter(site=instance).count(),
'prefix_count': Prefix.objects.restrict(request.user, 'view').filter(site=instance).count(),
@ -333,9 +332,15 @@ class SiteView(generic.ObjectView):
cumulative=True
).restrict(request.user, 'view').filter(site=instance)
asns = ASN.objects.restrict(request.user, 'view').filter(sites=instance)
asn_count = asns.count()
stats.update({'asn_count': asn_count})
return {
'stats': stats,
'locations': locations,
'asns': asns,
}

View File

@ -134,14 +134,18 @@ class ASNForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
label='Sites',
required=False
)
tags = DynamicModelMultipleChoiceField(
queryset=Tag.objects.all(),
required=False
)
class Meta:
model = ASN
fields = [
'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description'
'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'tags'
]
fieldsets = (
('ASN', ('asn', 'rir', 'sites', 'description')),
('ASN', ('asn', 'rir', 'sites', 'description', 'tags')),
('Tenancy', ('tenant_group', 'tenant')),
)
help_texts = {
@ -152,6 +156,17 @@ class ASNForm(BootstrapMixin, TenancyForm, CustomFieldModelForm):
'date_added': DatePicker(),
}
def __init__(self, data=None, instance=None, *args, **kwargs):
super().__init__(data=data, instance=instance, *args, **kwargs)
if self.instance and self.instance.pk is not None:
self.fields['sites'].initial = self.instance.sites.all().values_list('id', flat=True)
def save(self, *args, **kwargs):
instance = super().save(*args, **kwargs)
instance.sites.set(self.cleaned_data['sites'])
return instance
class RoleForm(BootstrapMixin, CustomFieldModelForm):
slug = SlugField()

View File

@ -0,0 +1,38 @@
# Generated by Django 3.2.8 on 2021-11-02 16:16
import dcim.fields
import django.core.serializers.json
from django.db import migrations, models
import django.db.models.deletion
import taggit.managers
class Migration(migrations.Migration):
dependencies = [
('tenancy', '0004_extend_tag_support'),
('extras', '0064_configrevision'),
('ipam', '0051_extend_tag_support'),
]
operations = [
migrations.CreateModel(
name='ASN',
fields=[
('created', models.DateField(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=django.core.serializers.json.DjangoJSONEncoder)),
('id', models.BigAutoField(primary_key=True, serialize=False)),
('asn', dcim.fields.ASNField(unique=True)),
('description', models.CharField(blank=True, max_length=200)),
('rir', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='asns', to='ipam.rir')),
('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')),
('tenant', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='asns', to='tenancy.tenant')),
],
options={
'verbose_name': 'ASN',
'verbose_name_plural': 'ASNs',
'ordering': ['asn'],
},
),
]

View File

@ -71,6 +71,7 @@ class RIR(OrganizationalModel):
return reverse('ipam:rir', args=[self.pk])
@extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks')
class ASN(PrimaryModel):
asn = ASNField(
@ -98,11 +99,6 @@ class ASN(PrimaryModel):
blank=True,
null=True
)
sites = models.ManyToManyField(
to='dcim.Site',
related_name='asns',
blank=True
)
objects = RestrictedQuerySet.as_manager()

View File

@ -214,13 +214,10 @@ class ASNView(generic.ObjectView):
queryset = ASN.objects.all()
def get_extra_context(self, request, instance):
sites_table = SiteTable(
list(instance.sites.all()),
orderable=False
)
sites = instance.sites.restrict(request.user, 'view').all()
return {
'sites_table': sites_table,
'sites': sites,
}

View File

@ -260,6 +260,20 @@
{% endif %}
</div>
</div>
<div class="card">
<h5 class="card-header">
ASNs
</h5>
<div class='card-body'>
{% if asns %}
{% for asn in asns %}
<a href="{{ asn.get_absolute_url }}"><span class="badge bg-primary">{{ asn }}</span></a>
{% endfor %}
{% else %}
<span class="text-muted">None</span>
{% endif %}
</div>
</div>
{% include 'inc/panels/image_attachments.html' %}
{% plugin_right_page object %}
</div>

View File

@ -47,17 +47,30 @@
</table>
</div>
</div>
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/tags.html' with tags=object.tags.all url='ipam:asn_list' %}
{% plugin_left_page object %}
</div>
<div class="col col-md-6">
{% include 'inc/panels/custom_fields.html' %}
{% include 'inc/panels/tags.html' with tags=object.tags.all url='ipam:asn_list' %}
<div class="card">
<h5 class="card-header">
Sites
</h5>
<div class='card-body'>
{% if sites %}
{% for site in sites %}
<a href="{{ site.get_absolute_url }}"><span class="badge bg-primary">{{ site }}</span></a>
{% endfor %}
{% else %}
<span class="text-muted">None</span>
{% endif %}
</div>
</div>
{% plugin_right_page object %}
</div>
</div>
<div class="row mb-3">
<div class="col col-md-12">
{% include 'inc/panel_table.html' with table=sites_table heading='Sites' %}
{% plugin_full_width_page object %}
</div>
</div>