mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 11:37:21 -06:00
Merge branch 'develop' into api2
This commit is contained in:
commit
0dd857f7a2
@ -635,16 +635,14 @@ class IPAddressBulkImportView(PermissionRequiredMixin, BulkImportView):
|
||||
|
||||
def save_obj(self, obj):
|
||||
obj.save()
|
||||
# Update primary IP for device if needed
|
||||
|
||||
# Update primary IP for device if needed. The Device must be updated directly in the database; otherwise we risk
|
||||
# overwriting a previous IP assignment from the same import (see #861).
|
||||
try:
|
||||
if obj.family == 4 and obj.primary_ip4_for:
|
||||
device = obj.primary_ip4_for
|
||||
device.primary_ip4 = obj
|
||||
device.save()
|
||||
Device.objects.filter(pk=obj.primary_ip4_for.pk).update(primary_ip4=obj)
|
||||
elif obj.family == 6 and obj.primary_ip6_for:
|
||||
device = obj.primary_ip6_for
|
||||
device.primary_ip6 = obj
|
||||
device.save()
|
||||
Device.objects.filter(pk=obj.primary_ip6_for.pk).update(primary_ip6=obj)
|
||||
except Device.DoesNotExist:
|
||||
pass
|
||||
|
||||
|
@ -548,9 +548,10 @@
|
||||
{% block javascript %}
|
||||
<script type="text/javascript">
|
||||
function toggleConnection(elem, api_url) {
|
||||
var url = netbox_api_path + api_url + elem.attr('data') + "/";
|
||||
if (elem.hasClass('connected')) {
|
||||
$.ajax({
|
||||
url: netbox_api_path + api_url + elem.attr('data') + "/",
|
||||
url: url,
|
||||
method: 'PATCH',
|
||||
dataType: 'json',
|
||||
beforeSend: function(xhr, settings) {
|
||||
@ -569,7 +570,7 @@ function toggleConnection(elem, api_url) {
|
||||
});
|
||||
} else {
|
||||
$.ajax({
|
||||
url: api_url + elem.attr('data') + "/",
|
||||
url: url,
|
||||
method: 'PATCH',
|
||||
dataType: 'json',
|
||||
beforeSend: function(xhr, settings) {
|
||||
|
@ -5,20 +5,19 @@ def handle_protectederror(obj, request, e):
|
||||
"""
|
||||
Generate a user-friendly error message in response to a ProtectedError exception.
|
||||
"""
|
||||
dependent_objects = e[1]
|
||||
try:
|
||||
dep_class = dependent_objects[0]._meta.verbose_name_plural
|
||||
dep_class = e.protected_objects[0]._meta.verbose_name_plural
|
||||
except IndexError:
|
||||
raise e
|
||||
|
||||
# Grammar for single versus multiple triggering objects
|
||||
if type(obj) in (list, tuple):
|
||||
err_message = "Unable to delete the requested {}. The following dependent {} were found: ".format(
|
||||
err_message = u"Unable to delete the requested {}. The following dependent {} were found: ".format(
|
||||
obj[0]._meta.verbose_name_plural,
|
||||
dep_class,
|
||||
)
|
||||
else:
|
||||
err_message = "Unable to delete {} {}. The following dependent {} were found: ".format(
|
||||
err_message = u"Unable to delete {} {}. The following dependent {} were found: ".format(
|
||||
obj._meta.verbose_name,
|
||||
obj,
|
||||
dep_class,
|
||||
@ -26,11 +25,11 @@ def handle_protectederror(obj, request, e):
|
||||
|
||||
# Append dependent objects to error message
|
||||
dependent_objects = []
|
||||
for o in e[1]:
|
||||
for o in e.protected_objects:
|
||||
if hasattr(o, 'get_absolute_url'):
|
||||
dependent_objects.append('<a href="{}">{}</a>'.format(o.get_absolute_url(), str(o)))
|
||||
dependent_objects.append(u'<a href="{}">{}</a>'.format(o.get_absolute_url(), o))
|
||||
else:
|
||||
dependent_objects.append(str(o))
|
||||
err_message += ', '.join(dependent_objects)
|
||||
err_message += u', '.join(dependent_objects)
|
||||
|
||||
messages.error(request, err_message)
|
||||
|
@ -236,14 +236,15 @@ class CSVDataField(forms.CharField):
|
||||
if not self.help_text:
|
||||
self.help_text = 'Enter one line per record in CSV format.'
|
||||
|
||||
def utf_8_encoder(self, unicode_csv_data):
|
||||
for line in unicode_csv_data:
|
||||
yield line.encode('utf-8')
|
||||
|
||||
def to_python(self, value):
|
||||
# Return a list of dictionaries, each representing an individual record
|
||||
"""
|
||||
Return a list of dictionaries, each representing an individual record
|
||||
"""
|
||||
# Python 2's csv module has problems with Unicode
|
||||
if not isinstance(value, str):
|
||||
value = value.encode('utf-8')
|
||||
records = []
|
||||
reader = csv.reader(self.utf_8_encoder(value.splitlines()))
|
||||
reader = csv.reader(value.splitlines())
|
||||
for i, row in enumerate(reader, start=1):
|
||||
if row:
|
||||
if len(row) < len(self.columns):
|
||||
@ -252,6 +253,7 @@ class CSVDataField(forms.CharField):
|
||||
elif len(row) > len(self.columns):
|
||||
raise forms.ValidationError("Line {}: Too many fields (found {}; expected {})"
|
||||
.format(i, len(row), len(self.columns)))
|
||||
row = [col.strip() for col in row]
|
||||
record = dict(zip(self.columns, row))
|
||||
records.append(record)
|
||||
return records
|
||||
|
@ -1,15 +1,26 @@
|
||||
import six
|
||||
|
||||
|
||||
def csv_format(data):
|
||||
"""
|
||||
Encapsulate any data which contains a comma within double quotes.
|
||||
"""
|
||||
csv = []
|
||||
for d in data:
|
||||
if d in [None, False]:
|
||||
for value in data:
|
||||
|
||||
# Represent None or False with empty string
|
||||
if value in [None, False]:
|
||||
csv.append(u'')
|
||||
elif type(d) not in (str, unicode):
|
||||
csv.append(u'{}'.format(d))
|
||||
elif u',' in d:
|
||||
csv.append(u'"{}"'.format(d))
|
||||
continue
|
||||
|
||||
# Force conversion to string first so we can check for any commas
|
||||
if not isinstance(value, six.string_types):
|
||||
value = u'{}'.format(value)
|
||||
|
||||
# Double-quote the value if it contains a comma
|
||||
if u',' in value:
|
||||
csv.append(u'"{}"'.format(value))
|
||||
else:
|
||||
csv.append(d)
|
||||
csv.append(u'{}'.format(value))
|
||||
|
||||
return u','.join(csv)
|
||||
|
@ -228,7 +228,7 @@ class ObjectDeleteView(View):
|
||||
return get_object_or_404(self.model, pk=kwargs['pk'])
|
||||
|
||||
def get_return_url(self, obj):
|
||||
if hasattr(obj, 'get_absolute_url'):
|
||||
if obj.pk and hasattr(obj, 'get_absolute_url'):
|
||||
return obj.get_absolute_url()
|
||||
return reverse(self.default_return_url)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user