Jeremy Stretch il y a 9 ans
Parent
commit
7502a02fba

+ 7 - 9
netbox/circuits/views.py

@@ -7,10 +7,8 @@ from utilities.views import (
     BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
     BulkDeleteView, BulkEditView, BulkImportView, ObjectDeleteView, ObjectEditView, ObjectListView,
 )
 )
 
 
-from . import forms
-from .filters import CircuitFilter
+from . import filters, forms, tables
 from .models import Circuit, CircuitType, Provider
 from .models import Circuit, CircuitType, Provider
-from .tables import CircuitTable, CircuitTypeTable, ProviderTable
 
 
 
 
 #
 #
@@ -19,7 +17,7 @@ from .tables import CircuitTable, CircuitTypeTable, ProviderTable
 
 
 class ProviderListView(ObjectListView):
 class ProviderListView(ObjectListView):
     queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
     queryset = Provider.objects.annotate(count_circuits=Count('circuits'))
-    table = ProviderTable
+    table = tables.ProviderTable
     edit_permissions = ['circuits.change_provider', 'circuits.delete_provider']
     edit_permissions = ['circuits.change_provider', 'circuits.delete_provider']
     template_name = 'circuits/provider_list.html'
     template_name = 'circuits/provider_list.html'
 
 
@@ -52,7 +50,7 @@ class ProviderDeleteView(PermissionRequiredMixin, ObjectDeleteView):
 class ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):
 class ProviderBulkImportView(PermissionRequiredMixin, BulkImportView):
     permission_required = 'circuits.add_provider'
     permission_required = 'circuits.add_provider'
     form = forms.ProviderImportForm
     form = forms.ProviderImportForm
-    table = ProviderTable
+    table = tables.ProviderTable
     template_name = 'circuits/provider_import.html'
     template_name = 'circuits/provider_import.html'
     obj_list_url = 'circuits:provider_list'
     obj_list_url = 'circuits:provider_list'
 
 
@@ -88,7 +86,7 @@ class ProviderBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 
 
 class CircuitTypeListView(ObjectListView):
 class CircuitTypeListView(ObjectListView):
     queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
     queryset = CircuitType.objects.annotate(circuit_count=Count('circuits'))
-    table = CircuitTypeTable
+    table = tables.CircuitTypeTable
     edit_permissions = ['circuits.change_circuittype', 'circuits.delete_circuittype']
     edit_permissions = ['circuits.change_circuittype', 'circuits.delete_circuittype']
     template_name = 'circuits/circuittype_list.html'
     template_name = 'circuits/circuittype_list.html'
 
 
@@ -114,9 +112,9 @@ class CircuitTypeBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 
 
 class CircuitListView(ObjectListView):
 class CircuitListView(ObjectListView):
     queryset = Circuit.objects.select_related('provider', 'type', 'site')
     queryset = Circuit.objects.select_related('provider', 'type', 'site')
-    filter = CircuitFilter
+    filter = filters.CircuitFilter
     filter_form = forms.CircuitFilterForm
     filter_form = forms.CircuitFilterForm
-    table = CircuitTable
+    table = tables.CircuitTable
     edit_permissions = ['circuits.change_circuit', 'circuits.delete_circuit']
     edit_permissions = ['circuits.change_circuit', 'circuits.delete_circuit']
     template_name = 'circuits/circuit_list.html'
     template_name = 'circuits/circuit_list.html'
 
 
@@ -148,7 +146,7 @@ class CircuitDeleteView(PermissionRequiredMixin, ObjectDeleteView):
 class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
 class CircuitBulkImportView(PermissionRequiredMixin, BulkImportView):
     permission_required = 'circuits.add_circuit'
     permission_required = 'circuits.add_circuit'
     form = forms.CircuitImportForm
     form = forms.CircuitImportForm
-    table = CircuitTable
+    table = tables.CircuitTable
     template_name = 'circuits/circuit_import.html'
     template_name = 'circuits/circuit_import.html'
     obj_list_url = 'circuits:circuit_list'
     obj_list_url = 'circuits:circuit_list'
 
 

+ 11 - 3
netbox/netbox/urls.py

