Преглед на файлове

Fixes #9313: Remove HTML code from CSV output of many-to-many relationships

jeremystretch преди 3 години
родител
ревизия
39a9ebaeee

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

@@ -16,6 +16,7 @@
 * [#9267](https://github.com/netbox-community/netbox/issues/9267) - Remove invalid entry in IP address role choices
 * [#9267](https://github.com/netbox-community/netbox/issues/9267) - Remove invalid entry in IP address role choices
 * [#9306](https://github.com/netbox-community/netbox/issues/9306) - Include VC master interfaces when selecting a LAG/bridge for a VC member interface
 * [#9306](https://github.com/netbox-community/netbox/issues/9306) - Include VC master interfaces when selecting a LAG/bridge for a VC member interface
 * [#9311](https://github.com/netbox-community/netbox/issues/9311) - Permit creating contact assignment without a priority via the REST API
 * [#9311](https://github.com/netbox-community/netbox/issues/9311) - Permit creating contact assignment without a priority via the REST API
+* [#9313](https://github.com/netbox-community/netbox/issues/9313) - Remove HTML code from CSV output of many-to-many relationships
 
 
 ---
 ---
 
 

+ 1 - 1
netbox/circuits/tables/circuits.py

@@ -59,7 +59,7 @@ class CircuitTable(NetBoxTable):
     )
     )
     commit_rate = CommitRateColumn()
     commit_rate = CommitRateColumn()
     comments = columns.MarkdownColumn()
     comments = columns.MarkdownColumn()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 2 - 2
netbox/circuits/tables/providers.py

@@ -14,7 +14,7 @@ class ProviderTable(NetBoxTable):
     name = tables.Column(
     name = tables.Column(
         linkify=True
         linkify=True
     )
     )
-    asns = tables.ManyToManyColumn(
+    asns = columns.ManyToManyColumn(
         linkify_item=True,
         linkify_item=True,
         verbose_name='ASNs'
         verbose_name='ASNs'
     )
     )
@@ -31,7 +31,7 @@ class ProviderTable(NetBoxTable):
         verbose_name='Circuits'
         verbose_name='Circuits'
     )
     )
     comments = columns.MarkdownColumn()
     comments = columns.MarkdownColumn()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

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

@@ -190,7 +190,7 @@ class DeviceTable(NetBoxTable):
         verbose_name='VC Priority'
         verbose_name='VC Priority'
     )
     )
     comments = columns.MarkdownColumn()
     comments = columns.MarkdownColumn()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 1 - 1
netbox/dcim/tables/devicetypes.py

@@ -43,7 +43,7 @@ class ManufacturerTable(NetBoxTable):
         verbose_name='Platforms'
         verbose_name='Platforms'
     )
     )
     slug = tables.Column()
     slug = tables.Column()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 1 - 1
netbox/dcim/tables/power.py

@@ -26,7 +26,7 @@ class PowerPanelTable(NetBoxTable):
         url_params={'power_panel_id': 'pk'},
         url_params={'power_panel_id': 'pk'},
         verbose_name='Feeds'
         verbose_name='Feeds'
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 1 - 1
netbox/dcim/tables/racks.py

@@ -69,7 +69,7 @@ class RackTable(NetBoxTable):
         orderable=False,
         orderable=False,
         verbose_name='Power'
         verbose_name='Power'
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 5 - 5
netbox/dcim/tables/sites.py

@@ -26,7 +26,7 @@ class RegionTable(NetBoxTable):
         url_params={'region_id': 'pk'},
         url_params={'region_id': 'pk'},
         verbose_name='Sites'
         verbose_name='Sites'
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(
@@ -55,7 +55,7 @@ class SiteGroupTable(NetBoxTable):
         url_params={'group_id': 'pk'},
         url_params={'group_id': 'pk'},
         verbose_name='Sites'
         verbose_name='Sites'
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(
@@ -86,7 +86,7 @@ class SiteTable(NetBoxTable):
     group = tables.Column(
     group = tables.Column(
         linkify=True
         linkify=True
     )
     )
-    asns = tables.ManyToManyColumn(
+    asns = columns.ManyToManyColumn(
         linkify_item=True,
         linkify_item=True,
         verbose_name='ASNs'
         verbose_name='ASNs'
     )
     )
@@ -98,7 +98,7 @@ class SiteTable(NetBoxTable):
     )
     )
     tenant = TenantColumn()
     tenant = TenantColumn()
     comments = columns.MarkdownColumn()
     comments = columns.MarkdownColumn()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(
@@ -137,7 +137,7 @@ class LocationTable(NetBoxTable):
         url_params={'location_id': 'pk'},
         url_params={'location_id': 'pk'},
         verbose_name='Devices'
         verbose_name='Devices'
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 1 - 1
netbox/ipam/tables/ip.py

@@ -118,7 +118,7 @@ class ASNTable(NetBoxTable):
         url_params={'asn_id': 'pk'},
         url_params={'asn_id': 'pk'},
         verbose_name='Provider Count'
         verbose_name='Provider Count'
     )
     )
-    sites = tables.ManyToManyColumn(
+    sites = columns.ManyToManyColumn(
         linkify_item=True,
         linkify_item=True,
         verbose_name='Sites'
         verbose_name='Sites'
     )
     )

+ 39 - 23
netbox/netbox/tables/columns.py

