Merge branch 'develop' into v2-develop

Conflicts:
	netbox/circuits/models.py
	netbox/netbox/settings.py
	upgrade.sh
This commit is contained in:
Jeremy Stretch
2017-04-21 15:07:48 -04:00
10 changed files with 80 additions and 35 deletions

View File

@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2017-04-19 17:17
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('circuits', '0007_circuit_add_description'),
]
operations = [
migrations.AlterField(
model_name='circuittermination',
name='interface',
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='circuit_termination', to='dcim.Interface'),
),
]

View File

@@ -151,11 +151,13 @@ class CircuitTermination(models.Model):
term_side = models.CharField(max_length=1, choices=TERM_SIDE_CHOICES, verbose_name='Termination')
site = models.ForeignKey('dcim.Site', related_name='circuit_terminations', on_delete=models.PROTECT)
interface = models.OneToOneField(
'dcim.Interface', related_name='circuit_termination', blank=True, null=True, on_delete=models.CASCADE
'dcim.Interface', related_name='circuit_termination', blank=True, null=True, on_delete=models.PROTECT
)
port_speed = models.PositiveIntegerField(verbose_name='Port speed (Kbps)')
upstream_speed = models.PositiveIntegerField(blank=True, null=True, verbose_name='Upstream speed (Kbps)',
help_text='Upstream speed, if different from port speed')
upstream_speed = models.PositiveIntegerField(
blank=True, null=True, verbose_name='Upstream speed (Kbps)',
help_text='Upstream speed, if different from port speed'
)
xconnect_id = models.CharField(max_length=50, blank=True, verbose_name='Cross-connect ID')
pp_info = models.CharField(max_length=100, blank=True, verbose_name='Patch panel/port(s)')

View File

@@ -1,8 +1,7 @@
#!/usr/bin/env python
# This script will generate a random 50-character string suitable for use as a SECRET_KEY.
import os
import random
charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*(-_=+)'
random.seed = (os.urandom(2048))
print(''.join(random.choice(charset) for c in range(50)))
secure_random = random.SystemRandom()
print(''.join(secure_random.sample(charset, 50)))

View File

@@ -418,12 +418,15 @@ class IPAddressForm(BootstrapMixin, ReturnURLForm, CustomFieldForm):
self.fields['nat_inside'].choices = []
class IPAddressBulkAddForm(BootstrapMixin, forms.Form):
address = ExpandableIPAddressField()
class IPAddressBulkAddForm(BootstrapMixin, CustomFieldForm):
address_pattern = ExpandableIPAddressField(label='Address Pattern')
vrf = forms.ModelChoiceField(queryset=VRF.objects.all(), required=False, label='VRF', empty_label='Global')
tenant = forms.ModelChoiceField(queryset=Tenant.objects.all(), required=False)
status = forms.ChoiceField(choices=IPADDRESS_STATUS_CHOICES)
description = forms.CharField(max_length=100, required=False)
pattern_map = ('address_pattern', 'address')
class Meta:
model = IPAddress
fields = ['address_pattern', 'vrf', 'tenant', 'status', 'description']
class IPAddressAssignForm(BootstrapMixin, forms.Form):

View File

@@ -588,7 +588,7 @@ class IPAddressDeleteView(PermissionRequiredMixin, ObjectDeleteView):
class IPAddressBulkAddView(PermissionRequiredMixin, BulkAddView):
permission_required = 'ipam.add_ipaddress'
form = forms.IPAddressBulkAddForm
model = IPAddress
model_form = forms.IPAddressForm
template_name = 'ipam/ipaddress_bulk_add.html'
default_return_url = 'ipam:ipaddress_list'

View File

@@ -10,13 +10,21 @@
{% block form %}
<div class="panel panel-default">
<div class="panel-heading"><strong>IP Address</strong></div>
<div class="panel-heading"><strong>IP Addresses</strong></div>
<div class="panel-body">
{% render_field form.address %}
{% render_field form.address_pattern %}
{% render_field form.vrf %}
{% render_field form.tenant %}
{% render_field form.status %}
{% render_field form.description %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
{% endblock %}

View File

@@ -296,12 +296,12 @@ class BulkAddView(View):
Create new objects in bulk.
form: Form class
model: The model of the objects being created
model_form: The ModelForm used to create individual objects
template_name: The name of the template
default_return_url: Name of the URL to which the user is redirected after creating the objects
"""
form = None
model = None
model_form = None
template_name = None
default_return_url = 'home'
@@ -310,47 +310,44 @@ class BulkAddView(View):
form = self.form()
return render(request, self.template_name, {
'obj_type': self.model._meta.verbose_name,
'obj_type': self.model_form._meta.model._meta.verbose_name,
'form': form,
'return_url': reverse(self.default_return_url),
})
def post(self, request):
model = self.model_form._meta.model
form = self.form(request.POST)
if form.is_valid():
# The first field will be used as the pattern
field_names = list(form.fields.keys())
pattern_field = field_names[0]
# Read the pattern field and target from the form's pattern_map
pattern_field, pattern_target = form.pattern_map
pattern = form.cleaned_data[pattern_field]
# All other fields will be copied as object attributes
kwargs = {k: form.cleaned_data[k] for k in field_names[1:]}
model_form_data = form.cleaned_data
new_objs = []
try:
with transaction.atomic():
for value in pattern:
obj = self.model(**kwargs)
setattr(obj, pattern_field, value)
obj.full_clean()
obj.save()
model_form_data[pattern_target] = value
model_form = self.model_form(model_form_data)
obj = model_form.save()
new_objs.append(obj)
except ValidationError as e:
form.add_error(None, e)
if not form.errors:
msg = u"Added {} {}".format(len(new_objs), self.model._meta.verbose_name_plural)
msg = u"Added {} {}".format(len(new_objs), model._meta.verbose_name_plural)
messages.success(request, msg)
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(self.model), msg)
UserAction.objects.log_bulk_create(request.user, ContentType.objects.get_for_model(model), msg)
if '_addanother' in request.POST:
return redirect(request.path)
return redirect(self.default_return_url)
return render(request, self.template_name, {
'form': form,
'obj_type': self.model._meta.verbose_name,
'obj_type': model._meta.verbose_name,
'return_url': reverse(self.default_return_url),
})