mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-17 13:08:16 -06:00
15094 review change
This commit is contained in:
parent
3f305d199d
commit
07ee64e6bd
@ -102,7 +102,7 @@ class GitBackend(DataBackend):
|
|||||||
try:
|
try:
|
||||||
porcelain.clone(self.url, local_path.name, **clone_args)
|
porcelain.clone(self.url, local_path.name, **clone_args)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
raise SyncError(_("Fetching remote data failed ({name}): {e}").format(name=type(e).__name__, e=e))
|
raise SyncError(_("Fetching remote data failed ({name}): {error}").format(name=type(e).__name__, error=e))
|
||||||
|
|
||||||
yield local_path.name
|
yield local_path.name
|
||||||
|
|
||||||
|
@ -872,7 +872,9 @@ class InterfaceImportForm(NetBoxModelImportForm):
|
|||||||
if vdc.device != self.cleaned_data['device']:
|
if vdc.device != self.cleaned_data['device']:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
_("VDC {vdc} is not assigned to device {device}").format(
|
_("VDC {vdc} is not assigned to device {device}").format(
|
||||||
vdc=vdc, device=self.cleaned_data['device']))
|
vdc=vdc, device=self.cleaned_data['device']
|
||||||
|
)
|
||||||
|
)
|
||||||
return self.cleaned_data['vdcs']
|
return self.cleaned_data['vdcs']
|
||||||
|
|
||||||
|
|
||||||
@ -1077,8 +1079,11 @@ class InventoryItemImportForm(NetBoxModelImportForm):
|
|||||||
component = model.objects.get(device=device, name=component_name)
|
component = model.objects.get(device=device, name=component_name)
|
||||||
self.instance.component = component
|
self.instance.component = component
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise forms.ValidationError(_("Component not found: {device} - {component_name}").format(
|
raise forms.ValidationError(
|
||||||
device=device, component_name=component_name))
|
_("Component not found: {device} - {component_name}").format(
|
||||||
|
device=device, component_name=component_name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -1198,12 +1203,15 @@ class CableImportForm(NetBoxModelImportForm):
|
|||||||
if termination_object.cable is not None and termination_object.cable != self.instance:
|
if termination_object.cable is not None and termination_object.cable != self.instance:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
_("Side {side_upper}: {device} {termination_object} is already connected").format(
|
_("Side {side_upper}: {device} {termination_object} is already connected").format(
|
||||||
side_upper=side.upper(), device=device, termination_object=termination_object))
|
side_upper=side.upper(), device=device, termination_object=termination_object
|
||||||
|
)
|
||||||
|
)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
_("{side_upper} side termination not found: {device} {name}").format(
|
_("{side_upper} side termination not found: {device} {name}").format(
|
||||||
side_upper=side.upper(), device=device, name=name))
|
side_upper=side.upper(), device=device, name=name
|
||||||
|
)
|
||||||
|
)
|
||||||
setattr(self.instance, f'{side}_terminations', [termination_object])
|
setattr(self.instance, f'{side}_terminations', [termination_object])
|
||||||
return termination_object
|
return termination_object
|
||||||
|
|
||||||
|
@ -177,8 +177,9 @@ class Cable(PrimaryModel):
|
|||||||
a_type = self.a_terminations[0]._meta.model_name
|
a_type = self.a_terminations[0]._meta.model_name
|
||||||
b_type = self.b_terminations[0]._meta.model_name
|
b_type = self.b_terminations[0]._meta.model_name
|
||||||
if b_type not in COMPATIBLE_TERMINATION_TYPES.get(a_type):
|
if b_type not in COMPATIBLE_TERMINATION_TYPES.get(a_type):
|
||||||
raise ValidationError(_("Incompatible termination types: ") + str(a_type) + _(" and ") + str(b_type))
|
raise ValidationError(
|
||||||
|
_("Incompatible termination types: {type_a} and {type_b}").format(type_a=a_type, type_b=b_type)
|
||||||
|
)
|
||||||
if a_type == b_type:
|
if a_type == b_type:
|
||||||
# can't directly use self.a_terminations here as possible they
|
# can't directly use self.a_terminations here as possible they
|
||||||
# don't have pk yet
|
# don't have pk yet
|
||||||
@ -327,13 +328,16 @@ class CableTermination(ChangeLoggedModel):
|
|||||||
app_label=self.termination_type.app_label,
|
app_label=self.termination_type.app_label,
|
||||||
model=self.termination_type.model,
|
model=self.termination_type.model,
|
||||||
termination_id=self.termination_id,
|
termination_id=self.termination_id,
|
||||||
cable_pk=existing_termination.cable.pk))
|
cable_pk=existing_termination.cable.pk
|
||||||
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate interface type (if applicable)
|
# Validate interface type (if applicable)
|
||||||
if self.termination_type.model == 'interface' and self.termination.type in NONCONNECTABLE_IFACE_TYPES:
|
if self.termination_type.model == 'interface' and self.termination.type in NONCONNECTABLE_IFACE_TYPES:
|
||||||
raise ValidationError(_("Cables cannot be terminated to {type_display} interfaces").format(
|
raise ValidationError(
|
||||||
type_display=self.termination.get_type_display()))
|
_("Cables cannot be terminated to {type_display} interfaces").format(
|
||||||
|
type_display=self.termination.get_type_display()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# A CircuitTermination attached to a ProviderNetwork cannot have a Cable
|
# A CircuitTermination attached to a ProviderNetwork cannot have a Cable
|
||||||
if self.termination_type.model == 'circuittermination' and self.termination.provider_network is not None:
|
if self.termination_type.model == 'circuittermination' and self.termination.provider_network is not None:
|
||||||
|
@ -52,7 +52,8 @@ class Condition:
|
|||||||
def __init__(self, attr, value, op=EQ, negate=False):
|
def __init__(self, attr, value, op=EQ, negate=False):
|
||||||
if op not in self.OPERATORS:
|
if op not in self.OPERATORS:
|
||||||
raise ValueError(_("Unknown operator: {op}. Must be one of: {operators}").format(
|
raise ValueError(_("Unknown operator: {op}. Must be one of: {operators}").format(
|
||||||
op=op, operators=', '.join(self.OPERATORS)))
|
op=op, operators=', '.join(self.OPERATORS)
|
||||||
|
))
|
||||||
if type(value) not in self.TYPES:
|
if type(value) not in self.TYPES:
|
||||||
raise ValueError(_("Unsupported value type: {value}").format(value=type(value)))
|
raise ValueError(_("Unsupported value type: {value}").format(value=type(value)))
|
||||||
if op not in self.TYPES[type(value)]:
|
if op not in self.TYPES[type(value)]:
|
||||||
|
@ -113,7 +113,8 @@ class DashboardWidget:
|
|||||||
request: The current request
|
request: The current request
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(_("{class_name} must define a render() method.").format(
|
raise NotImplementedError(_("{class_name} must define a render() method.").format(
|
||||||
class_name=self.__class__))
|
class_name=self.__class__
|
||||||
|
))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
|
@ -131,7 +131,8 @@ def process_event_rules(event_rules, model_name, event, data, username=None, sna
|
|||||||
|
|
||||||
else:
|
else:
|
||||||
raise ValueError(_("Unknown action type for an event rule: {action_type}").format(
|
raise ValueError(_("Unknown action type for an event rule: {action_type}").format(
|
||||||
action_type=event_rule.action_type))
|
action_type=event_rule.action_type
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
def process_event_queue(events):
|
def process_event_queue(events):
|
||||||
@ -177,4 +178,4 @@ def flush_events(queue):
|
|||||||
func = import_string(name)
|
func = import_string(name)
|
||||||
func(queue)
|
func(queue)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(_("Cannot import events pipeline {name} error: {e}").format(name=name, e=e))
|
logger.error(_("Cannot import events pipeline {name} error: {error}").format(name=name, error=e))
|
||||||
|
@ -202,7 +202,7 @@ class EventRuleImportForm(NetBoxModelImportForm):
|
|||||||
try:
|
try:
|
||||||
webhook = Webhook.objects.get(name=action_object)
|
webhook = Webhook.objects.get(name=action_object)
|
||||||
except Webhook.DoesNotExist:
|
except Webhook.DoesNotExist:
|
||||||
raise forms.ValidationError(_("Webhook {action_object} not found").format(action_object=action_object))
|
raise forms.ValidationError(_("Webhook {name} not found").format(name=action_object))
|
||||||
self.instance.action_object = webhook
|
self.instance.action_object = webhook
|
||||||
# Script
|
# Script
|
||||||
elif action_type == EventRuleActionChoices.SCRIPT:
|
elif action_type == EventRuleActionChoices.SCRIPT:
|
||||||
@ -211,7 +211,7 @@ class EventRuleImportForm(NetBoxModelImportForm):
|
|||||||
try:
|
try:
|
||||||
module, script = get_module_and_script(module_name, script_name)
|
module, script = get_module_and_script(module_name, script_name)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise forms.ValidationError(_("Script {action_object} not found").format(action_object=action_object))
|
raise forms.ValidationError(_("Script {name} not found").format(name=action_object))
|
||||||
self.instance.action_object = module
|
self.instance.action_object = module
|
||||||
self.instance.action_object_type = ContentType.objects.get_for_model(module, for_concrete_model=False)
|
self.instance.action_object_type = ContentType.objects.get_for_model(module, for_concrete_model=False)
|
||||||
self.instance.action_parameters = {
|
self.instance.action_parameters = {
|
||||||
|
@ -33,7 +33,7 @@ class BaseIPField(models.Field):
|
|||||||
# Always return a netaddr.IPNetwork object. (netaddr.IPAddress does not provide a mask.)
|
# Always return a netaddr.IPNetwork object. (netaddr.IPAddress does not provide a mask.)
|
||||||
return IPNetwork(value)
|
return IPNetwork(value)
|
||||||
except AddrFormatError:
|
except AddrFormatError:
|
||||||
raise ValidationError(_("Invalid IP address format: {}").format(value))
|
raise ValidationError(_("Invalid IP address format: {address}").format(address=value))
|
||||||
except (TypeError, ValueError) as e:
|
except (TypeError, ValueError) as e:
|
||||||
raise ValidationError(e)
|
raise ValidationError(e)
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ class IPAddressFormField(forms.Field):
|
|||||||
try:
|
try:
|
||||||
validate_ipv6_address(value)
|
validate_ipv6_address(value)
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
raise ValidationError(_("Invalid IPv4/IPv6 address format: {}").format(value))
|
raise ValidationError(_("Invalid IPv4/IPv6 address format: {address}").format(address=value))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return IPAddress(value)
|
return IPAddress(value)
|
||||||
|
@ -5,7 +5,11 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
def prefix_validator(prefix):
|
def prefix_validator(prefix):
|
||||||
if prefix.ip != prefix.cidr.ip:
|
if prefix.ip != prefix.cidr.ip:
|
||||||
raise ValidationError(_("{} is not a valid prefix. Did you mean {}?").format(prefix, prefix.cidr))
|
raise ValidationError(
|
||||||
|
_("{prefix} is not a valid prefix. Did you mean {suggested}?").format(
|
||||||
|
prefix=prefix, suggested=prefix.cidr
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class MaxPrefixLengthValidator(BaseValidator):
|
class MaxPrefixLengthValidator(BaseValidator):
|
||||||
|
@ -83,7 +83,7 @@ class ChoiceField(serializers.Field):
|
|||||||
except TypeError: # Input is an unhashable type
|
except TypeError: # Input is an unhashable type
|
||||||
pass
|
pass
|
||||||
|
|
||||||
raise ValidationError(_("{data} is not a valid choice.").format(data=data))
|
raise ValidationError(_("{value} is not a valid choice.").format(value=data))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def choices(self):
|
def choices(self):
|
||||||
|
@ -44,14 +44,14 @@ class WritableNestedSerializer(BaseModelSerializer):
|
|||||||
pk = int(data)
|
pk = int(data)
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
_("Related objects must be referenced by numeric ID or by dictionary of attributes. Received an unrecognized value: {data}").format(data=data)
|
_("Related objects must be referenced by numeric ID or by dictionary of attributes. Received an unrecognized value: {value}").format(value=data)
|
||||||
)
|
)
|
||||||
|
|
||||||
# Look up object by PK
|
# Look up object by PK
|
||||||
try:
|
try:
|
||||||
return self.Meta.model.objects.get(pk=pk)
|
return self.Meta.model.objects.get(pk=pk)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise ValidationError(_("Related object not found using the provided numeric ID: {pk}").format(pk=pk))
|
raise ValidationError(_("Related object not found using the provided numeric ID: {id}").format(id=pk))
|
||||||
|
|
||||||
|
|
||||||
# Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
|
# Declared here for use by PrimaryModelSerializer, but should be imported from extras.api.nested_serializers
|
||||||
|
@ -133,7 +133,9 @@ class ObjectPermissionMixin:
|
|||||||
# Sanity check: Ensure that the requested permission applies to the specified object
|
# Sanity check: Ensure that the requested permission applies to the specified object
|
||||||
model = obj._meta.concrete_model
|
model = obj._meta.concrete_model
|
||||||
if model._meta.label_lower != '.'.join((app_label, model_name)):
|
if model._meta.label_lower != '.'.join((app_label, model_name)):
|
||||||
raise ValueError(_("Invalid permission {perm} for model {model}").format(perm=perm, model=model))
|
raise ValueError(_("Invalid permission {permission} for model {model}").format(
|
||||||
|
permission=perm, model=model
|
||||||
|
))
|
||||||
|
|
||||||
# Compile a QuerySet filter that matches all instances of the specified model
|
# Compile a QuerySet filter that matches all instances of the specified model
|
||||||
tokens = {
|
tokens = {
|
||||||
|
@ -36,7 +36,8 @@ class CustomFieldsMixin:
|
|||||||
"""
|
"""
|
||||||
if not getattr(self, 'model', None):
|
if not getattr(self, 'model', None):
|
||||||
raise NotImplementedError(_("{class_name} must specify a model class.").format(
|
raise NotImplementedError(_("{class_name} must specify a model class.").format(
|
||||||
class_name=self.__class__.__name__))
|
class_name=self.__class__.__name__
|
||||||
|
))
|
||||||
return ContentType.objects.get_for_model(self.model)
|
return ContentType.objects.get_for_model(self.model)
|
||||||
|
|
||||||
def _get_custom_fields(self, content_type):
|
def _get_custom_fields(self, content_type):
|
||||||
|
@ -275,13 +275,15 @@ class CustomFieldsMixin(models.Model):
|
|||||||
# Validate all field values
|
# Validate all field values
|
||||||
for field_name, value in self.custom_field_data.items():
|
for field_name, value in self.custom_field_data.items():
|
||||||
if field_name not in custom_fields:
|
if field_name not in custom_fields:
|
||||||
raise ValidationError(_("Unknown field name '{field_name}' in custom field data.").format(
|
raise ValidationError(_("Unknown field name '{name}' in custom field data.").format(
|
||||||
field_name=field_name))
|
name=field_name
|
||||||
|
))
|
||||||
try:
|
try:
|
||||||
custom_fields[field_name].validate(value)
|
custom_fields[field_name].validate(value)
|
||||||
except ValidationError as e:
|
except ValidationError as e:
|
||||||
raise ValidationError(_("Invalid value for custom field '{field_name}': {message}").format(
|
raise ValidationError(_("Invalid value for custom field '{name}': {error}").format(
|
||||||
field_name=field_name, message=e.message))
|
name=field_name, error=e.message
|
||||||
|
))
|
||||||
|
|
||||||
# Check for missing required values
|
# Check for missing required values
|
||||||
for cf in custom_fields.values():
|
for cf in custom_fields.values():
|
||||||
@ -550,7 +552,8 @@ class SyncedDataMixin(models.Model):
|
|||||||
to the local instance. This method should *NOT* call save() on the instance.
|
to the local instance. This method should *NOT* call save() on the instance.
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(_("{class_name} must implement a sync_data() method.").format(
|
raise NotImplementedError(_("{class_name} must implement a sync_data() method.").format(
|
||||||
class_name=self.__class__))
|
class_name=self.__class__
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -23,22 +23,30 @@ def register_template_extensions(class_list):
|
|||||||
if not inspect.isclass(template_extension):
|
if not inspect.isclass(template_extension):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
_("PluginTemplateExtension class {template_extension} was passed as an instance!").format(
|
_("PluginTemplateExtension class {template_extension} was passed as an instance!").format(
|
||||||
template_extension=template_extension))
|
template_extension=template_extension
|
||||||
|
)
|
||||||
|
)
|
||||||
if not issubclass(template_extension, PluginTemplateExtension):
|
if not issubclass(template_extension, PluginTemplateExtension):
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
_("{template_extension} is not a subclass of netbox.plugins.PluginTemplateExtension!").format(
|
_("{template_extension} is not a subclass of netbox.plugins.PluginTemplateExtension!").format(
|
||||||
template_extension=template_extension))
|
template_extension=template_extension
|
||||||
|
)
|
||||||
|
)
|
||||||
if template_extension.model is None:
|
if template_extension.model is None:
|
||||||
raise TypeError(
|
raise TypeError(
|
||||||
_("PluginTemplateExtension class {template_extension} does not define a valid model!").format(
|
_("PluginTemplateExtension class {template_extension} does not define a valid model!").format(
|
||||||
template_extension=template_extension))
|
template_extension=template_extension
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
registry['plugins']['template_extensions'][template_extension.model].append(template_extension)
|
registry['plugins']['template_extensions'][template_extension.model].append(template_extension)
|
||||||
|
|
||||||
|
|
||||||
def register_menu(menu):
|
def register_menu(menu):
|
||||||
if not isinstance(menu, PluginMenu):
|
if not isinstance(menu, PluginMenu):
|
||||||
raise TypeError(_("{menu} must be an instance of netbox.plugins.PluginMenu").format(menu=menu))
|
raise TypeError(_("{item} must be an instance of netbox.plugins.PluginMenuItem").format(
|
||||||
|
item=menu_link
|
||||||
|
))
|
||||||
registry['plugins']['menus'].append(menu)
|
registry['plugins']['menus'].append(menu)
|
||||||
|
|
||||||
|
|
||||||
@ -50,11 +58,13 @@ def register_menu_items(section_name, class_list):
|
|||||||
for menu_link in class_list:
|
for menu_link in class_list:
|
||||||
if not isinstance(menu_link, PluginMenuItem):
|
if not isinstance(menu_link, PluginMenuItem):
|
||||||
raise TypeError(_("{menu_link} must be an instance of netbox.plugins.PluginMenuItem").format(
|
raise TypeError(_("{menu_link} must be an instance of netbox.plugins.PluginMenuItem").format(
|
||||||
menu_link=menu_link))
|
menu_link=menu_link
|
||||||
|
))
|
||||||
for button in menu_link.buttons:
|
for button in menu_link.buttons:
|
||||||
if not isinstance(button, PluginMenuButton):
|
if not isinstance(button, PluginMenuButton):
|
||||||
raise TypeError(_("{button} must be an instance of netbox.plugins.PluginMenuButton").format(
|
raise TypeError(_("{button} must be an instance of netbox.plugins.PluginMenuButton").format(
|
||||||
button=button))
|
button=button
|
||||||
|
))
|
||||||
|
|
||||||
registry['plugins']['menu_items'][section_name] = class_list
|
registry['plugins']['menu_items'][section_name] = class_list
|
||||||
|
|
||||||
|
@ -391,7 +391,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView):
|
|||||||
try:
|
try:
|
||||||
instance = prefetched_objects[object_id]
|
instance = prefetched_objects[object_id]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
form.add_error('data', _("Row {i}: Object with ID {object_id} does not exist").format(i=i, object_id=object_id))
|
form.add_error('data', _("Row {i}: Object with ID {id} does not exist").format(i=i, id=object_id))
|
||||||
raise ValidationError('')
|
raise ValidationError('')
|
||||||
|
|
||||||
# Take a snapshot for change logging
|
# Take a snapshot for change logging
|
||||||
|
@ -103,7 +103,8 @@ class ObjectChildrenView(ObjectView, ActionsMixin, TableMixin):
|
|||||||
parent: The parent object
|
parent: The parent object
|
||||||
"""
|
"""
|
||||||
raise NotImplementedError(_('{class_name} must implement get_children()').format(
|
raise NotImplementedError(_('{class_name} must implement get_children()').format(
|
||||||
class_name=self.__class__.__name__))
|
class_name=self.__class__.__name__
|
||||||
|
))
|
||||||
|
|
||||||
def prep_table_data(self, request, queryset, parent):
|
def prep_table_data(self, request, queryset, parent):
|
||||||
"""
|
"""
|
||||||
|
@ -39,7 +39,7 @@ def parse_numeric_range(string, base=10):
|
|||||||
try:
|
try:
|
||||||
begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1
|
begin, end = int(begin.strip(), base=base), int(end.strip(), base=base) + 1
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise forms.ValidationError(_('Range "{dash_range}" is invalid.').format(dash_range=dash_range))
|
raise forms.ValidationError(_('Range "{value}" is invalid.').format(value=dash_range))
|
||||||
values.extend(range(begin, end))
|
values.extend(range(begin, end))
|
||||||
return sorted(set(values))
|
return sorted(set(values))
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ def parse_alphanumeric_range(string):
|
|||||||
begin, end = dash_range, dash_range
|
begin, end = dash_range, dash_range
|
||||||
if begin.isdigit() and end.isdigit():
|
if begin.isdigit() and end.isdigit():
|
||||||
if int(begin) >= int(end):
|
if int(begin) >= int(end):
|
||||||
raise forms.ValidationError(_('Range "{dash_range}" is invalid.').format(dash_range=dash_range))
|
raise forms.ValidationError(_('Range "{value}" is invalid.').format(value=dash_range))
|
||||||
|
|
||||||
for n in list(range(int(begin), int(end) + 1)):
|
for n in list(range(int(begin), int(end) + 1)):
|
||||||
values.append(n)
|
values.append(n)
|
||||||
@ -74,10 +74,10 @@ def parse_alphanumeric_range(string):
|
|||||||
else:
|
else:
|
||||||
# Not a valid range (more than a single character)
|
# Not a valid range (more than a single character)
|
||||||
if not len(begin) == len(end) == 1:
|
if not len(begin) == len(end) == 1:
|
||||||
raise forms.ValidationError(_('Range "{dash_range}" is invalid.').format(dash_range=dash_range))
|
raise forms.ValidationError(_('Range "{value}" is invalid.').format(value=dash_range))
|
||||||
|
|
||||||
if ord(begin) >= ord(end):
|
if ord(begin) >= ord(end):
|
||||||
raise forms.ValidationError(_('Range "{dash_range}" is invalid.').format(dash_range=dash_range))
|
raise forms.ValidationError(_('Range "{value}" is invalid.').format(value=dash_range))
|
||||||
|
|
||||||
for n in list(range(ord(begin), ord(end) + 1)):
|
for n in list(range(ord(begin), ord(end) + 1)):
|
||||||
values.append(chr(n))
|
values.append(chr(n))
|
||||||
@ -223,20 +223,23 @@ def parse_csv(reader):
|
|||||||
field, to_field = header.split('.', 1)
|
field, to_field = header.split('.', 1)
|
||||||
if field in headers:
|
if field in headers:
|
||||||
raise forms.ValidationError(_('Duplicate or conflicting column header for "{field}"').format(
|
raise forms.ValidationError(_('Duplicate or conflicting column header for "{field}"').format(
|
||||||
field=field))
|
field=field
|
||||||
|
))
|
||||||
headers[field] = to_field
|
headers[field] = to_field
|
||||||
else:
|
else:
|
||||||
if header in headers:
|
if header in headers:
|
||||||
raise forms.ValidationError(_('Duplicate or conflicting column header for "{header}"').format(
|
raise forms.ValidationError(_('Duplicate or conflicting column header for "{header}"').format(
|
||||||
header=header))
|
header=header
|
||||||
|
))
|
||||||
headers[header] = None
|
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):
|
||||||
if len(row) != len(headers):
|
if len(row) != len(headers):
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
_("Row {i}: Expected {len_headers} columns but found {len_row}").format(
|
_("Row {i}: Expected {count_expected} columns but found {count_found}").format(
|
||||||
len_headers=len(headers), len_row=len(row))
|
count_expected=len(headers), len_row=len(count_found)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
row = [col.strip() for col in row]
|
row = [col.strip() for col in row]
|
||||||
record = dict(zip(headers.keys(), row))
|
record = dict(zip(headers.keys(), row))
|
||||||
@ -260,13 +263,15 @@ def validate_csv(headers, fields, required_fields):
|
|||||||
raise forms.ValidationError(_('Unexpected column header "{field}" found.').format(field=field))
|
raise forms.ValidationError(_('Unexpected column header "{field}" found.').format(field=field))
|
||||||
if to_field and not hasattr(fields[field], 'to_field_name'):
|
if to_field and not hasattr(fields[field], 'to_field_name'):
|
||||||
raise forms.ValidationError(_('Column "{field}" is not a related object; cannot use dots').format(
|
raise forms.ValidationError(_('Column "{field}" is not a related object; cannot use dots').format(
|
||||||
field=field))
|
field=field
|
||||||
|
))
|
||||||
if to_field and not hasattr(fields[field].queryset.model, to_field):
|
if to_field and not hasattr(fields[field].queryset.model, to_field):
|
||||||
raise forms.ValidationError(_('Invalid related object attribute for column "{field}": {to_field}').format(
|
raise forms.ValidationError(_('Invalid related object attribute for column "{field}": {to_field}').format(
|
||||||
field=field, to_field=to_field))
|
field=field, to_field=to_field
|
||||||
|
))
|
||||||
|
|
||||||
# Validate required fields (if not an update)
|
# Validate required fields (if not an update)
|
||||||
if not is_update:
|
if not is_update:
|
||||||
for f in required_fields:
|
for f in required_fields:
|
||||||
if f not in headers:
|
if f not in headers:
|
||||||
raise forms.ValidationError(_('Required column header "{f}" not found.').format(f=f))
|
raise forms.ValidationError(_('Required column header "{header}" not found.').format(header=f))
|
||||||
|
Loading…
Reference in New Issue
Block a user