1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Fixes #6895: Remove errant markup for null values in CSV export

This commit is contained in:
jeremystretch
2021-09-29 21:00:45 -04:00
parent 14b065cf5f
commit 1f1a05dc67
8 changed files with 42 additions and 46 deletions

View File

@ -4,6 +4,7 @@
### Bug Fixes ### Bug Fixes
* [#6895](https://github.com/netbox-community/netbox/issues/6895) - Remove errant markup for null values in CSV export
* [#7373](https://github.com/netbox-community/netbox/issues/7373) - Fix flashing when server, client, and browser color-mode preferences are mismatched * [#7373](https://github.com/netbox-community/netbox/issues/7373) - Fix flashing when server, client, and browser color-mode preferences are mismatched
--- ---

View File

@ -2,7 +2,7 @@ import django_tables2 as tables
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from dcim.models import Cable from dcim.models import Cable
from utilities.tables import BaseTable, ChoiceFieldColumn, ColorColumn, TagColumn, ToggleColumn from utilities.tables import BaseTable, ChoiceFieldColumn, ColorColumn, TagColumn, TemplateColumn, ToggleColumn
from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT from .template_code import CABLE_LENGTH, CABLE_TERMINATION_PARENT
__all__ = ( __all__ = (
@ -45,7 +45,7 @@ class CableTable(BaseTable):
verbose_name='Termination B' verbose_name='Termination B'
) )
status = ChoiceFieldColumn() status = ChoiceFieldColumn()
length = tables.TemplateColumn( length = TemplateColumn(
template_code=CABLE_LENGTH, template_code=CABLE_LENGTH,
order_by='_abs_length' order_by='_abs_length'
) )

View File

@ -9,7 +9,7 @@ from dcim.models import (
from tenancy.tables import TenantColumn from tenancy.tables import TenantColumn
from utilities.tables import ( from utilities.tables import (
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn, BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ColorColumn, ColoredLabelColumn, LinkedCountColumn,
MarkdownColumn, TagColumn, ToggleColumn, MarkdownColumn, TagColumn, TemplateColumn, ToggleColumn,
) )
from .template_code import ( from .template_code import (
CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS, CABLETERMINATION, CONSOLEPORT_BUTTONS, CONSOLESERVERPORT_BUTTONS, DEVICE_LINK, DEVICEBAY_BUTTONS, DEVICEBAY_STATUS,
@ -258,7 +258,7 @@ class CableTerminationTable(BaseTable):
orderable=False, orderable=False,
verbose_name='Cable Color' verbose_name='Cable Color'
) )
cable_peer = tables.TemplateColumn( cable_peer = TemplateColumn(
accessor='_cable_peer', accessor='_cable_peer',
template_code=CABLETERMINATION, template_code=CABLETERMINATION,
orderable=False, orderable=False,
@ -268,7 +268,7 @@ class CableTerminationTable(BaseTable):
class PathEndpointTable(CableTerminationTable): class PathEndpointTable(CableTerminationTable):
connection = tables.TemplateColumn( connection = TemplateColumn(
accessor='_path.last_node', accessor='_path.last_node',
template_code=CABLETERMINATION, template_code=CABLETERMINATION,
verbose_name='Connection', verbose_name='Connection',
@ -470,7 +470,7 @@ class BaseInterfaceTable(BaseTable):
verbose_name='IP Addresses' verbose_name='IP Addresses'
) )
untagged_vlan = tables.Column(linkify=True) untagged_vlan = tables.Column(linkify=True)
tagged_vlans = tables.TemplateColumn( tagged_vlans = TemplateColumn(
template_code=INTERFACE_TAGGED_VLANS, template_code=INTERFACE_TAGGED_VLANS,
orderable=False, orderable=False,
verbose_name='Tagged VLANs' verbose_name='Tagged VLANs'

View File

@ -5,13 +5,11 @@ CABLETERMINATION = """
<i class="mdi mdi-chevron-right"></i> <i class="mdi mdi-chevron-right"></i>
{% endif %} {% endif %}
<a href="{{ value.get_absolute_url }}">{{ value }}</a> <a href="{{ value.get_absolute_url }}">{{ value }}</a>
{% else %}
&mdash;
{% endif %} {% endif %}
""" """
CABLE_LENGTH = """ CABLE_LENGTH = """
{% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% else %}&mdash;{% endif %} {% if record.length %}{{ record.length }} {{ record.get_length_unit_display }}{% endif %}
""" """
CABLE_TERMINATION_PARENT = """ CABLE_TERMINATION_PARENT = """
@ -63,8 +61,6 @@ INTERFACE_TAGGED_VLANS = """
{% endfor %} {% endfor %}
{% elif record.mode == 'tagged-all' %} {% elif record.mode == 'tagged-all' %}
All All
{% else %}
&mdash;
{% endif %} {% endif %}
""" """

View File

@ -39,15 +39,7 @@ PREFIXFLAT_LINK = """
{% if record.pk %} {% if record.pk %}
<a href="{% url 'ipam:prefix' pk=record.pk %}">{{ record.prefix }}</a> <a href="{% url 'ipam:prefix' pk=record.pk %}">{{ record.prefix }}</a>
{% else %} {% else %}
&mdash; {{ record.prefix }}
{% endif %}
"""
PREFIX_ROLE_LINK = """
{% if record.role %}
<a href="{% url 'ipam:prefix_list' %}?role={{ record.role.slug }}">{{ record.role }}</a>
{% else %}
&mdash;
{% endif %} {% endif %}
""" """
@ -218,8 +210,8 @@ class PrefixTable(BaseTable):
linkify=True, linkify=True,
verbose_name='VLAN' verbose_name='VLAN'
) )
role = tables.TemplateColumn( role = tables.Column(
template_code=PREFIX_ROLE_LINK linkify=True
) )
is_pool = BooleanColumn( is_pool = BooleanColumn(
verbose_name='Pool' verbose_name='Pool'
@ -264,8 +256,8 @@ class IPRangeTable(BaseTable):
status = ChoiceFieldColumn( status = ChoiceFieldColumn(
default=AVAILABLE_LABEL default=AVAILABLE_LABEL
) )
role = tables.TemplateColumn( role = tables.Column(
template_code=PREFIX_ROLE_LINK linkify=True
) )
tenant = TenantColumn() tenant = TenantColumn()

View File

@ -6,7 +6,7 @@ from dcim.models import Interface
from tenancy.tables import TenantColumn from tenancy.tables import TenantColumn
from utilities.tables import ( from utilities.tables import (
BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn, BaseTable, BooleanColumn, ButtonsColumn, ChoiceFieldColumn, ContentTypeColumn, LinkedCountColumn, TagColumn,
ToggleColumn, TemplateColumn, ToggleColumn,
) )
from virtualization.models import VMInterface from virtualization.models import VMInterface
from ipam.models import * from ipam.models import *
@ -35,19 +35,9 @@ VLAN_LINK = """
VLAN_PREFIXES = """ VLAN_PREFIXES = """
{% for prefix in record.prefixes.all %} {% for prefix in record.prefixes.all %}
<a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %} <a href="{% url 'ipam:prefix' pk=prefix.pk %}">{{ prefix }}</a>{% if not forloop.last %}<br />{% endif %}
{% empty %}
&mdash;
{% endfor %} {% endfor %}
""" """
VLAN_ROLE_LINK = """
{% if record.role %}
<a href="{% url 'ipam:vlan_list' %}?role={{ record.role.slug }}">{{ record.role }}</a>
{% else %}
&mdash;
{% endif %}
"""
VLANGROUP_ADD_VLAN = """ VLANGROUP_ADD_VLAN = """
{% with next_vid=record.get_next_available_vid %} {% with next_vid=record.get_next_available_vid %}
{% if next_vid and perms.ipam.add_vlan %} {% if next_vid and perms.ipam.add_vlan %}
@ -115,10 +105,10 @@ class VLANTable(BaseTable):
status = ChoiceFieldColumn( status = ChoiceFieldColumn(
default=AVAILABLE_LABEL default=AVAILABLE_LABEL
) )
role = tables.TemplateColumn( role = tables.Column(
template_code=VLAN_ROLE_LINK linkify=True
) )
prefixes = tables.TemplateColumn( prefixes = TemplateColumn(
template_code=VLAN_PREFIXES, template_code=VLAN_PREFIXES,
orderable=False, orderable=False,
verbose_name='Prefixes' verbose_name='Prefixes'
@ -190,8 +180,8 @@ class InterfaceVLANTable(BaseTable):
) )
tenant = TenantColumn() tenant = TenantColumn()
status = ChoiceFieldColumn() status = ChoiceFieldColumn()
role = tables.TemplateColumn( role = tables.Column(
template_code=VLAN_ROLE_LINK linkify=True
) )
class Meta(BaseTable.Meta): class Meta(BaseTable.Meta):

View File

@ -1,7 +1,7 @@
import django_tables2 as tables import django_tables2 as tables
from tenancy.tables import TenantColumn from tenancy.tables import TenantColumn
from utilities.tables import BaseTable, BooleanColumn, TagColumn, ToggleColumn from utilities.tables import BaseTable, BooleanColumn, TagColumn, TemplateColumn, ToggleColumn
from ipam.models import * from ipam.models import *
__all__ = ( __all__ = (
@ -11,9 +11,7 @@ __all__ = (
VRF_TARGETS = """ VRF_TARGETS = """
{% for rt in value.all %} {% for rt in value.all %}
<a href="{{ rt.get_absolute_url }}">{{ rt }}</a>{% if not forloop.last %}<br />{% endif %} <a href="{{ rt.get_absolute_url }}">{{ rt }}</a>{% if not forloop.last %}<br />{% endif %}
{% empty %}
&mdash;
{% endfor %} {% endfor %}
""" """
@ -34,11 +32,11 @@ class VRFTable(BaseTable):
enforce_unique = BooleanColumn( enforce_unique = BooleanColumn(
verbose_name='Unique' verbose_name='Unique'
) )
import_targets = tables.TemplateColumn( import_targets = TemplateColumn(
template_code=VRF_TARGETS, template_code=VRF_TARGETS,
orderable=False orderable=False
) )
export_targets = tables.TemplateColumn( export_targets = TemplateColumn(
template_code=VRF_TARGETS, template_code=VRF_TARGETS,
orderable=False orderable=False
) )

View File

@ -157,6 +157,25 @@ class BooleanColumn(tables.Column):
return str(value) return str(value)
class TemplateColumn(tables.TemplateColumn):
"""
Overrides the stock TemplateColumn to render a placeholder if the returned value is an empty string.
"""
PLACEHOLDER = mark_safe('&mdash;')
def render(self, *args, **kwargs):
ret = super().render(*args, **kwargs)
if not ret.strip():
return self.PLACEHOLDER
return ret
def value(self, **kwargs):
ret = super().value(**kwargs)
if ret == self.PLACEHOLDER:
return ''
return ret
class ButtonsColumn(tables.TemplateColumn): class ButtonsColumn(tables.TemplateColumn):
""" """
Render edit, delete, and changelog buttons for an object. Render edit, delete, and changelog buttons for an object.