Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
selwin committed Jan 5, 2013
0 parents commit 0299032
Show file tree
Hide file tree
Showing 15 changed files with 238 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
@@ -0,0 +1,9 @@
node_modules/
.DS*
TAGS
dist
cabal-dev
*.pyc
build/
py/ua_parser.egg-info/

3 changes: 3 additions & 0 deletions AUTHORS.txt
@@ -0,0 +1,3 @@
Author:

* Selwin Ong (https://github.com/selwin)
20 changes: 20 additions & 0 deletions LICENSE.txt
@@ -0,0 +1,20 @@
Copyright (c) 2013 Selwin Ong

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2 changes: 2 additions & 0 deletions MANIFEST.in
@@ -0,0 +1,2 @@
include LICENSE.txt
include README.rst
76 changes: 76 additions & 0 deletions README.rst
@@ -0,0 +1,76 @@
Django User Agents
==================

A django package that allows easy identification of visitor's browser, OS and device information,
including whether the visitor uses a mobile phone, tablet or a touch capable device. Under the hood,
it uses `user-agents <https://github.com/selwin/python-user-agents>`_.


How to Use
==========

1. Install ``django-user-agents``, you'll have to make sure that `user-agents`_ is installed first::

pip install pyyaml ua-parser user-agents
pip install django-user-agents

2. Configure ``settings.py``:

.. code-block:: python
MIDDLEWARE_CLASSES = (
# other middlewares...
'django_user_agents.middleware.UserAgentMiddleware',
)
# Cache backend is optional, but recommended to speed up user agent parsing
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}
3. ``UserAgentMiddleware`` will add a ``user_agent`` attribute to ``request``:

.. code-block:: python
# Let's assume that the visitor uses an iPhone...
request.user_agent.is_mobile # returns True
request.user_agent.is_tablet # returns False
request.user_agent.is_touch_capable # returns True
request.user_agent.is_pc # returns False
# Accessing user agent's browser attributes
request.user_agent.browser # returns Browser(family=u'Mobile Safari', version=(5, 1), version_string='5.1')
request.user_agent.browser.family # returns 'Mobile Safari'
request.user_agent.browser.version # returns (5, 1)
request.user_agent.browser.version_string # returns '5.1'
# Operating System properties
request.user_agent.os # returns OperatingSystem(family=u'iOS', version=(5, 1), version_string='5.1')
request.user_agent.os.family # returns 'iOS'
request.user_agent.os.version # returns (5, 1)
request.user_agent.os.version_string # returns '5.1'
# Device properties
request.user_agent.device # returns Device(family='iPhone')
request.user_agent.device.family # returns 'iPhone'
You can find out more about user agent attributes at `here <https://github.com/selwin/python-user-agents>`_.


Running Tests
=============

`which django-admin.py` test django_user_agents --settings=django_user_agents.tests.settings --pythonpath=.


Changelog
=========

0.1
---

* Initial release
1 change: 1 addition & 0 deletions django_user_agents/__init__.py
@@ -0,0 +1 @@
VERSION = (0, 1)
23 changes: 23 additions & 0 deletions django_user_agents/middleware.py
@@ -0,0 +1,23 @@
from django.core.cache import cache
from django.template.defaultfilters import slugify
from django.utils.functional import SimpleLazyObject

from user_agents import parse


def get_user_agent_cached(ua_string):
# Tries to get UserAgent objects from cache before constructing a UserAgent
# from scratch because parsing regexes.yaml/json (ua-parser) is slow
key = slugify(ua_string)
user_agent = cache.get(key)
if user_agent is None:
user_agent = parse(ua_string)
cache.set(key, user_agent)
return user_agent


class UserAgentMiddleware(object):
# A middleware that adds a "user_agent" object to request
def process_request(self, request):
request.user_agent = SimpleLazyObject(
lambda: get_user_agent_cached(request.META['HTTP_USER_AGENT']))
Empty file added django_user_agents/models.py
Empty file.
1 change: 1 addition & 0 deletions django_user_agents/tests/__init__.py
@@ -0,0 +1 @@
from .tests import MiddlewareTest
33 changes: 33 additions & 0 deletions django_user_agents/tests/settings.py
@@ -0,0 +1,33 @@
from os import path


DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': ':memory:',
},
}

INSTALLED_APPS = ['django_user_agents']

MIDDLEWARE_CLASSES = (
'django_user_agents.middleware.UserAgentMiddleware',
)

ROOT_URLCONF = 'django_user_agents.tests.urls'

TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'TIMEOUT': 60,
}
}

TEMPLATE_DIRS = (
path.join(path.dirname(__file__), "templates"),
)
Empty file.
25 changes: 25 additions & 0 deletions django_user_agents/tests/tests.py
@@ -0,0 +1,25 @@
from django.core.cache import cache, get_cache
from django.core.urlresolvers import reverse
from django.template.defaultfilters import slugify
from django.test.client import Client
from django.utils import unittest

from user_agents.parsers import parse, UserAgent


iphone_ua_string = 'Mozilla/5.0 (iPhone; CPU iPhone OS 5_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B179 Safari/7534.48.3'
ipad_ua_string = 'Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10'


class MiddlewareTest(unittest.TestCase):

def test_middleware_assigns_user_agent(self):
client = Client(HTTP_USER_AGENT=ipad_ua_string)
response = client.get(reverse('user_agent_test'))
self.assertIsInstance(response.context['user_agent'], UserAgent)

def test_cache_is_set(self):
client = Client(HTTP_USER_AGENT=iphone_ua_string)
response = client.get(reverse('user_agent_test'))
self.assertIsInstance(response.context['user_agent'], UserAgent)
self.assertIsInstance(cache.get(slugify(iphone_ua_string)), UserAgent)
6 changes: 6 additions & 0 deletions django_user_agents/tests/urls.py
@@ -0,0 +1,6 @@
from django.conf.urls import patterns, url


urlpatterns = patterns('django_user_agents.tests.views',
url(r'^user-agents/', 'test', name='user_agent_test'),
)
5 changes: 5 additions & 0 deletions django_user_agents/tests/views.py
@@ -0,0 +1,5 @@
from django.shortcuts import render


def test(request):
return render(request, "test.html", {'user_agent': request.user_agent})
34 changes: 34 additions & 0 deletions setup.py
@@ -0,0 +1,34 @@
# -*- coding: utf-8 -*-
from setuptools import setup


description = "A django package that allows easy identification of visitor's "
"browser, operating system and device information (mobile phone, "
"tablet or a touch capable)."

setup(
name='django-user_agents',
version='0.1',
author='Selwin Ong',
author_email='selwin.ong@gmail.com',
packages=['django_user_agents'],
url='https://github.com/selwin/django-user_agents',
license='MIT',
description=description,
long_description=open('README.rst').read(),
zip_safe=False,
include_package_data=True,
package_data = { '': ['README.rst'] },
#install_requires=['user-agents'],
classifiers=[
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Framework :: Django',
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Software Development :: Libraries :: Python Modules',
]
)

0 comments on commit 0299032

Please sign in to comment.