@@ -6,7 +6,7 @@ from django.conf import settings
 from django.contrib.auth.models import AnonymousUser
 from django.contrib.auth.models import AnonymousUser
 from django.db.models import DateField, DateTimeField
 from django.db.models import DateField, DateTimeField
 from django.template import Context, Template
 from django.template import Context, Template
-from django.urls import NoReverseMatch, reverse
+from django.urls import reverse
 from django.utils.formats import date_format
 from django.utils.formats import date_format
 from django.utils.safestring import mark_safe
 from django.utils.safestring import mark_safe
 from django_tables2.columns import library
 from django_tables2.columns import library
@@ -27,6 +27,7 @@ __all__ = (
     'CustomLinkColumn',
     'CustomLinkColumn',
     'LinkedCountColumn',
     'LinkedCountColumn',
     'MarkdownColumn',
     'MarkdownColumn',
+    'ManyToManyColumn',
     'MPTTColumn',
     'MPTTColumn',
     'TagColumn',
     'TagColumn',
     'TemplateColumn',
     'TemplateColumn',
@@ -35,6 +36,10 @@ __all__ = (
 )
 )
 
 
 
 
+#
+# Django-tables2 overrides
+#
+
 @library.register
 @library.register
 class DateColumn(tables.DateColumn):
 class DateColumn(tables.DateColumn):
     """
     """
@@ -42,7 +47,6 @@ class DateColumn(tables.DateColumn):
     tables and null when exporting data. It is registered in the tables library to use this class instead of the
     tables and null when exporting data. It is registered in the tables library to use this class instead of the
     default, making this behavior consistent in all fields of type DateField.
     default, making this behavior consistent in all fields of type DateField.
     """
     """
-
     def value(self, value):
     def value(self, value):
         return value
         return value
 
 
@@ -59,7 +63,6 @@ class DateTimeColumn(tables.DateTimeColumn):
     tables and null when exporting data. It is registered in the tables library to use this class instead of the
     tables and null when exporting data. It is registered in the tables library to use this class instead of the
     default, making this behavior consistent in all fields of type DateTimeField.
     default, making this behavior consistent in all fields of type DateTimeField.
     """
     """
-
     def value(self, value):
     def value(self, value):
         if value:
         if value:
             return date_format(value, format="SHORT_DATETIME_FORMAT")
             return date_format(value, format="SHORT_DATETIME_FORMAT")
@@ -71,6 +74,39 @@ class DateTimeColumn(tables.DateTimeColumn):
             return cls(**kwargs)
             return cls(**kwargs)
 
 
 
 
+class ManyToManyColumn(tables.ManyToManyColumn):
+    """
+    Overrides django-tables2's stock ManyToManyColumn to ensure that value() returns only plaintext data.
+    """
+    def value(self, value):
+        items = [self.transform(item) for item in self.filter(value)]
+        return self.separator.join(items)
+
+
+class TemplateColumn(tables.TemplateColumn):
+    """
+    Overrides django-tables2's stock TemplateColumn class to render a placeholder symbol if the returned value
+    is an empty string.
+    """
+    PLACEHOLDER = mark_safe('—')
+
+    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
+
+
+#
+# Custom columns
+#
+
 class ToggleColumn(tables.CheckBoxColumn):
 class ToggleColumn(tables.CheckBoxColumn):
     """
     """
     Extend CheckBoxColumn to add a "toggle all" checkbox in the column header.
     Extend CheckBoxColumn to add a "toggle all" checkbox in the column header.
@@ -112,26 +148,6 @@ class BooleanColumn(tables.Column):
         return str(value)
         return str(value)
 
 
 
 
-class TemplateColumn(tables.TemplateColumn):
-    """
-    Overrides django-tables2's stock TemplateColumn class to render a placeholder symbol if the returned value
-    is an empty string.
-    """
-    PLACEHOLDER = mark_safe('—')
-
-    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
-
-
 @dataclass
 @dataclass
 class ActionsItem:
 class ActionsItem:
     title: str
     title: str

+ 1 - 1
netbox/tenancy/tables/tenants.py

@@ -38,7 +38,7 @@ class TenantTable(NetBoxTable):
         linkify=True
         linkify=True
     )
     )
     comments = columns.MarkdownColumn()
     comments = columns.MarkdownColumn()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 2 - 2
netbox/virtualization/tables/clusters.py

@@ -40,7 +40,7 @@ class ClusterGroupTable(NetBoxTable):
         url_params={'group_id': 'pk'},
         url_params={'group_id': 'pk'},
         verbose_name='Clusters'
         verbose_name='Clusters'
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(
@@ -83,7 +83,7 @@ class ClusterTable(NetBoxTable):
         verbose_name='VMs'
         verbose_name='VMs'
     )
     )
     comments = columns.MarkdownColumn()
     comments = columns.MarkdownColumn()
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(

+ 1 - 1
netbox/virtualization/tables/virtualmachines.py

@@ -78,7 +78,7 @@ class VMInterfaceTable(BaseInterfaceTable):
     vrf = tables.Column(
     vrf = tables.Column(
         linkify=True
         linkify=True
     )
     )
-    contacts = tables.ManyToManyColumn(
+    contacts = columns.ManyToManyColumn(
         linkify_item=True
         linkify_item=True
     )
     )
     tags = columns.TagColumn(
     tags = columns.TagColumn(