Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Django 1.11 support #81

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
31 changes: 13 additions & 18 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -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:
Expand All @@ -29,4 +24,4 @@ deploy:
on:
tags: true
repo: gregmuellegger/django-mobile
condition: "$TOX_ENV = py34-18"
condition: "$TOX_ENV = py34-111"
6 changes: 5 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----

Expand Down Expand Up @@ -66,7 +70,7 @@ Changelog
-----

* FIX: Cookie backend actually never really worked. Thanks to demidov91 for
the report.
the report.

0.2.3
-----
Expand Down
27 changes: 15 additions & 12 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
============
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand All @@ -283,35 +286,35 @@ 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'``.

``FLAVOURS_GET_PARAMETER``
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
Expand Down
9 changes: 8 additions & 1 deletion django_mobile/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -39,4 +45,5 @@ class defaults(object):
FLAVOURS_TEMPLATE_LOADERS.append(loader)
FLAVOURS_TEMPLATE_LOADERS = tuple(FLAVOURS_TEMPLATE_LOADERS)


settings = SettingsProxy(django_settings, defaults)
8 changes: 5 additions & 3 deletions django_mobile/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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",
Expand All @@ -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)
Expand Down
46 changes: 26 additions & 20 deletions django_mobile_tests/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,40 @@
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',
'django_mobile.middleware.MobileDetectionMiddleware',
'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',
Expand All @@ -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):
Expand Down
11 changes: 7 additions & 4 deletions django_mobile_tests/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

IS_PYTHON_3 = sys.version > '3'


def _reset():
'''
Reset the thread local.
Expand All @@ -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()
Expand Down Expand Up @@ -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')
Expand Down
15 changes: 5 additions & 10 deletions django_mobile_tests/urls.py
Original file line number Diff line number Diff line change
@@ -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)),
)
]
18 changes: 8 additions & 10 deletions tox.ini
Original file line number Diff line number Diff line change
@@ -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