├── .bumpversion.cfg ├── .editorconfig ├── .gitignore ├── README.md ├── README.rst ├── check.sh ├── detect ├── __init__.py └── middleware.py ├── isort.sh ├── pep8.sh ├── setup.cfg └── setup.py /.bumpversion.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | commit = True 3 | tag = True 4 | current_version = 1.0.20 5 | 6 | [bumpversion:file:setup.py] 7 | search = version = '{current_version}' 8 | replace = version = '{new_version}' 9 | 10 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = false 10 | 11 | # 4 space indentation 12 | [*.py] 13 | indent_style = space 14 | indent_size = 4 15 | 16 | # Tab indentation (no size specified) 17 | [*.js] 18 | indent_style = space 19 | indent_size = 4 20 | 21 | # Tab indentation (no size specified) 22 | [*.html] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | # Matches the exact files either package.json or .travis.yml 27 | [{package.json,.travis.yml}] 28 | indent_style = space 29 | indent_size = 2 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.db 2 | *.pyc 3 | *.swp 4 | *.idea 5 | *.sqlite3 6 | *.DS_Store 7 | *.python-version 8 | 9 | build 10 | 11 | # Compiled python modules. 12 | *.pyc 13 | 14 | # Setuptools distribution folder. 15 | /dist/ 16 | 17 | # Python egg metadata, regenerated from source files by setuptools. 18 | /*.egg-info 19 | /*.egg 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # django-detect 2 | Django UserAgent Detect 3 | 4 | ## Installation 5 | ```shell 6 | pip install django-detect 7 | ``` 8 | 9 | ## Usage 10 | ```python 11 | # ####### Device、OS ####### 12 | # Windows 13 | request.Windows 14 | # Linux 15 | request.Linux 16 | # iMac/iPhone/iPad/iPod 17 | request.iMac 18 | request.iPhone 19 | request.iPad 20 | request.iPod 21 | # PC 22 | request.PC = request.Windows or request.Linux or request.iMac 23 | # iOS 24 | request.iOS = request.iPhone or request.iPad or request.iMac or request.iPod 25 | # Android and Version 26 | request.Android 27 | request.Android.version 28 | 29 | # ####### APP ####### 30 | # Weixin/Wechat and Version 31 | request.weixin 32 | request.weixin.version 33 | request.wechat 34 | request.wechat.version 35 | ``` 36 | 37 | ## Settings.py 38 | ```python 39 | # Use `MIDDLEWARE_CLASSES` prior to Django 1.10 40 | MIDDLEWARE = ( 41 | ... 42 | 'detect.middleware.UserAgentDetectionMiddleware', 43 | ... 44 | ) 45 | ``` -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ============= 2 | django-detect 3 | ============= 4 | 5 | Installation 6 | ============ 7 | 8 | :: 9 | 10 | pip install django-detect 11 | 12 | 13 | Usage 14 | ===== 15 | 16 | :: 17 | 18 | # ####### Device、OS ####### 19 | # Windows 20 | request.Windows 21 | # Linux 22 | request.Linux 23 | # iMac/iPhone/iPad/iPod 24 | request.iMac 25 | request.iPhone 26 | request.iPad 27 | request.iPod 28 | # PC 29 | request.PC = request.Windows or request.Linux or request.iMac 30 | # iOS 31 | request.iOS = request.iPhone or request.iPad or request.iMac or request.iPod 32 | # Android and Version 33 | request.Android 34 | request.Android.version 35 | 36 | # ####### APP ####### 37 | # Weixin/Wechat and Version 38 | request.weixin 39 | request.weixin.version 40 | request.wechat 41 | request.wechat.version 42 | 43 | 44 | Settings.py 45 | =========== 46 | 47 | :: 48 | 49 | # Use `MIDDLEWARE_CLASSES` prior to Django 1.10 50 | MIDDLEWARE = ( 51 | ... 52 | 'detect.middleware.UserAgentDetectionMiddleware', 53 | ... 54 | ) 55 | 56 | -------------------------------------------------------------------------------- /check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo '>> iSort' 4 | ./isort.sh 5 | echo 6 | 7 | echo '>> PEP8' 8 | ./pep8.sh 9 | echo 10 | -------------------------------------------------------------------------------- /detect/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/django-xxx/django-detect/2c6058c0f6257a0fd868e5d4cf3cc873f92c37b9/detect/__init__.py -------------------------------------------------------------------------------- /detect/middleware.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | import re 4 | 5 | from django.conf import settings 6 | from django_six import MiddlewareMixin 7 | 8 | 9 | class ConstExtendIntField(int): 10 | def __new__(cls, flag, version=''): 11 | obj = int.__new__(cls, flag) 12 | obj.version = version 13 | return obj 14 | 15 | 16 | def tfv(ua, pattern='', s=''): 17 | """ True/False and Version """ 18 | matched = re.findall(pattern, ua) 19 | return ConstExtendIntField(True, matched[0]) if matched else ConstExtendIntField(s in ua, '') 20 | 21 | 22 | class UserAgentDetectionMiddleware(MiddlewareMixin): 23 | 24 | def process_request(self, request): 25 | raw_ua = request.META.get('HTTP_USER_AGENT', '') 26 | ua = raw_ua.lower() 27 | 28 | request.raw_ua = raw_ua 29 | request.ua = ua 30 | 31 | # ####### Device、OS ####### 32 | # Windows 33 | request.Windows = 'windows nt' in ua 34 | # Linux 35 | request.Linux = 'linux x86_64' in ua 36 | # macOS 37 | request.macOS = request.iMac = 'macintosh' in ua 38 | # iPhone、iPad、iPod 39 | request.iPhone, request.iPad, request.iPod = 'iphone' in ua, 'ipad' in ua, 'ipod' in ua 40 | # PC 41 | request.PC = request.Windows or request.Linux or request.iMac or request.macOS 42 | # iOS 43 | request.iOS = request.iPhone or request.iPad or request.iPod 44 | # Android 45 | request.Android = tfv(ua, pattern=r'android ([\d.]+)', s='android') 46 | 47 | # ####### APP ####### 48 | # 百度 / Baidu 49 | # 百度APP / BaiduBoxApp 50 | request.bd = request.baidu = tfv(ua, pattern=r'baiduboxapp[\s/]([\d.]+)', s='baiduboxapp') 51 | # 百度智能小程序 / Swan 52 | request.bdMiniProgram = request.bdSmartProgram = tfv(ua, pattern=r'swan[\s/]([\d.]+)', s='swan') 53 | 54 | # 阿里 / Ali 55 | # 钉钉 / DingDing 56 | request.dd = request.ding = request.dingtalk = tfv(ua, pattern=r'dingtalk[\s/]([\d.]+)', s='dingtalk') 57 | 58 | # 腾讯 / Tencent 59 | # QQ 60 | # Mozilla/5.0 (iPhone; CPU iPhone OS 12_4_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 QQ/8.2.0.617 V1_IPH_SQ_8.2.0_1_APP_A Pixel/750 Core/WKWebView Device/Apple(iPhone 6) NetType/WIFI QBWebViewType/1 WKType/1 61 | # Mozilla/5.0 (Linux; Android 8.0.0; MIX 2 Build/OPR1.170623.027; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/66.0.3359.126 MQQBrowser/6.2 TBS/045008 Mobile Safari/537.36 V1_AND_SQ_8.2.0_1296_YYB_D QQ/8.2.0.4310 NetType/WIFI WebP/0.3.0 Pixel/1080 StatusBarHeight/66 SimpleUISwitch/0 62 | request.qq = tfv(ua, pattern=r' qq/([\d.]+)', s=' qq/') 63 | # 微信 / Weixin/Wechat 64 | request.wx = request.weixin = request.wechat = tfv(ua, pattern=r'micromessenger[\s/]([\d.]+)', s='micromessenger') 65 | request.pcwx = request.PCWechat = tfv(ua, pattern=r'windowswechat[\s/]([\d.]+)', s='windowswechat') 66 | request.macwx = request.MacWechat = tfv(ua, pattern=r'macwechat[\s/]([\d.]+)', s='macwechat') 67 | request.winwx = request.WindowsWechat = request.PCWechat and not request.MacWechat 68 | # 企业微信 / Weixin/Wechat Work 69 | request.wxwork = tfv(ua, pattern=r'wxwork[\s/]([\d.]+)', s='wxwork') 70 | # 微信小程序 / Weixin/Wechat MiniProgram 71 | # Refer: https://developers.weixin.qq.com/community/develop/doc/000688811bc278ab99f69ff1256000 72 | # Android.*MicroMessenger.*miniProgram 73 | # iPhone.*MicroMessenger.* 74 | # Refer: https://developers.weixin.qq.com/community/develop/doc/00044454a102f8ccf2d70d09b5b000 75 | # 微信 7.0 起小程序内嵌 web-view 的 UA 带上了 miniProgram 标识 76 | request.wxMiniProgram = request.wx and 'miniprogram' in ua 77 | 78 | # 字节跳动 / ByteDance 79 | # 字节跳动 IDE 80 | request.ttIDE = tfv(ua, pattern=r'bytedanceide[\s/]([\d.]+)', s='bytedanceide') 81 | # 头条 / Toutiao 82 | request.tt = request.toutiao = tfv(ua, pattern=r'newsarticle[\s/]([\d.]+)', s='newsarticle') 83 | # 头条小程序 / Toutiao MiniProgram 84 | request.ttMiniProgram = request.ttMicroApp = tfv(ua, pattern=r'toutiaomicroapp[\s/]([\d.]+)', s='toutiaomicroapp') 85 | # 飞书 / Lark 86 | request.fs = request.feishu = request.lark = tfv(ua, pattern=r'lark[\s/]([\d.]+)', s='lark') 87 | # 飞书 IDE 88 | request.fsIDE = tfv(ua, pattern=r'feishuide[\s/]([\d.]+)', s='feishuide') 89 | # 飞书小程序 / Feishu MiniProgram 90 | request.fsMiniProgram = request.fsMicroApp = request.eeMiniProgram = request.eeMicroApp = tfv(ua, pattern=r'eemicroapp[\s/]([\d.]+)', s='eemicroapp') 91 | 92 | # ####### Crawler ####### 93 | # curl/7.50.1 94 | request.curl = 'curl' in ua 95 | # python - requests / 2.19.1 96 | request.requests = 'requests' in ua 97 | # Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html) 98 | request.Baiduspider = 'baiduspider' in ua 99 | 100 | exts = {} 101 | if hasattr(settings, 'DJANGO_DETECT_EXT_FUNC') and hasattr(settings.DJANGO_DETECT_EXT_FUNC, '__call__'): 102 | exts = settings.DJANGO_DETECT_EXT_FUNC(request) or {} 103 | for k, v in exts.items(): 104 | setattr(request, k, v) 105 | 106 | return None 107 | -------------------------------------------------------------------------------- /isort.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | isort . 4 | -------------------------------------------------------------------------------- /pep8.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Ignoring autogenerated files 4 | # -- Migration directories 5 | # Ignoring error codes 6 | # -- E128 continuation line under-indented for visual indent 7 | # -- E501 line too long 8 | # -- E701 multiple statements on one line 9 | 10 | pycodestyle --exclude=migrations --ignore=E128,E501,E701 . 11 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [wheel] 2 | universal = 1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from setuptools import setup 4 | 5 | version = '1.0.20' 6 | 7 | 8 | setup( 9 | name='django-detect', 10 | version=version, 11 | keywords='django-detect', 12 | description='Django UserAgent Detect', 13 | long_description=open('README.md').read(), 14 | long_description_content_type='text/markdown', 15 | 16 | url='https://github.com/Brightcells/django-detect', 17 | 18 | author='Hackathon', 19 | author_email='kimi.huang@brightcells.com', 20 | 21 | packages=['detect'], 22 | py_modules=[], 23 | install_requires=['django-six'], 24 | 25 | classifiers=[ 26 | 'Development Status :: 5 - Production/Stable', 27 | 'Environment :: Web Environment', 28 | 'Framework :: Django', 29 | 'Intended Audience :: Developers', 30 | 'Programming Language :: Python', 31 | 'Topic :: Software Development :: Libraries :: Python Modules', 32 | 'Topic :: Office/Business :: Financial :: Spreadsheet', 33 | ], 34 | ) 35 | --------------------------------------------------------------------------------