Created
October 1, 2021 15:08
-
-
Save fmalina/7ab2acfa426f287acb7bdb4784dda59c to your computer and use it in GitHub Desktop.
Mobile phone detection middleware for Django
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"""Mobile phone detection middleware for Django""" | |
from django.utils.cache import patch_vary_headers | |
class MobileMiddleware: | |
def __init__(self, get_response): | |
self.get_response = get_response | |
def is_mobile(self, ua): | |
ua = ua.lower() | |
for s in ['ipad', 'tablet']: | |
if s in ua: | |
return 0 | |
for s in ['phone', 'mobile', 'symbian', 'smartphone', | |
'midp', 'wap', 'pda', 'mini', 'palm', | |
'netfront', 'opera mobi', 'windows ce']: | |
if s in ua: | |
return 1 | |
return 0 | |
def __call__(self, request): | |
ua = request.META.get('HTTP_USER_AGENT', '') | |
mobile = device = self.is_mobile(ua) | |
prefer = request.session.get('mobile', '') | |
switch = request.GET.get('mobile', '') | |
if prefer in [0, 1] and prefer != mobile: | |
mobile = prefer | |
if switch in ['0', '1']: | |
mobile = int(switch) | |
request.device = device # Is this a mobile device? | |
request.mobile = mobile # Show mobile site? | |
request.session['mobile'] = mobile | |
response = self.get_response(request) | |
# patch_vary_headers(response, ['User-Agent']) | |
return response | |
#### Tests | |
from django.contrib.sessions.models import Session | |
from django.test import Client, TestCase | |
from unittest.mock import MagicMock, Mock, patch | |
from adaptive import MobileMiddleware | |
MOBI_VERSION_SIGNATURE = 'MOBILE = true' | |
FULL_VERSION_SIGNATURE = 'MOBILE = false' | |
class MobileMiddlewareTests(TestCase): | |
def test_mobile_browser_agent(self): | |
request = Mock() | |
request.session = {} | |
request.META = {'HTTP_USER_AGENT': 'My Mobile Browser'} | |
MobileMiddleware(request) | |
self.assertEqual(request.mobile, 1) | |
def test_desktop_browser_agent(self): | |
request = Mock() | |
request.session = {} | |
request.META = {'HTTP_USER_AGENT': 'My Desktop Browser'} | |
MobileMiddleware(request) | |
self.assertEqual(request.mobile, 0) | |
def test_set_default_version(self): | |
request = Mock() | |
request.session = {} | |
request.META = MagicMock() | |
request.GET = {} | |
MobileMiddleware(request) | |
self.assertEqual(request.mobile, 0) | |
def test_set_version_through_get_parameter(self): | |
request = Mock() | |
request.session = {} | |
request.META = MagicMock() | |
request.GET = {'mobile': '1'} | |
MobileMiddleware(request) | |
self.assertEqual(request.mobile, 1) | |
TEST_URL = '/cookies' # use a very barebones view | |
class RealAgentNameTests(TestCase): | |
def assertFull(self, agent): | |
client = Client(HTTP_USER_AGENT=agent) | |
response = client.get(TEST_URL) | |
if FULL_VERSION_SIGNATURE not in response.content.decode(): | |
self.fail(f'Agent is matched as mobile: {agent}') | |
def assertMobile(self, agent): | |
client = Client(HTTP_USER_AGENT=agent) | |
response = client.get(TEST_URL) | |
if MOBI_VERSION_SIGNATURE not in response.content.decode(): | |
self.fail(f'Agent is not matched as mobile: {agent}') | |
def test_ipad(self): | |
self.assertFull('Mozilla/5.0 (iPad; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10') | |
def test_iphone(self): | |
self.assertMobile('Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like Gecko) Version/3.0 Mobile/1A543a Safari/419.3') | |
def test_motorola_xoom(self): | |
self.assertFull('Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13') | |
def test_opera_mobile_on_android(self): | |
self.assertMobile('Opera/9.80 (Android 2.3.3; Linux; Opera Mobi/ADR-1111101157; U; en) Presto/2.9.201 Version/11.50') | |
class RegressionTests(TestCase): | |
def setUp(self): | |
self.desktop = Client() | |
self.mobile = Client(HTTP_USER_AGENT='mobile') | |
def test_multiple_browser_access(self): | |
response = self.desktop.get(TEST_URL) | |
self.assertContains(response, FULL_VERSION_SIGNATURE) | |
response = self.mobile.get(TEST_URL) | |
self.assertContains(response, MOBI_VERSION_SIGNATURE) | |
response = self.desktop.get(TEST_URL) | |
self.assertContains(response, FULL_VERSION_SIGNATURE) | |
response = self.mobile.get(TEST_URL) | |
self.assertContains(response, MOBI_VERSION_SIGNATURE) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment