Răsfoiți Sursa

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

jeremystretch 4 ani în urmă
părinte
comite
1f1a05dc67

+ 1 - 0
docs/release-notes/version-3.0.md

@@ -4,6 +4,7 @@
 
 ### 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
 
 ---

+ 2 - 2
netbox/dcim/tables/cables.py

@@ -2,7 +2,7 @@ import django_tables2 as tables
 from django_tables2.utils import Accessor
 
 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
 
 __all__ = (
@@ -45,7 +45,7 @@ class CableTable(BaseTable):
         verbose_name='Termination B'
     )
     status = ChoiceFieldColumn()
-    length = tables.TemplateColumn(
+    length = TemplateColumn(
         template_code=CABLE_LENGTH,
         order_by='_abs_length'
     )

+ 4 - 4
netbox/dcim/tables/devices.py

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

+ 1 - 5
netbox/dcim/tables/template_code.py

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

+ 5 - 13
netbox/ipam/tables/ip.py

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

+ 6 - 16
netbox/ipam/tables/vlans.py

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

+ 4 - 6
netbox/ipam/tables/vrfs.py

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

+ 19 - 0
netbox/utilities/tables.py

@@ -157,6 +157,25 @@ class BooleanColumn(tables.Column):
         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):
     """
     Render edit, delete, and changelog buttons for an object.