diff --git a/.travis.yml b/.travis.yml index 42449ea..bd30e9e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,22 +1,17 @@ language: python env: - - TOX_ENV=py26-15 - - TOX_ENV=py26-16 - - TOX_ENV=py27-15 - - TOX_ENV=py27-16 - - TOX_ENV=py27-17 - - TOX_ENV=py27-18 - - TOX_ENV=py27-19 - - TOX_ENV=py33-17 - - TOX_ENV=py33-18 - - TOX_ENV=py34-17 - - TOX_ENV=py34-18 - - TOX_ENV=py34-19 - - TOX_ENV=pypy-15 - - TOX_ENV=pypy-16 - - TOX_ENV=pypy-17 - - TOX_ENV=pypy-18 - - TOX_ENV=pypy-19 + - TOX_ENV=py27-111 + - TOX_ENV=py34-111 + - TOX_ENV=py34-20 + - TOX_ENV=py35-111 + - TOX_ENV=py35-20 + - TOX_ENV=py36-111 + - TOX_ENV=py36-20 +matrix: + allow_failures: + - env: TOX_ENV=py34-20 + - env: TOX_ENV=py35-20 + - env: TOX_ENV=py36-20 before_install: - sudo pip install tox script: @@ -29,4 +24,4 @@ deploy: on: tags: true repo: gregmuellegger/django-mobile - condition: "$TOX_ENV = py34-18" + condition: "$TOX_ENV = py34-111" diff --git a/CHANGES.rst b/CHANGES.rst index 7d16dc9..15b35e4 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,10 @@ Changelog .. _#68: https://github.com/gregmuellegger/django-mobile/issues/68 +* `#81`_: Django 1.11 support. + +.. _#81: https://github.com/gregmuellegger/django-mobile/issues/81 + 0.7.0 ----- @@ -66,7 +70,7 @@ Changelog ----- * FIX: Cookie backend actually never really worked. Thanks to demidov91 for - the report. + the report. 0.2.3 ----- diff --git a/README.rst b/README.rst index 289705e..9c22e7c 100644 --- a/README.rst +++ b/README.rst @@ -19,6 +19,9 @@ steps: 2. The template loader takes then care of choosing the correct templates based on the flavour detected in the middleware. +Compatibility +============= +Compatible with Django 1.11 LTS. Installation ============ @@ -153,7 +156,7 @@ You can also use django's caching middlewares ``FetchFromCacheMiddleware`` like you already do. But to make them aware of flavours, you need to add ``django_mobile.cache.middleware.FetchFromCacheFlavourMiddleware`` item before standard Django ``FetchFromCacheMiddleware`` -in the ``MIDDLEWARE_CLASSES`` settings and ``django_mobile.cache.middleware.UpdateCacheFlavourMiddleware`` before +in the ``MIDDLEWARE_CLASSES`` settings and ``django_mobile.cache.middleware.UpdateCacheFlavourMiddleware`` before ``django_mobile.cache.middleware.UpdateCacheMiddleware`` correspondingly. It is necessary to split the usage of ``CacheMiddleware`` because some additional work should be done on request and response *before* standard caching behavior and that is not possible while using two complete middlewares in either order @@ -240,36 +243,36 @@ changed in your own ``settings.py``: ``FLAVOURS`` A list of available flavours for your site. - + **Default:** ``('full', 'mobile')`` ``DEFAULT_MOBILE_FLAVOUR`` The flavour which is chosen if the built-in ``MobileDetectionMiddleware`` detects a mobile browser. - + **Default:** ``'mobile'`` ``FLAVOURS_COOKIE_HTTPONLY`` The value that get passed into ``HttpResponse.set_cookie``'s ``httponly`` argument. Set this to ``True`` if you don't want the Javascript code to be able to read the flavour cookie. - + **Default:** ``False`` ``FLAVOURS_COOKIE_KEY`` The cookie name that is used for storing the selected flavour in the browser. This is only used if ``FLAVOURS_STORAGE_BACKEND`` is set to ``'cookie'``. - + **Default:** ``'flavour'`` ``FLAVOURS_TEMPLATE_PREFIX`` This string will be prefixed to the template names when searching for flavoured templates. This is useful if you have many flavours and want to store them in a common subdirectory. Example: - + .. code-block:: python - + from django.template.loader import render_to_string from django_mobile import set_flavour @@ -283,14 +286,14 @@ changed in your own ``settings.py``: set_flavour('mobile') render_to_string('index.html') # will render 'flavours/mobile/index.html' - + **Default:** ``''`` (empty string) ``FLAVOURS_TEMPLATE_LOADERS`` **django-mobile**'s template loader can load templates prefixed with the current flavour. Specify with this setting which loaders are used to load flavoured templates. - + **Default:** same as ``TEMPLATE_LOADERS`` setting but without ``'django_mobile.loader.Loader'``. @@ -298,20 +301,20 @@ changed in your own ``settings.py``: Users can change the flavour they want to look at with a HTTP GET parameter. This determines the name of this parameter. Set it to ``None`` to disable. - + **Default:** ``'flavour'`` ``FLAVOURS_SESSION_KEY`` The user's preference set with the GET parameter is stored in the user's session. This setting determines which session key is used to hold this information. - + **Default:** ``'flavour'`` ``FLAVOURS_STORAGE_BACKEND`` Determines how the selected flavour is stored persistently. Available values: ``'session'`` and ``'cookie'``. - + **Default:** ``'cookie'`` Cache Settings diff --git a/django_mobile/conf.py b/django_mobile/conf.py index 3ffc804..2034f7a 100644 --- a/django_mobile/conf.py +++ b/django_mobile/conf.py @@ -30,7 +30,13 @@ class defaults(object): FLAVOURS_COOKIE_HTTPONLY = False FLAVOURS_SESSION_KEY = u'flavour' FLAVOURS_TEMPLATE_LOADERS = [] - for loader in django_settings.TEMPLATE_LOADERS: + + DEFAULT_TEMPLATE_LOADERS = [] + for template_engine in django_settings.TEMPLATES: + DEFAULT_TEMPLATE_LOADERS += template_engine.get( + 'OPTIONS', {}).get('loaders', []) + + for loader in DEFAULT_TEMPLATE_LOADERS: if isinstance(loader, (tuple, list)) and loader[0] == CACHE_LOADER_NAME: for cached_loader in loader[1]: if cached_loader != DJANGO_MOBILE_LOADER: @@ -39,4 +45,5 @@ class defaults(object): FLAVOURS_TEMPLATE_LOADERS.append(loader) FLAVOURS_TEMPLATE_LOADERS = tuple(FLAVOURS_TEMPLATE_LOADERS) + settings = SettingsProxy(django_settings, defaults) diff --git a/django_mobile/middleware.py b/django_mobile/middleware.py index 9ce62bd..e478106 100644 --- a/django_mobile/middleware.py +++ b/django_mobile/middleware.py @@ -2,9 +2,10 @@ from django_mobile import flavour_storage from django_mobile import set_flavour, _init_flavour from django_mobile.conf import settings +from django.utils.deprecation import MiddlewareMixin -class SetFlavourMiddleware(object): +class SetFlavourMiddleware(MiddlewareMixin): def process_request(self, request): _init_flavour(request) @@ -18,7 +19,7 @@ def process_response(self, request, response): return response -class MobileDetectionMiddleware(object): +class MobileDetectionMiddleware(MiddlewareMixin): user_agents_test_match = ( "w3c ", "acs-", "alav", "alca", "amoi", "audi", "avan", "benq", "bird", "blac", "blaz", "brew", @@ -44,7 +45,8 @@ class MobileDetectionMiddleware(object): )) http_accept_regex = re.compile("application/vnd\.wap\.xhtml\+xml", re.IGNORECASE) - def __init__(self): + def __init__(self, get_response=None, *args, **kwargs): + self.get_response = get_response user_agents_test_match = r'^(?:%s)' % '|'.join(self.user_agents_test_match) self.user_agents_test_match_regex = re.compile(user_agents_test_match, re.IGNORECASE) self.user_agents_test_search_regex = re.compile(self.user_agents_test_search, re.IGNORECASE) diff --git a/django_mobile_tests/settings.py b/django_mobile_tests/settings.py index 53c8c54..5f8d51e 100644 --- a/django_mobile_tests/settings.py +++ b/django_mobile_tests/settings.py @@ -43,15 +43,8 @@ ROOT_URLCONF = 'django_mobile_tests.urls' # List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - ('django_mobile.loader.CachedLoader', ( - 'django_mobile.loader.Loader', - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - )), -) -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( 'django.middleware.common.CommonMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', @@ -59,9 +52,31 @@ 'django_mobile.middleware.SetFlavourMiddleware', ) -TEMPLATE_DIRS = ( - os.path.join(PROJECT_ROOT, 'templates'), -) +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [ + os.path.join(PROJECT_ROOT, 'templates'), + ], + 'OPTIONS': { + 'context_processors': [ + "django.contrib.auth.context_processors.auth", + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django_mobile.context_processors.flavour", + "django_mobile.context_processors.is_mobile", + ], + 'loaders': [ + ('django_mobile.loader.CachedLoader', ( + 'django_mobile.loader.Loader', + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', + )), + ] + }, + }, +] INSTALLED_APPS = ( 'django.contrib.auth', @@ -74,15 +89,6 @@ 'django_mobile_tests', ) -TEMPLATE_CONTEXT_PROCESSORS = ( - "django.contrib.auth.context_processors.auth", - "django.core.context_processors.debug", - "django.core.context_processors.i18n", - "django.core.context_processors.media", - "django_mobile.context_processors.flavour", - "django_mobile.context_processors.is_mobile", -) - import django if django.VERSION < (1, 6): diff --git a/django_mobile_tests/test_base.py b/django_mobile_tests/test_base.py index a952d62..986c333 100644 --- a/django_mobile_tests/test_base.py +++ b/django_mobile_tests/test_base.py @@ -12,6 +12,7 @@ IS_PYTHON_3 = sys.version > '3' + def _reset(): ''' Reset the thread local. @@ -20,16 +21,18 @@ def _reset(): del django_mobile._local django_mobile._local = threading.local() -def str_p3_response( string ) : + +def str_p3_response(string): """ Since response.content is a binary string in python 3, we decode it to make it comparable to str objects ( python 2 compatibility ) """ - if IS_PYTHON_3 : - return string.decode( 'ASCII' ) + if IS_PYTHON_3: + return string.decode('ASCII') return string + class BaseTestCase(TestCase): def setUp(self): _reset() @@ -158,7 +161,7 @@ def test_functional(self): result = result.strip() self.assertEqual(result, 'Hello .') # simulate RequestContext - result = render_to_string('index.html', context_instance=RequestContext(Mock())) + result = render_to_string('index.html', request=RequestContext(Mock())) result = result.strip() self.assertEqual(result, 'Hello full.') set_flavour('mobile') diff --git a/django_mobile_tests/urls.py b/django_mobile_tests/urls.py index 9e5f5a9..c6af55d 100644 --- a/django_mobile_tests/urls.py +++ b/django_mobile_tests/urls.py @@ -1,18 +1,13 @@ -try: - from django.conf.urls.defaults import * -except ImportError: - from django.conf.urls import * -from django.shortcuts import render_to_response -from django.template import RequestContext +from django.conf.urls import url +from django.shortcuts import render from django_mobile.cache import cache_page def index(request): - return render_to_response('index.html', { - }, context_instance=RequestContext(request)) + return render(request, 'index.html') -urlpatterns = patterns('', +urlpatterns = [ url(r'^$', index), url(r'^cached/$', cache_page(60*10)(index)), -) +] diff --git a/tox.ini b/tox.ini index 2767fb0..4dbc137 100644 --- a/tox.ini +++ b/tox.ini @@ -1,19 +1,17 @@ [tox] minversion = 1.8 envlist = - py26-{15,16}, - py27-{15,16,17,18,19,master}, - py33-{17,18,master}, - py34-{17,18,19,master}, - pypy-{15,16,17,18,19,master} + py27-{111}, + py34-{111,20}, + py35-{111,20,master}, + py36-{111,20,master}, + py37-{master}, + pypy-{,master} [testenv] commands = python runtests.py deps = - 15: Django >= 1.5, < 1.6 - 16: Django >= 1.6, < 1.7 - 17: Django >= 1.7, < 1.8 - 18: Django >= 1.8, < 1.9 - 19: Django >= 1.9, < 1.10 + 111: Django >= 1.10, < 2.0 + 20: Django >= 1.11, < 2.1 master: https://github.com/django/django/tarball/master#egg=Django -r{toxinidir}/requirements/tests.txt