Repository: carltongibson/django-filter

Issue:
Test to show that templates from drf extensions can't be loaded
I'm not sure there is a bug, but I can't find a way to load templates from `django_filters/rest_framework/templates/...`

Maybe it is solvable through settings but I didn't find it yet.

The test is to show what I'm talking about.



Discussion:

Resolving patch:
diff --git a/django_filters/rest_framework/backends.py b/django_filters/rest_framework/backends.py
--- a/django_filters/rest_framework/backends.py
+++ b/django_filters/rest_framework/backends.py
@@ -1,22 +1,45 @@
 
 from __future__ import absolute_import
 
-from django.template import loader
+from django.template import Template, TemplateDoesNotExist, loader
+from rest_framework.compat import template_render
 from rest_framework.filters import BaseFilterBackend
 
 from .. import compat
 from . import filterset
 
 
+CRISPY_TEMPLATE = """
+{% load crispy_forms_tags %}
+{% load i18n %}
+
+<h2>{% trans "Field filters" %}</h2>
+{% crispy filter.form %}
+"""
+
+
+FILTER_TEMPLATE = """
+{% load i18n %}
+<h2>{% trans "Field filters" %}</h2>
+<form class="form" action="" method="get">
+    {{ filter.form.as_p }}
+    <button type="submit" class="btn btn-primary">{% trans "Submit" %}</button>
+</form>
+"""
+
+
 if compat.is_crispy:
-    filter_template = 'django_filters/rest_framework/crispy_form.html'
+    template_path = 'django_filters/rest_framework/crispy_form.html'
+    template_default = Template(CRISPY_TEMPLATE)
+
 else:
-    filter_template = 'django_filters/rest_framework/form.html'
+    template_path = 'django_filters/rest_framework/form.html'
+    template_default = Template(FILTER_TEMPLATE)
 
 
 class DjangoFilterBackend(BaseFilterBackend):
     default_filter_set = filterset.FilterSet
-    template = filter_template
+    template = template_path
 
     def get_filter_class(self, view, queryset=None):
         """
@@ -57,8 +80,12 @@ def to_html(self, request, queryset, view):
         if not filter_class:
             return None
         filter_instance = filter_class(request.query_params, queryset=queryset)
-        context = {
+
+        try:
+            template = loader.get_template(self.template)
+        except TemplateDoesNotExist:
+            template = template_default
+
+        return template_render(template, context={
             'filter': filter_instance
-        }
-        template = loader.get_template(self.template)
-        return compat.template_render(template, context)
+        })


Test patch:
diff --git a/tests/rest_framework/__init__.py b/tests/rest_framework/__init__.py
--- a/tests/rest_framework/__init__.py
+++ b/tests/rest_framework/__init__.py
@@ -0,0 +1 @@
+default_app_config = 'tests.rest_framework.apps.RestFrameworkTestConfig'
diff --git a/tests/rest_framework/apps.py b/tests/rest_framework/apps.py
new file mode 100644
--- /dev/null
+++ b/tests/rest_framework/apps.py
@@ -0,0 +1,8 @@
+
+from django.apps import AppConfig
+
+
+class RestFrameworkTestConfig(AppConfig):
+    name = 'tests.rest_framework'
+    label = 'drf_test_app'
+    verbose_name = "Rest Framework Test App"
diff --git a/tests/rest_framework/templates/filter_template.html b/tests/rest_framework/templates/filter_template.html
new file mode 100644
--- /dev/null
+++ b/tests/rest_framework/templates/filter_template.html
@@ -0,0 +1 @@
+Test
diff --git a/tests/rest_framework/test_backends.py b/tests/rest_framework/test_backends.py
--- a/tests/rest_framework/test_backends.py
+++ b/tests/rest_framework/test_backends.py
@@ -280,6 +280,53 @@ def test_unknown_filter(self):
         response = view(request).render()
         self.assertEqual(response.status_code, status.HTTP_200_OK)
 
+    def test_html_rendering(self):
+        """
+        Make sure response renders w/ backend
+        """
+        view = FilterFieldsRootView.as_view()
+        request = factory.get('/')
+        request.META['HTTP_ACCEPT'] = 'text/html'
+        response = view(request).render()
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+
+    def test_backend_output(self):
+        """
+        Ensure backend renders default if template path does not exist
+        """
+        view = FilterFieldsRootView()
+        backend = view.filter_backends[0]
+        request = view.initialize_request(factory.get('/'))
+        html = backend().to_html(request, view.get_queryset(), view)
+
+        self.assertHTMLEqual(html, """
+        <h2>Field filters</h2>
+        <form class="form" action="" method="get">
+            <p>
+                <label for="id_decimal">Decimal:</label>
+                <input id="id_decimal" name="decimal" step="any" type="number" />
+                <span class="helptext">Filter</span>
+            </p>
+            <p>
+                <label for="id_date">Date:</label>
+                <input id="id_date" name="date" type="text" />
+                <span class="helptext">Filter</span>
+            </p>
+            <button type="submit" class="btn btn-primary">Submit</button>
+        </form>
+        """)
+
+    def test_template_path(self):
+        view = FilterFieldsRootView()
+
+        class Backend(view.filter_backends[0]):
+            template = 'filter_template.html'
+
+        request = view.initialize_request(factory.get('/'))
+        html = Backend().to_html(request, view.get_queryset(), view)
+
+        self.assertHTMLEqual(html, "Test")
+
 
 @override_settings(ROOT_URLCONF='tests.rest_framework.test_backends')
 class IntegrationTestDetailFiltering(CommonFilteringTestCase):
diff --git a/tests/settings.py b/tests/settings.py
--- a/tests/settings.py
+++ b/tests/settings.py
@@ -7,12 +7,15 @@
 
 INSTALLED_APPS = (
     'django.contrib.contenttypes',
+    'django.contrib.staticfiles',
     'django.contrib.auth',
-    'django_filters',
-    'tests',
+    'rest_framework',
     'tests.rest_framework',
+    'tests',
 )
 
+MIDDLEWARE = []
+
 ROOT_URLCONF = 'tests.urls'
 
 USE_TZ = True
@@ -25,7 +28,7 @@
 }]
 
 
-MIDDLEWARE = []
+STATIC_URL = '/static/'
 
 
 # help verify that DEFAULTS is importable from conf.