mirror of
https://github.com/jazzband/django-analytical.git
synced 2026-03-16 22:20:25 +00:00
Add multiple domains support for Google Analytics
This commit is contained in:
parent
39af53a8c8
commit
1ae5d5c4d7
6 changed files with 161 additions and 10 deletions
|
|
@ -1,5 +1,6 @@
|
|||
Development
|
||||
-----------
|
||||
* Added multiple domains support for Google Analytics.
|
||||
* Fixed bug in deleted settings testing code (Eric Davis).
|
||||
|
||||
Version 0.9.2
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ from __future__ import absolute_import
|
|||
|
||||
import re
|
||||
|
||||
from django.conf import settings
|
||||
from django.template import Library, Node, TemplateSyntaxError
|
||||
|
||||
from analytical.utils import is_internal_ip, disable_html, get_required_setting
|
||||
from analytical.utils import is_internal_ip, disable_html, \
|
||||
get_required_setting, get_domain, AnalyticalException
|
||||
|
||||
def enumerate(sequence, start=0):
|
||||
"""Copy of the Python 2.6 `enumerate` builtin for compatibility."""
|
||||
|
|
@ -18,6 +20,10 @@ def enumerate(sequence, start=0):
|
|||
n += 1
|
||||
|
||||
|
||||
TRACK_SINGLE_DOMAIN = 1
|
||||
TRACK_MULTIPLE_SUBDOMAINS = 2
|
||||
TRACK_MULTIPLE_DOMAINS = 3
|
||||
|
||||
SCOPE_VISITOR = 1
|
||||
SCOPE_SESSION = 2
|
||||
SCOPE_PAGE = 3
|
||||
|
|
@ -38,6 +44,9 @@ SETUP_CODE = """
|
|||
|
||||
</script>
|
||||
"""
|
||||
DOMAIN_CODE = "_gaq.push(['_setDomainName', '%s']);"
|
||||
NO_ALLOW_HASH_CODE = "_gaq.push(['_setAllowHash', false]);"
|
||||
ALLOW_LINKER_CODE = "_gaq.push(['_setAllowLinker', true]);"
|
||||
CUSTOM_VAR_CODE = "_gaq.push(['_setCustomVar', %(index)s, '%(name)s', " \
|
||||
"'%(value)s', %(scope)s]);"
|
||||
|
||||
|
|
@ -65,13 +74,31 @@ class GoogleAnalyticsNode(Node):
|
|||
"must be a string looking like 'UA-XXXXXX-Y'")
|
||||
|
||||
def render(self, context):
|
||||
commands = self._get_custom_var_commands(context)
|
||||
commands = self._get_domain_commands(context)
|
||||
commands.extend(self._get_custom_var_commands(context))
|
||||
html = SETUP_CODE % {'property_id': self.property_id,
|
||||
'commands': " ".join(commands)}
|
||||
if is_internal_ip(context, 'GOOGLE_ANALYTICS'):
|
||||
html = disable_html(html, 'Google Analytics')
|
||||
return html
|
||||
|
||||
def _get_domain_commands(self, context):
|
||||
commands = []
|
||||
tracking_type = getattr(settings, 'GOOGLE_ANALYTICS_TRACKING_STYLE',
|
||||
TRACK_SINGLE_DOMAIN)
|
||||
if tracking_type == TRACK_SINGLE_DOMAIN:
|
||||
pass
|
||||
else:
|
||||
domain = get_domain(context, 'google_analytics')
|
||||
if domain is None:
|
||||
raise AnalyticalException("tracking multiple domains with Google"
|
||||
" Analytics requires a domain name")
|
||||
commands.append(DOMAIN_CODE % domain)
|
||||
commands.append(NO_ALLOW_HASH_CODE)
|
||||
if tracking_type == TRACK_MULTIPLE_DOMAINS:
|
||||
commands.append(ALLOW_LINKER_CODE)
|
||||
return commands
|
||||
|
||||
def _get_custom_var_commands(self, context):
|
||||
values = (context.get('google_analytics_var%s' % i)
|
||||
for i in range(1, 6))
|
||||
|
|
|
|||
|
|
@ -5,12 +5,15 @@ Tests for the Google Analytics template tags and filters.
|
|||
from django.http import HttpRequest
|
||||
from django.template import Context
|
||||
|
||||
from analytical.templatetags.google_analytics import GoogleAnalyticsNode
|
||||
from analytical.tests.utils import TagTestCase, override_settings, SETTING_DELETED
|
||||
from analytical.templatetags.google_analytics import GoogleAnalyticsNode, \
|
||||
TRACK_SINGLE_DOMAIN, TRACK_MULTIPLE_DOMAINS, TRACK_MULTIPLE_SUBDOMAINS
|
||||
from analytical.tests.utils import TestCase, TagTestCase, override_settings, \
|
||||
without_apps, SETTING_DELETED
|
||||
from analytical.utils import AnalyticalException
|
||||
|
||||
|
||||
@override_settings(GOOGLE_ANALYTICS_PROPERTY_ID='UA-123456-7')
|
||||
@override_settings(GOOGLE_ANALYTICS_PROPERTY_ID='UA-123456-7',
|
||||
GOOGLE_ANALYTICS_TRACKING_STYLE=TRACK_SINGLE_DOMAIN)
|
||||
class GoogleAnalyticsTagTestCase(TagTestCase):
|
||||
"""
|
||||
Tests for the ``google_analytics`` template tag.
|
||||
|
|
@ -34,6 +37,22 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
|
|||
def test_wrong_property_id(self):
|
||||
self.assertRaises(AnalyticalException, GoogleAnalyticsNode)
|
||||
|
||||
@override_settings(
|
||||
GOOGLE_ANALYTICS_TRACKING_STYLE=TRACK_MULTIPLE_SUBDOMAINS,
|
||||
GOOGLE_ANALYTICS_DOMAIN='example.com')
|
||||
def test_track_multiple_subdomains(self):
|
||||
r = GoogleAnalyticsNode().render(Context())
|
||||
self.assertTrue("_gaq.push(['_setDomainName', 'example.com']);" in r, r)
|
||||
self.assertTrue("_gaq.push(['_setAllowHash', false]);" in r, r)
|
||||
|
||||
@override_settings(GOOGLE_ANALYTICS_TRACKING_STYLE=TRACK_MULTIPLE_DOMAINS,
|
||||
GOOGLE_ANALYTICS_DOMAIN='example.com')
|
||||
def test_track_multiple_domains(self):
|
||||
r = GoogleAnalyticsNode().render(Context())
|
||||
self.assertTrue("_gaq.push(['_setDomainName', 'example.com']);" in r, r)
|
||||
self.assertTrue("_gaq.push(['_setAllowHash', false]);" in r, r)
|
||||
self.assertTrue("_gaq.push(['_setAllowLinker', true]);" in r, r)
|
||||
|
||||
def test_custom_vars(self):
|
||||
context = Context({'google_analytics_var1': ('test1', 'foo'),
|
||||
'google_analytics_var5': ('test2', 'bar', 1)})
|
||||
|
|
@ -52,3 +71,15 @@ class GoogleAnalyticsTagTestCase(TagTestCase):
|
|||
self.assertTrue(r.startswith(
|
||||
'<!-- Google Analytics disabled on internal IP address'), r)
|
||||
self.assertTrue(r.endswith('-->'), r)
|
||||
|
||||
|
||||
@without_apps('django.contrib.sites')
|
||||
@override_settings(GOOGLE_ANALYTICS_PROPERTY_ID='UA-123456-7',
|
||||
GOOGLE_ANALYTICS_TRACKING_STYLE=TRACK_MULTIPLE_DOMAINS,
|
||||
GOOGLE_ANALYTICS_DOMAIN=SETTING_DELETED,
|
||||
ANALYTICAL_DOMAIN=SETTING_DELETED)
|
||||
class NoDomainTestCase(TestCase):
|
||||
def test_exception_without_domain(self):
|
||||
context = Context()
|
||||
self.assertRaises(AnalyticalException, GoogleAnalyticsNode().render,
|
||||
context)
|
||||
|
|
@ -2,14 +2,15 @@
|
|||
Tests for the analytical.utils module.
|
||||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.http import HttpRequest
|
||||
from django.template import Context
|
||||
from django.conf import settings
|
||||
|
||||
from analytical.utils import (
|
||||
is_internal_ip, get_required_setting, AnalyticalException)
|
||||
get_domain, is_internal_ip, get_required_setting, AnalyticalException)
|
||||
from analytical.tests.utils import (
|
||||
TestCase, override_settings, SETTING_DELETED)
|
||||
TestCase, override_settings, with_apps, SETTING_DELETED)
|
||||
|
||||
|
||||
class SettingDeletedTestCase(TestCase):
|
||||
|
|
@ -40,6 +41,37 @@ class SettingDeletedTestCase(TestCase):
|
|||
user_id = get_required_setting("USER_ID", "\d+", "invalid USER_ID")
|
||||
|
||||
|
||||
@override_settings(ANALYTICAL_DOMAIN="example.org")
|
||||
class GetDomainTestCase(TestCase):
|
||||
def test_get_service_domain_from_context(self):
|
||||
context = Context({'test_domain': 'example.com'})
|
||||
self.assertEqual(get_domain(context, 'test'), 'example.com')
|
||||
|
||||
def test_get_analytical_domain_from_context(self):
|
||||
context = Context({'analytical_domain': 'example.com'})
|
||||
self.assertEqual(get_domain(context, 'test'), 'example.com')
|
||||
|
||||
@override_settings(TEST_DOMAIN="example.net")
|
||||
def test_get_service_domain_from_settings(self):
|
||||
context = Context()
|
||||
self.assertEqual(get_domain(context, 'test'), 'example.net')
|
||||
|
||||
def test_get_analytical_domain_from_settings(self):
|
||||
context = Context()
|
||||
self.assertEqual(get_domain(context, 'test'), 'example.org')
|
||||
|
||||
|
||||
@with_apps('django.contrib.sites')
|
||||
@override_settings(TEST_DOMAIN=SETTING_DELETED,
|
||||
ANALYTICAL_DOMAIN=SETTING_DELETED)
|
||||
class GetDomainTestCaseWithSites(TestCase):
|
||||
def test_get_domain_from_site(self):
|
||||
site = Site.objects.create(domain="example.com", name="test")
|
||||
with override_settings(SITE_ID=site.id):
|
||||
context = Context()
|
||||
self.assertEqual(get_domain(context, 'test'), 'example.com')
|
||||
|
||||
|
||||
class InternalIpTestCase(TestCase):
|
||||
|
||||
@override_settings(ANALYTICAL_INTERNAL_IPS=['1.1.1.1'])
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ Utility function for django-analytical.
|
|||
"""
|
||||
|
||||
from django.conf import settings
|
||||
from django.contrib.sites.models import Site
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
|
||||
HTML_COMMENT = "<!-- %(service)s disabled on internal IP " \
|
||||
|
|
@ -78,6 +80,31 @@ def get_identity(context, prefix=None, identity_func=None, user=None):
|
|||
return None
|
||||
|
||||
|
||||
def get_domain(context, prefix):
|
||||
"""
|
||||
Return the domain used for the tracking code. Each service may be
|
||||
configured with its own domain (called `<name>_domain`), or a
|
||||
django-analytical-wide domain may be set (using `analytical_domain`.
|
||||
|
||||
If no explicit domain is found in either the context or the
|
||||
settings, try to get the domain from the contrib sites framework.
|
||||
"""
|
||||
domain = context.get('%s_domain' % prefix)
|
||||
if domain is None:
|
||||
domain = context.get('analytical_domain')
|
||||
if domain is None:
|
||||
domain = getattr(settings, '%s_DOMAIN' % prefix.upper(), None)
|
||||
if domain is None:
|
||||
domain = getattr(settings, 'ANALYTICAL_DOMAIN', None)
|
||||
if domain is None:
|
||||
if 'django.contrib.sites' in settings.INSTALLED_APPS:
|
||||
try:
|
||||
domain = Site.objects.get_current().domain
|
||||
except (ImproperlyConfigured, Site.DoesNotExist):
|
||||
pass
|
||||
return domain
|
||||
|
||||
|
||||
def is_internal_ip(context, prefix=None):
|
||||
"""
|
||||
Return whether the visitor is coming from an internal IP address,
|
||||
|
|
|
|||
|
|
@ -46,8 +46,9 @@ Configuration
|
|||
=============
|
||||
|
||||
Before you can use the Google Analytics integration, you must first set
|
||||
your website property ID. You can also add custom segments for Google
|
||||
Analytics to track.
|
||||
your website property ID. If you track multiple domains with the same
|
||||
code, you also need to set-up the domain. Finally, you can add custom
|
||||
segments for Google Analytics to track.
|
||||
|
||||
|
||||
.. _google-analytics-property-id:
|
||||
|
|
@ -66,6 +67,38 @@ project :file:`settings.py` file::
|
|||
If you do not set a property ID, the tracking code will not be rendered.
|
||||
|
||||
|
||||
Tracking multiple domains
|
||||
-------------------------
|
||||
|
||||
The default code is suitable for tracking a single domain. If you track
|
||||
multiple domains, set the :const:`GOOGLE_ANALYTICS_TRACKING_STYLE`
|
||||
setting to one of the :const:`analytical.google_analytics.SCOPE_*`
|
||||
constants:
|
||||
|
||||
============================= ===== =============================================
|
||||
Constant Value Description
|
||||
============================= ===== =============================================
|
||||
``TRACK_SINGLE_DOMAIN`` 1 Track one domain.
|
||||
``TRACK_MULTIPLE_SUBDOMAINS`` 2 Track multiple subdomains of the same top
|
||||
domain (e.g. `fr.example.com` and
|
||||
`nl.example.com`).
|
||||
``TRACK_MULTIPLE_DOMAINS`` 3 Track multiple top domains (e.g. `example.fr`
|
||||
and `example.nl`).
|
||||
============================= ===== =============================================
|
||||
|
||||
As noted, the default tracking style is
|
||||
:const:`~analytical.google_analytics.TRACK_SINGLE_DOMAIN`.
|
||||
|
||||
When you track multiple (sub)domains, django-analytical needs to know
|
||||
what domain name to pass to Google Analytics. If you use the contrib
|
||||
sites app, the domain is automatically picked up from the current
|
||||
:const:`~django.contrib.sites.models.Site` instance. Otherwise, you may
|
||||
either pass the domain to the template tag through the context variable
|
||||
:const:`google_analytics_domain` (fallback: :const:`analytical_domain`)
|
||||
or set it in the project :file:`settings.py` file using
|
||||
:const:`GOOGLE_ANALYTICS_DOMAIN` (fallback: :const:`ANALYTICAL_DOMAIN`).
|
||||
|
||||
|
||||
.. _google-analytics-internal-ips:
|
||||
|
||||
Internal IP addresses
|
||||
|
|
|
|||
Loading…
Reference in a new issue