diff --git a/CHANGELOG.md b/CHANGELOG.md index 6014da3dc..a63cd9f87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * [#3150](https://github.com/digitalocean/netbox/issues/3150) - Fix formatting of cable length during cable trace * [#3085](https://github.com/digitalocean/netbox/issues/3085) - Catch all exceptions during export template rendering * [#3186](https://github.com/digitalocean/netbox/issues/3186) - Add interface name filter for IP addresses +* [#3190](https://github.com/digitalocean/netbox/issues/3190) - Fix custom field rendering for Jinja2 export templates ## Bug Fixes diff --git a/netbox/extras/models.py b/netbox/extras/models.py index da8f09a50..4c1f9cb76 100644 --- a/netbox/extras/models.py +++ b/netbox/extras/models.py @@ -106,6 +106,7 @@ class CustomFieldModel(models.Model): class Meta: abstract = True + @property def cf(self): """ Name-based CustomFieldValue accessor for use in templates diff --git a/netbox/extras/querysets.py b/netbox/extras/querysets.py index 439323c94..70c93968f 100644 --- a/netbox/extras/querysets.py +++ b/netbox/extras/querysets.py @@ -1,6 +1,24 @@ +from collections import OrderedDict + from django.db.models import Q, QuerySet +class CustomFieldQueryset: + """ + Annotate custom fields on objects within a QuerySet. + """ + def __init__(self, queryset, custom_fields): + self.queryset = queryset + self.model = queryset.model + self.custom_fields = custom_fields + + def __iter__(self): + for obj in self.queryset: + values_dict = {cfv.field_id: cfv.value for cfv in obj.custom_field_values.all()} + obj.custom_fields = OrderedDict([(field, values_dict.get(field.pk)) for field in self.custom_fields]) + yield obj + + class ConfigContextQuerySet(QuerySet): def get_for_object(self, obj): diff --git a/netbox/utilities/views.py b/netbox/utilities/views.py index 8b92e5a59..fd54088ba 100644 --- a/netbox/utilities/views.py +++ b/netbox/utilities/views.py @@ -1,5 +1,4 @@ import sys -from collections import OrderedDict from copy import deepcopy from django.conf import settings @@ -12,7 +11,7 @@ from django.forms import CharField, Form, ModelMultipleChoiceField, MultipleHidd from django.http import HttpResponse, HttpResponseServerError from django.shortcuts import get_object_or_404, redirect, render from django.template import loader -from django.template.exceptions import TemplateDoesNotExist, TemplateSyntaxError +from django.template.exceptions import TemplateDoesNotExist from django.urls import reverse from django.utils.html import escape from django.utils.http import is_safe_url @@ -23,6 +22,7 @@ from django.views.generic import View from django_tables2 import RequestConfig from extras.models import CustomField, CustomFieldValue, ExportTemplate +from extras.querysets import CustomFieldQueryset from utilities.forms import BootstrapMixin, CSVDataField from utilities.utils import csv_format from .error_handlers import handle_protectederror @@ -30,23 +30,6 @@ from .forms import ConfirmationForm from .paginator import EnhancedPaginator -class CustomFieldQueryset: - """ - Annotate custom fields on objects within a QuerySet. - """ - - def __init__(self, queryset, custom_fields): - self.queryset = queryset - self.model = queryset.model - self.custom_fields = custom_fields - - def __iter__(self): - for obj in self.queryset: - values_dict = {cfv.field_id: cfv.value for cfv in obj.custom_field_values.all()} - obj.custom_fields = OrderedDict([(field, values_dict.get(field.pk)) for field in self.custom_fields]) - yield obj - - class GetReturnURLMixin(object): """ Provides logic for determining where a user should be redirected after processing a form. @@ -115,8 +98,9 @@ class ObjectListView(View): self.queryset = self.filter(request.GET, self.queryset).qs # If this type of object has one or more custom fields, prefetch any relevant custom field values - custom_fields = CustomField.objects.filter(obj_type=ContentType.objects.get_for_model(model))\ - .prefetch_related('choices') + custom_fields = CustomField.objects.filter( + obj_type=ContentType.objects.get_for_model(model) + ).prefetch_related('choices') if custom_fields: self.queryset = self.queryset.prefetch_related('custom_field_values')