@@ -7,16 +7,22 @@ from users.views import login, logout
 
 
 
 
 urlpatterns = [
 urlpatterns = [
+
+    # Default page
     url(r'^$', home, name='home'),
     url(r'^$', home, name='home'),
+
+    # Login/logout
+    url(r'^login/$', login, name='login'),
+    url(r'^logout/$', logout, name='logout'),
+
+    # Apps
     url(r'^circuits/', include('circuits.urls', namespace='circuits')),
     url(r'^circuits/', include('circuits.urls', namespace='circuits')),
     url(r'^dcim/', include('dcim.urls', namespace='dcim')),
     url(r'^dcim/', include('dcim.urls', namespace='dcim')),
     url(r'^ipam/', include('ipam.urls', namespace='ipam')),
     url(r'^ipam/', include('ipam.urls', namespace='ipam')),
     url(r'^secrets/', include('secrets.urls', namespace='secrets')),
     url(r'^secrets/', include('secrets.urls', namespace='secrets')),
     url(r'^profile/', include('users.urls', namespace='users')),
     url(r'^profile/', include('users.urls', namespace='users')),
 
 
-    url(r'^login/$', login, name='login'),
-    url(r'^logout/$', logout, name='logout'),
-
+    # API
     url(r'^api/circuits/', include('circuits.api.urls', namespace='circuits-api')),
     url(r'^api/circuits/', include('circuits.api.urls', namespace='circuits-api')),
     url(r'^api/dcim/', include('dcim.api.urls', namespace='dcim-api')),
     url(r'^api/dcim/', include('dcim.api.urls', namespace='dcim-api')),
     url(r'^api/ipam/', include('ipam.api.urls', namespace='ipam-api')),
     url(r'^api/ipam/', include('ipam.api.urls', namespace='ipam-api')),
@@ -28,5 +34,7 @@ urlpatterns = [
     url(r'^404/$', page_not_found),
     url(r'^404/$', page_not_found),
     url(r'^500/$', trigger_500),
     url(r'^500/$', trigger_500),
 
 
+    # Admin
     url(r'^admin/', include(admin.site.urls)),
     url(r'^admin/', include(admin.site.urls)),
+
 ]
 ]

+ 6 - 5
netbox/secrets/api/views.py

@@ -12,7 +12,8 @@ from rest_framework.views import APIView
 from extras.api.renderers import FormlessBrowsableAPIRenderer, FreeRADIUSClientsRenderer
 from extras.api.renderers import FormlessBrowsableAPIRenderer, FreeRADIUSClientsRenderer
 from secrets.filters import SecretFilter
 from secrets.filters import SecretFilter
 from secrets.models import Secret, SecretRole, UserKey
 from secrets.models import Secret, SecretRole, UserKey
-from .serializers import SecretRoleSerializer, SecretSerializer
+
+from . import serializers
 
 
 
 
 ERR_USERKEY_MISSING = "No UserKey found for the current user."
 ERR_USERKEY_MISSING = "No UserKey found for the current user."
@@ -25,7 +26,7 @@ class SecretRoleListView(generics.ListAPIView):
     List all secret roles
     List all secret roles
     """
     """
     queryset = SecretRole.objects.all()
     queryset = SecretRole.objects.all()
-    serializer_class = SecretRoleSerializer
+    serializer_class = serializers.SecretRoleSerializer
 
 
 
 
 class SecretRoleDetailView(generics.RetrieveAPIView):
 class SecretRoleDetailView(generics.RetrieveAPIView):
@@ -33,7 +34,7 @@ class SecretRoleDetailView(generics.RetrieveAPIView):
     Retrieve a single secret role
     Retrieve a single secret role
     """
     """
     queryset = SecretRole.objects.all()
     queryset = SecretRole.objects.all()
-    serializer_class = SecretRoleSerializer
+    serializer_class = serializers.SecretRoleSerializer
 
 
 
 
 class SecretListView(generics.GenericAPIView):
 class SecretListView(generics.GenericAPIView):
@@ -42,7 +43,7 @@ class SecretListView(generics.GenericAPIView):
     """
     """
     queryset = Secret.objects.select_related('device__primary_ip', 'role')\
     queryset = Secret.objects.select_related('device__primary_ip', 'role')\
         .prefetch_related('role__users', 'role__groups')
         .prefetch_related('role__users', 'role__groups')
-    serializer_class = SecretSerializer
+    serializer_class = serializers.SecretSerializer
     filter_class = SecretFilter
     filter_class = SecretFilter
     renderer_classes = [FormlessBrowsableAPIRenderer, JSONRenderer, FreeRADIUSClientsRenderer]
     renderer_classes = [FormlessBrowsableAPIRenderer, JSONRenderer, FreeRADIUSClientsRenderer]
 
 
@@ -87,7 +88,7 @@ class SecretDetailView(generics.GenericAPIView):
     """
     """
     queryset = Secret.objects.select_related('device__primary_ip', 'role')\
     queryset = Secret.objects.select_related('device__primary_ip', 'role')\
         .prefetch_related('role__users', 'role__groups')
         .prefetch_related('role__users', 'role__groups')
-    serializer_class = SecretSerializer
+    serializer_class = serializers.SecretSerializer
     renderer_classes = [FormlessBrowsableAPIRenderer, JSONRenderer, FreeRADIUSClientsRenderer]
     renderer_classes = [FormlessBrowsableAPIRenderer, JSONRenderer, FreeRADIUSClientsRenderer]
 
 
     def get(self, request, pk, private_key=None):
     def get(self, request, pk, private_key=None):

+ 1 - 1
netbox/secrets/forms.py

@@ -6,6 +6,7 @@ from django.db.models import Count
 
 
 from dcim.models import Device
 from dcim.models import Device
 from utilities.forms import BootstrapMixin, BulkImportForm, ConfirmationForm, CSVDataField
 from utilities.forms import BootstrapMixin, BulkImportForm, ConfirmationForm, CSVDataField
+
 from .models import Secret, SecretRole, UserKey
 from .models import Secret, SecretRole, UserKey
 
 
 
 
@@ -133,4 +134,3 @@ class UserKeyForm(forms.ModelForm, BootstrapMixin):
 class ActivateUserKeyForm(forms.Form):
 class ActivateUserKeyForm(forms.Form):
     _selected_action = forms.ModelMultipleChoiceField(queryset=UserKey.objects.all(), label='User Keys')
     _selected_action = forms.ModelMultipleChoiceField(queryset=UserKey.objects.all(), label='User Keys')
     secret_key = forms.CharField(label='Your private key', widget=forms.Textarea(attrs={'class': 'vLargeTextField'}))
     secret_key = forms.CharField(label='Your private key', widget=forms.Textarea(attrs={'class': 'vLargeTextField'}))
-

+ 1 - 0
netbox/secrets/models.py

@@ -11,6 +11,7 @@ from django.db import models
 from django.utils.encoding import force_bytes
 from django.utils.encoding import force_bytes
 
 
 from dcim.models import Device
 from dcim.models import Device
+
 from .hashers import SecretValidationHasher
 from .hashers import SecretValidationHasher
 
 
 
 

+ 3 - 1
netbox/secrets/tables.py

@@ -5,7 +5,9 @@ from .models import SecretRole, Secret
 
 
 
 
 SECRETROLE_EDIT_LINK = """
 SECRETROLE_EDIT_LINK = """
-{% if perms.secrets.change_secretrole %}<a href="{% url 'secrets:secretrole_edit' slug=record.slug %}">Edit</a>{% endif %}
+{% if perms.secrets.change_secretrole %}
+    <a href="{% url 'secrets:secretrole_edit' slug=record.slug %}">Edit</a>
+{% endif %}
 """
 """
 
 
 
 

+ 1 - 0
netbox/secrets/urls.py

@@ -2,6 +2,7 @@ from django.conf.urls import url
 
 
 from . import views
 from . import views
 
 
+
 urlpatterns = [
 urlpatterns = [
 
 
     # Secret roles
     # Secret roles

+ 17 - 20
netbox/secrets/views.py

@@ -8,14 +8,11 @@ from django.shortcuts import get_object_or_404, redirect, render
 from django.utils.decorators import method_decorator
 from django.utils.decorators import method_decorator
 
 
 from dcim.models import Device
 from dcim.models import Device
-from utilities.views import BulkEditView, BulkDeleteView, ObjectListView, ObjectEditView, ObjectDeleteView
+from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView
 
 
+from . import filters, forms, tables
 from .decorators import userkey_required
 from .decorators import userkey_required
-from .filters import SecretFilter
-from .forms import SecretRoleForm, SecretRoleBulkDeleteForm, SecretForm, SecretImportForm, SecretBulkEditForm,\
-    SecretBulkDeleteForm, SecretFilterForm
 from .models import SecretRole, Secret, UserKey
 from .models import SecretRole, Secret, UserKey
-from .tables import SecretRoleTable, SecretTable
 
 
 
 
 #
 #
@@ -24,7 +21,7 @@ from .tables import SecretRoleTable, SecretTable
 
 
 class SecretRoleListView(ObjectListView):
 class SecretRoleListView(ObjectListView):
     queryset = SecretRole.objects.annotate(secret_count=Count('secrets'))
     queryset = SecretRole.objects.annotate(secret_count=Count('secrets'))
-    table = SecretRoleTable
+    table = tables.SecretRoleTable
     edit_permissions = ['secrets.change_secretrole', 'secrets.delete_secretrole']
     edit_permissions = ['secrets.change_secretrole', 'secrets.delete_secretrole']
     template_name = 'secrets/secretrole_list.html'
     template_name = 'secrets/secretrole_list.html'
 
 
@@ -32,7 +29,7 @@ class SecretRoleListView(ObjectListView):
 class SecretRoleEditView(PermissionRequiredMixin, ObjectEditView):
 class SecretRoleEditView(PermissionRequiredMixin, ObjectEditView):
     permission_required = 'secrets.change_secretrole'
     permission_required = 'secrets.change_secretrole'
     model = SecretRole
     model = SecretRole
-    form_class = SecretRoleForm
+    form_class = forms.SecretRoleForm
     success_url = 'secrets:secretrole_list'
     success_url = 'secrets:secretrole_list'
     cancel_url = 'secrets:secretrole_list'
     cancel_url = 'secrets:secretrole_list'
 
 
@@ -40,7 +37,7 @@ class SecretRoleEditView(PermissionRequiredMixin, ObjectEditView):
 class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'secrets.delete_secretrole'
     permission_required = 'secrets.delete_secretrole'
     cls = SecretRole
     cls = SecretRole
-    form = SecretRoleBulkDeleteForm
+    form = forms.SecretRoleBulkDeleteForm
     default_redirect_url = 'secrets:secretrole_list'
     default_redirect_url = 'secrets:secretrole_list'
 
 
 
 
@@ -51,9 +48,9 @@ class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 @method_decorator(login_required, name='dispatch')
 @method_decorator(login_required, name='dispatch')
 class SecretListView(ObjectListView):
 class SecretListView(ObjectListView):
     queryset = Secret.objects.select_related('role').prefetch_related('device')
     queryset = Secret.objects.select_related('role').prefetch_related('device')
-    filter = SecretFilter
-    filter_form = SecretFilterForm
-    table = SecretTable
+    filter = filters.SecretFilter
+    filter_form = forms.SecretFilterForm
+    table = tables.SecretTable
     edit_permissions = ['secrets.change_secret', 'secrets.delete_secret']
     edit_permissions = ['secrets.change_secret', 'secrets.delete_secret']
     template_name = 'secrets/secret_list.html'
     template_name = 'secrets/secret_list.html'
 
 
@@ -79,7 +76,7 @@ def secret_add(request, pk):
     uk = UserKey.objects.get(user=request.user)
     uk = UserKey.objects.get(user=request.user)
 
 
     if request.method == 'POST':
     if request.method == 'POST':
-        form = SecretForm(request.POST, instance=secret)
+        form = forms.SecretForm(request.POST, instance=secret)
         if form.is_valid():
         if form.is_valid():
 
 
             # Retrieve the master key from the current user's UserKey
             # Retrieve the master key from the current user's UserKey
@@ -101,7 +98,7 @@ def secret_add(request, pk):
                     return redirect('secrets:secret', pk=secret.pk)
                     return redirect('secrets:secret', pk=secret.pk)
 
 
     else:
     else:
-        form = SecretForm(instance=secret)
+        form = forms.SecretForm(instance=secret)
 
 
     return render(request, 'secrets/secret_edit.html', {
     return render(request, 'secrets/secret_edit.html', {
         'secret': secret,
         'secret': secret,
@@ -118,7 +115,7 @@ def secret_edit(request, pk):
     uk = UserKey.objects.get(user=request.user)
     uk = UserKey.objects.get(user=request.user)
 
 
     if request.method == 'POST':
     if request.method == 'POST':
-        form = SecretForm(request.POST, instance=secret)
+        form = forms.SecretForm(request.POST, instance=secret)
         if form.is_valid():
         if form.is_valid():
 
 
             # Re-encrypt the Secret if a plaintext has been specified.
             # Re-encrypt the Secret if a plaintext has been specified.
@@ -143,7 +140,7 @@ def secret_edit(request, pk):
             return redirect('secrets:secret', pk=secret.pk)
             return redirect('secrets:secret', pk=secret.pk)
 
 
     else:
     else:
-        form = SecretForm(instance=secret)
+        form = forms.SecretForm(instance=secret)
 
 
     return render(request, 'secrets/secret_edit.html', {
     return render(request, 'secrets/secret_edit.html', {
         'secret': secret,
         'secret': secret,
@@ -165,7 +162,7 @@ def secret_import(request):
     uk = UserKey.objects.get(user=request.user)
     uk = UserKey.objects.get(user=request.user)
 
 
     if request.method == 'POST':
     if request.method == 'POST':
-        form = SecretImportForm(request.POST)
+        form = forms.SecretImportForm(request.POST)
         if form.is_valid():
         if form.is_valid():
 
 
             new_secrets = []
             new_secrets = []
@@ -183,7 +180,7 @@ def secret_import(request):
                             secret.save()
                             secret.save()
                             new_secrets.append(secret)
                             new_secrets.append(secret)
 
 
-                    table = SecretTable(new_secrets)
+                    table = tables.SecretTable(new_secrets)
                     messages.success(request, "Imported {} new secrets".format(len(new_secrets)))
                     messages.success(request, "Imported {} new secrets".format(len(new_secrets)))
 
 
                     return render(request, 'import_success.html', {
                     return render(request, 'import_success.html', {
@@ -194,7 +191,7 @@ def secret_import(request):
                     form.add_error('csv', "Record {}: {}".format(len(new_secrets) + 1, e.__cause__))
                     form.add_error('csv', "Record {}: {}".format(len(new_secrets) + 1, e.__cause__))
 
 
     else:
     else:
-        form = SecretImportForm()
+        form = forms.SecretImportForm()
 
 
     return render(request, 'secrets/secret_import.html', {
     return render(request, 'secrets/secret_import.html', {
         'form': form,
         'form': form,
@@ -205,7 +202,7 @@ def secret_import(request):
 class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
 class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
     permission_required = 'secrets.change_secret'
     permission_required = 'secrets.change_secret'
     cls = Secret
     cls = Secret
-    form = SecretBulkEditForm
+    form = forms.SecretBulkEditForm
     template_name = 'secrets/secret_bulk_edit.html'
     template_name = 'secrets/secret_bulk_edit.html'
     default_redirect_url = 'secrets:secret_list'
     default_redirect_url = 'secrets:secret_list'
 
 
@@ -223,5 +220,5 @@ class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
 class SecretBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
 class SecretBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
     permission_required = 'secrets.delete_secret'
     permission_required = 'secrets.delete_secret'
     cls = Secret
     cls = Secret
-    form = SecretBulkDeleteForm
+    form = forms.SecretBulkDeleteForm
     default_redirect_url = 'secrets:secret_list'
     default_redirect_url = 'secrets:secret_list'

+ 0 - 3
netbox/users/admin.py

@@ -1,3 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.

+ 0 - 3
netbox/users/tests.py

@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.

+ 4 - 0
netbox/users/urls.py

@@ -2,9 +2,13 @@ from django.conf.urls import url
 
 
 from . import views
 from . import views
 
 
+
 urlpatterns = [
 urlpatterns = [
+
+    # User profiles
     url(r'^profile/$', views.profile, name='profile'),
     url(r'^profile/$', views.profile, name='profile'),
     url(r'^profile/password/$', views.change_password, name='change_password'),
     url(r'^profile/password/$', views.change_password, name='change_password'),
     url(r'^profile/user-key/$', views.userkey, name='userkey'),
     url(r'^profile/user-key/$', views.userkey, name='userkey'),
     url(r'^profile/user-key/edit/$', views.userkey_edit, name='userkey_edit'),
     url(r'^profile/user-key/edit/$', views.userkey_edit, name='userkey_edit'),
+
 ]
 ]

+ 1 - 0
netbox/users/views.py

@@ -9,6 +9,7 @@ from django.utils.http import is_safe_url
 
 
 from secrets.forms import UserKeyForm
 from secrets.forms import UserKeyForm
 from secrets.models import UserKey
 from secrets.models import UserKey
+
 from .forms import LoginForm, PasswordChangeForm
 from .forms import LoginForm, PasswordChangeForm
 
 
 
 

+ 0 - 1
netbox/utilities/fields.py

@@ -3,7 +3,6 @@ from django.db import models
 
 
 class NullableCharField(models.CharField):
 class NullableCharField(models.CharField):
     description = "Stores empty values as NULL rather than ''"
     description = "Stores empty values as NULL rather than ''"
-    #__metaclass__ = models.SubfieldBase
 
 
     def to_python(self, value):
     def to_python(self, value):
         if isinstance(value, models.CharField):
         if isinstance(value, models.CharField):

+ 6 - 4
netbox/utilities/views.py

@@ -1,8 +1,10 @@
+from django_tables2 import RequestConfig
+
 from django.conf import settings
 from django.conf import settings
 from django.contrib import messages
 from django.contrib import messages
 from django.contrib.admin.views.decorators import staff_member_required
 from django.contrib.admin.views.decorators import staff_member_required
 from django.contrib.contenttypes.models import ContentType
 from django.contrib.contenttypes.models import ContentType
-from django.core.urlresolvers import reverse, NoReverseMatch
+from django.core.urlresolvers import reverse
 from django.db import transaction, IntegrityError
 from django.db import transaction, IntegrityError
 from django.db.models import ProtectedError
 from django.db.models import ProtectedError
 from django.http import HttpResponseRedirect
 from django.http import HttpResponseRedirect
@@ -12,12 +14,11 @@ from django.utils.decorators import method_decorator
 from django.utils.http import is_safe_url
 from django.utils.http import is_safe_url
 from django.views.generic import View
 from django.views.generic import View
 
 
-from django_tables2 import RequestConfig
+from extras.models import ExportTemplate
 
 
 from .error_handlers import handle_protectederror
 from .error_handlers import handle_protectederror
 from .forms import ConfirmationForm
 from .forms import ConfirmationForm
 from .paginator import EnhancedPaginator
 from .paginator import EnhancedPaginator
-from extras.models import ExportTemplate
 
 
 
 
 class ObjectListView(View):
 class ObjectListView(View):
@@ -45,7 +46,8 @@ class ObjectListView(View):
                                           filename='netbox_{}'.format(self.queryset.model._meta.verbose_name_plural))
                                           filename='netbox_{}'.format(self.queryset.model._meta.verbose_name_plural))
                 return response
                 return response
             except TemplateSyntaxError:
             except TemplateSyntaxError:
-                messages.error(request, "There was an error rendering the selected export template ({}).".format(et.name))
+                messages.error(request, "There was an error rendering the selected export template ({})."
+                               .format(et.name))
 
 
         # Attempt to redirect automatically if the query returns a single result
         # Attempt to redirect automatically if the query returns a single result
         if self.redirect_on_single_result and self.queryset.count() == 1:
         if self.redirect_on_single_result and self.queryset.count() == 1: