Repository: carltongibson/django-filter

Issue:
Handle `RemovedInDjango110Warning` Notices
Running the test suite for `py34-django-latest` we get a number of `RemovedInDjango110Warning` notices...

```
django_filters/filterset.py:104: RemovedInDjango110Warning: 

  'get_field_by_name is an unofficial API that has been deprecated. 
  You may be able to replace it with 'get_field()'
      rel, model, direct, m2m = opts.get_field_by_name(parts[-1])

django_filters/filterset.py:90: RemovedInDjango110Warning: 

  'get_field_by_name is an unofficial API that has been deprecated. 
  You may be able to replace it with 'get_field()'
      rel = opts.get_field_by_name(name)[0]

django-filter/tests/test_filterset.py:195: RemovedInDjango110Warning: 

  'get_field_by_name is an unofficial API that has been deprecated. 
  You may be able to replace it with 'get_field()'
       f = User._meta.get_field_by_name('comments')[0]

django-filter/tests/test_filterset.py:222: RemovedInDjango110Warning:

   'get_field_by_name is an unofficial API that has been deprecated. 
   You may be able to replace it with 'get_field()'
       f = Worker._meta.get_field_by_name('employers')[0]

django-filter/tests/test_filterset.py:204: RemovedInDjango110Warning:

  'get_field_by_name is an unofficial API that has been deprecated. 
  You may be able to replace it with 'get_field()'
      f = Book._meta.get_field_by_name('lovers')[0]

django-filter/tests/test_filterset.py:213: RemovedInDjango110Warning:

    'get_field_by_name is an unofficial API that has been deprecated. 
    You may be able to replace it with 'get_field()'
        f = DirectedNode._meta.get_field_by_name('inbound_nodes')[0]

django-filter/tests/test_filterset.py:186: RemovedInDjango110Warning: 

   'get_field_by_name is an unofficial API that has been deprecated. 
   You may be able to replace it with 'get_field()'
       f = Account._meta.get_field_by_name('profile')[0]

django-filter/.tox/py34-django-latest/lib/python3.4/site-packages/django/test/testcases.py:229: RemovedInDjango110Warning: 

   SimpleTestCase.urls is deprecated and will be removed in Django 1.10. 
   Use @override_settings(ROOT_URLCONF=...) in GenericClassBasedViewTests instead.
       self._urlconf_setup()

django-filter/tests/urls.py:13: RemovedInDjango110Warning: 

   django.conf.urls.patterns() is deprecated and will be removed in Django 1.10. 
   Update your urlpatterns to be a list of django.conf.urls.url() instances instead.
       (r'^books/$', FilterView.as_view(model=Book)),

django-filter/.tox/py34-django-latest/lib/python3.4/site-packages/django/conf/urls/__init__.py:89: RemovedInDjango110Warning: 

  Support for string view arguments to url() is deprecated and will be removed in Django 1.10 
  (got django_filters.views.object_filter). 
  Pass the callable instead.
      t = url(prefix=prefix, *t)

django-filter/.tox/py34-django-latest/lib/python3.4/site-packages/django/template/utils.py:37: RemovedInDjango110Warning: 

  You haven't defined a TEMPLATES setting. 
  You must do so before upgrading to Django 1.10. 
  Otherwise Django will be unable to load templates. "unable to load templates.", RemovedInDjango110Warning)

django-filter/.tox/py34-django-latest/lib/python3.4/site-packages/django/test/testcases.py:229: RemovedInDjango110Warning: 

   SimpleTestCase.urls is deprecated and will be removed in Django 1.10. 
   Use @override_settings(ROOT_URLCONF=...) in GenericFunctionalViewTests instead.
        self._urlconf_setup()
```



Discussion:
this is a _meta API refactor issue


Resolving patch:
diff --git a/django_filters/filterset.py b/django_filters/filterset.py
--- a/django_filters/filterset.py
+++ b/django_filters/filterset.py
@@ -71,7 +71,7 @@ def get_model_field(model, f):
     opts = model._meta
     for name in parts[:-1]:
         try:
-            rel = opts.get_field_by_name(name)[0]
+            rel = opts.get_field(name)
         except FieldDoesNotExist:
             return None
         if isinstance(rel, ForeignObjectRel):
@@ -85,7 +85,7 @@ def get_model_field(model, f):
             model = rel.rel.to
             opts = model._meta
     try:
-        rel, model, direct, m2m = opts.get_field_by_name(parts[-1])
+        rel = opts.get_field(parts[-1])
     except FieldDoesNotExist:
         return None
     return rel
@@ -134,18 +134,18 @@ def filters_for_model(model, fields=None, exclude=None, filter_for_field=None,
 
 def get_full_clean_override(together):
     def full_clean(form):
-        
+
         def add_error(message):
             try:
                 form.add_error(None, message)
             except AttributeError:
                 form._errors[NON_FIELD_ERRORS] = message
-        
+
         def all_valid(fieldset):
             cleaned_data = form.cleaned_data
             count = len([i for i in fieldset if cleaned_data.get(i)])
             return 0 < count < len(fieldset)
-        
+
         super(form.__class__, form).full_clean()
         message = 'Following fields must be together: %s'
         if isinstance(together[0], (list, tuple)):
@@ -166,7 +166,7 @@ def __init__(self, options=None):
         self.order_by = getattr(options, 'order_by', False)
 
         self.form = getattr(options, 'form', forms.Form)
-        
+
         self.together = getattr(options, 'together', None)
 
 
diff --git a/runtests.py b/runtests.py
--- a/runtests.py
+++ b/runtests.py
@@ -27,6 +27,10 @@
         USE_TZ=True,
         SECRET_KEY='foobar',
         SILENCED_SYSTEM_CHECKS=['1_7.W001'],
+        TEMPLATES=[{
+            'BACKEND': 'django.template.backends.django.DjangoTemplates',
+            'APP_DIRS': True,
+        }],
         **test_runners_args
     )
 


Test patch:
diff --git a/tests/test_filterset.py b/tests/test_filterset.py
--- a/tests/test_filterset.py
+++ b/tests/test_filterset.py
@@ -120,7 +120,7 @@ def test_filter_found_for_field(self):
         result = FilterSet.filter_for_field(f, 'username')
         self.assertIsInstance(result, CharFilter)
         self.assertEqual(result.name, 'username')
-    
+
     def test_filter_found_for_uuidfield(self):
         if UUIDTestModel is None:
             self.assertLess(django.VERSION, (1, 8))
@@ -193,7 +193,7 @@ def test_filter_overrides(self):
 class FilterSetFilterForReverseFieldTests(TestCase):
 
     def test_reverse_o2o_relationship(self):
-        f = Account._meta.get_field_by_name('profile')[0]
+        f = Account._meta.get_field('profile')
         result = FilterSet.filter_for_reverse_field(f, 'profile')
         self.assertIsInstance(result, ModelChoiceFilter)
         self.assertEqual(result.name, 'profile')
@@ -202,7 +202,7 @@ def test_reverse_o2o_relationship(self):
         self.assertEqual(result.extra['queryset'].model, Profile)
 
     def test_reverse_fk_relationship(self):
-        f = User._meta.get_field_by_name('comments')[0]
+        f = User._meta.get_field('comments')
         result = FilterSet.filter_for_reverse_field(f, 'comments')
         self.assertIsInstance(result, ModelMultipleChoiceFilter)
         self.assertEqual(result.name, 'comments')
@@ -211,7 +211,7 @@ def test_reverse_fk_relationship(self):
         self.assertEqual(result.extra['queryset'].model, Comment)
 
     def test_reverse_m2m_relationship(self):
-        f = Book._meta.get_field_by_name('lovers')[0]
+        f = Book._meta.get_field('lovers')
         result = FilterSet.filter_for_reverse_field(f, 'lovers')
         self.assertIsInstance(result, ModelMultipleChoiceFilter)
         self.assertEqual(result.name, 'lovers')
@@ -220,7 +220,7 @@ def test_reverse_m2m_relationship(self):
         self.assertEqual(result.extra['queryset'].model, User)
 
     def test_reverse_non_symmetrical_selfref_m2m_field(self):
-        f = DirectedNode._meta.get_field_by_name('inbound_nodes')[0]
+        f = DirectedNode._meta.get_field('inbound_nodes')
         result = FilterSet.filter_for_reverse_field(f, 'inbound_nodes')
         self.assertIsInstance(result, ModelMultipleChoiceFilter)
         self.assertEqual(result.name, 'inbound_nodes')
@@ -229,7 +229,7 @@ def test_reverse_non_symmetrical_selfref_m2m_field(self):
         self.assertEqual(result.extra['queryset'].model, DirectedNode)
 
     def test_reverse_m2m_field_with_through_model(self):
-        f = Worker._meta.get_field_by_name('employers')[0]
+        f = Worker._meta.get_field('employers')
         result = FilterSet.filter_for_reverse_field(f, 'employers')
         self.assertIsInstance(result, ModelMultipleChoiceFilter)
         self.assertEqual(result.name, 'employers')
@@ -662,14 +662,14 @@ def setUp(self):
         self.alex = User.objects.create(username='alex', status=1)
         self.jacob = User.objects.create(username='jacob', status=2)
         self.qs = User.objects.all().order_by('id')
-    
+
     def test_fields_set(self):
         class F(FilterSet):
             class Meta:
                 model = User
                 fields = ['username', 'status', 'is_active', 'first_name']
                 together = [
-                    ('username', 'status'), 
+                    ('username', 'status'),
                     ('first_name', 'is_active'),
                 ]
 
@@ -680,14 +680,14 @@ class Meta:
         f = F({'username': 'alex', 'status': 1}, queryset=self.qs)
         self.assertEqual(f.qs.count(), 1)
         self.assertQuerysetEqual(f.qs, [self.alex.pk], lambda o: o.pk)
-        
+
     def test_single_fields_set(self):
         class F(FilterSet):
             class Meta:
                 model = User
                 fields = ['username', 'status']
                 together = ['username', 'status']
-        
+
         f = F({}, queryset=self.qs)
         self.assertEqual(f.qs.count(), 2)
         f = F({'username': 'alex'}, queryset=self.qs)
diff --git a/tests/test_views.py b/tests/test_views.py
--- a/tests/test_views.py
+++ b/tests/test_views.py
@@ -2,7 +2,7 @@
 from __future__ import unicode_literals
 
 from django.core.exceptions import ImproperlyConfigured
-from django.test import TestCase
+from django.test import TestCase, override_settings
 from django.test.client import RequestFactory
 
 from django_filters.views import FilterView
@@ -11,8 +11,8 @@
 from .models import Book
 
 
+@override_settings(ROOT_URLCONF='tests.urls')
 class GenericViewTestCase(TestCase):
-    urls = 'tests.urls'
 
     def setUp(self):
         Book.objects.create(
@@ -78,4 +78,3 @@ def test_view_filtering_on_price(self):
         for b in ['Ender&#39;s Game', 'Rainbow Six']:
             self.assertNotContains(response, b)
         self.assertContains(response, 'Snowcrash')
-
diff --git a/tests/urls.py b/tests/urls.py
--- a/tests/urls.py
+++ b/tests/urls.py
@@ -1,14 +1,13 @@
 from __future__ import absolute_import
 from __future__ import unicode_literals
 
-from django.conf.urls import patterns
+from django.conf.urls import url
 
-from django_filters.views import FilterView
+from django_filters.views import FilterView, object_filter
 from .models import Book
 
 
-urlpatterns = patterns('',
-    (r'^books-legacy/$',
-        'django_filters.views.object_filter', {'model': Book}),
-    (r'^books/$', FilterView.as_view(model=Book)),
-)
+urlpatterns = [
+    url(r'^books-legacy/$', object_filter, {'model': Book}),
+    url(r'^books/$', FilterView.as_view(model=Book)),
+]