mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-22 20:12:00 -06:00
#6732 - Swap ASN M2M to Site model and update some templates/filters
This commit is contained in:
parent
330c498fe4
commit
7625a2dd3c
@ -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
|
||||
|
@ -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(
|
||||
|
19
netbox/dcim/migrations/0141_asn_model.py
Normal file
19
netbox/dcim/migrations/0141_asn_model.py
Normal 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'),
|
||||
),
|
||||
]
|
@ -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
|
||||
)
|
||||
|
@ -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):
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
38
netbox/ipam/migrations/0052_asn_model.py
Normal file
38
netbox/ipam/migrations/0052_asn_model.py
Normal 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'],
|
||||
},
|
||||
),
|
||||
]
|
@ -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()
|
||||
|
||||
|
@ -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,
|
||||
}
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
Loading…
Reference in New Issue
Block a user