mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-24 16:26:09 -06:00
11617 update header processing for related fields
This commit is contained in:
parent
702cfc1fac
commit
f7b3dad29c
@ -21,7 +21,7 @@ from utilities.error_handlers import handle_protectederror
|
|||||||
from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
|
from utilities.exceptions import AbortRequest, AbortTransaction, PermissionsViolation
|
||||||
from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
|
from utilities.forms import BulkRenameForm, ConfirmationForm, restrict_form_fields
|
||||||
from utilities.forms.bulk_import import BulkImportForm
|
from utilities.forms.bulk_import import BulkImportForm
|
||||||
from utilities.forms.utils import validate_import_headers
|
from utilities.forms.utils import headers_to_dict, validate_import_headers
|
||||||
from utilities.htmx import is_embedded
|
from utilities.htmx import is_embedded
|
||||||
from utilities.htmx import is_htmx
|
from utilities.htmx import is_htmx
|
||||||
from utilities.permissions import get_permission_for_model
|
from utilities.permissions import get_permission_for_model
|
||||||
@ -393,8 +393,10 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
|
|||||||
'data': record,
|
'data': record,
|
||||||
'instance': instance,
|
'instance': instance,
|
||||||
}
|
}
|
||||||
|
headers = None
|
||||||
if hasattr(form, '_csv_headers'):
|
if hasattr(form, '_csv_headers'):
|
||||||
model_form_kwargs['headers'] = form._csv_headers # Add CSV headers
|
headers = form._csv_headers
|
||||||
|
model_form_kwargs['headers'] = headers # Add CSV headers
|
||||||
model_form = self.model_form(**model_form_kwargs)
|
model_form = self.model_form(**model_form_kwargs)
|
||||||
|
|
||||||
# validate the fields (required fields are present and no unknown fields)
|
# validate the fields (required fields are present and no unknown fields)
|
||||||
@ -402,7 +404,8 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
|
|||||||
required_fields = [
|
required_fields = [
|
||||||
name for name, field in form_fields.items() if field.required
|
name for name, field in form_fields.items() if field.required
|
||||||
]
|
]
|
||||||
headers = list(record.keys())
|
if not headers:
|
||||||
|
headers = headers_to_dict(list(record.keys()))
|
||||||
validate_import_headers(headers, form_fields, required_fields)
|
validate_import_headers(headers, form_fields, required_fields)
|
||||||
|
|
||||||
# When updating, omit all form fields other than those specified in the record. (No
|
# When updating, omit all form fields other than those specified in the record. (No
|
||||||
|
@ -205,6 +205,28 @@ def restrict_form_fields(form, user, action='view'):
|
|||||||
field.queryset = field.queryset.restrict(user, action)
|
field.queryset = field.queryset.restrict(user, action)
|
||||||
|
|
||||||
|
|
||||||
|
def headers_to_dict(headers):
|
||||||
|
"""
|
||||||
|
Create a dictionary mapping each header to an optional "to" field specifying how
|
||||||
|
the related object is being referenced. For example, importing a Device might use a
|
||||||
|
`site.slug` header, to indicate the related site is being referenced by its slug.
|
||||||
|
"""
|
||||||
|
header_dict = {}
|
||||||
|
for header in headers:
|
||||||
|
header = header.strip()
|
||||||
|
if '.' in header:
|
||||||
|
field, to_field = header.split('.', 1)
|
||||||
|
if field in headers:
|
||||||
|
raise forms.ValidationError(f'Duplicate or conflicting column header for "{field}"')
|
||||||
|
header_dict[field] = to_field
|
||||||
|
else:
|
||||||
|
if header in headers:
|
||||||
|
raise forms.ValidationError(f'Duplicate or conflicting column header for "{header}"')
|
||||||
|
header_dict[header] = None
|
||||||
|
|
||||||
|
return header_dict
|
||||||
|
|
||||||
|
|
||||||
def parse_csv(reader):
|
def parse_csv(reader):
|
||||||
"""
|
"""
|
||||||
Parse a csv_reader object into a headers dictionary and a list of records dictionaries. Raise an error
|
Parse a csv_reader object into a headers dictionary and a list of records dictionaries. Raise an error
|
||||||
@ -213,21 +235,8 @@ def parse_csv(reader):
|
|||||||
records = []
|
records = []
|
||||||
headers = {}
|
headers = {}
|
||||||
|
|
||||||
# Consume the first line of CSV data as column headers. Create a dictionary mapping each header to an optional
|
# Consume the first line of CSV data as column headers.
|
||||||
# "to" field specifying how the related object is being referenced. For example, importing a Device might use a
|
headers = headers_to_dict(list(reader))
|
||||||
# `site.slug` header, to indicate the related site is being referenced by its slug.
|
|
||||||
|
|
||||||
for header in next(reader):
|
|
||||||
header = header.strip()
|
|
||||||
if '.' in header:
|
|
||||||
field, to_field = header.split('.', 1)
|
|
||||||
if field in headers:
|
|
||||||
raise forms.ValidationError(f'Duplicate or conflicting column header for "{field}"')
|
|
||||||
headers[field] = to_field
|
|
||||||
else:
|
|
||||||
if header in headers:
|
|
||||||
raise forms.ValidationError(f'Duplicate or conflicting column header for "{header}"')
|
|
||||||
headers[header] = None
|
|
||||||
|
|
||||||
# Parse CSV rows into a list of dictionaries mapped from the column headers.
|
# Parse CSV rows into a list of dictionaries mapped from the column headers.
|
||||||
for i, row in enumerate(reader, start=1):
|
for i, row in enumerate(reader, start=1):
|
||||||
|
Loading…
Reference in New Issue
Block a user