Index: docs/ref/contrib/sites.txt
===================================================================
--- docs/ref/contrib/sites.txt	(revision 17914)
+++ docs/ref/contrib/sites.txt	(working copy)
@@ -215,26 +215,32 @@
 lawrence.com alerts." On LJWorld.com, the email has the subject "Thanks for
 subscribing to LJWorld.com alerts." Same goes for the email's message body.
 
-Note that an even more flexible (but more heavyweight) way of doing this would
-be to use Django's template system. Assuming Lawrence.com and LJWorld.com have
-different template directories (:setting:`TEMPLATE_DIRS`), you could simply farm out
-to the template system like so::
+The current Site object is made available in the 
+:ref:`template context <ref-templates-api>` when you use
+:class:`~django.template.context.RequestContext` and when your
+:setting:`TEMPLATE_CONTEXT_PROCESSORS` setting contains
+``"django.contrib.sites.context_processors.site"``, which is default.
 
+Using template context, an even more flexible (but more heavyweight) way of 
+sending email-notifications would be to use Django's template system::
+
     from django.core.mail import send_mail
-    from django.template import loader, Context
+    from django.template import loader, RequestContext
 
     def register_for_newsletter(request):
         # Check form values, etc., and subscribe the user.
         # ...
 
-        subject = loader.get_template('alerts/subject.txt').render(Context({}))
-        message = loader.get_template('alerts/message.txt').render(Context({}))
+        subject_template = loader.get_template('alerts/subject.txt')
+        subject = subject_template.render(RequestContext(request, {}))
+        message_template = loader.get_template('alerts/message.txt')
+        message = message_template.render(RequestContext(request, {}))
         send_mail(subject, message, 'editor@ljworld.com', [user.email])
 
         # ...
 
 In this case, you'd have to create :file:`subject.txt` and :file:`message.txt` template
-files for both the LJWorld.com and Lawrence.com template directories. That
+files that include ``{{ site.name }}`` and ``{{ site.domain }}``. That
 gives you more flexibility, but it's also more complex.
 
 It's a good idea to exploit the :class:`~django.contrib.sites.models.Site`
@@ -389,10 +395,7 @@
   checks the current :setting:`SITE_ID` in retrieving flatpages to display.
 
 * In the :mod:`syndication framework <django.contrib.syndication>`, the
-  templates for ``title`` and ``description`` automatically have access to a
-  variable ``{{ site }}``, which is the
-  :class:`~django.contrib.sites.models.Site` object representing the current
-  site. Also, the hook for providing item URLs will use the ``domain`` from
+  hook for providing item URLs will use the ``domain`` from
   the current :class:`~django.contrib.sites.models.Site` object if you don't
   specify a fully-qualified domain.
 
Index: django/conf/global_settings.py
===================================================================
--- django/conf/global_settings.py	(revision 17914)
+++ django/conf/global_settings.py	(working copy)
@@ -197,6 +197,7 @@
 # only parameter and returns a dictionary to add to the context.
 TEMPLATE_CONTEXT_PROCESSORS = (
     'django.contrib.auth.context_processors.auth',
+    'django.contrib.sites.context_processors.site',
     'django.core.context_processors.debug',
     'django.core.context_processors.i18n',
     'django.core.context_processors.media',
Index: django/contrib/syndication/views.py
===================================================================
--- django/contrib/syndication/views.py	(revision 17914)
+++ django/contrib/syndication/views.py	(working copy)
@@ -137,11 +137,11 @@
 
         for item in self.__get_dynamic_attr('items', obj):
             if title_tmp is not None:
-                title = title_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
+                title = title_tmp.render(RequestContext(request, {'obj': item}))
             else:
                 title = self.__get_dynamic_attr('item_title', item)
             if description_tmp is not None:
-                description = description_tmp.render(RequestContext(request, {'obj': item, 'site': current_site}))
+                description = description_tmp.render(RequestContext(request, {'obj': item}))
             else:
                 description = self.__get_dynamic_attr('item_description', item)
             link = add_domain(
Index: django/contrib/sites/tests/base.py
===================================================================
--- django/contrib/sites/tests/base.py	(revision 0)
+++ django/contrib/sites/tests/base.py	(revision 0)
@@ -0,0 +1,62 @@
+from django.conf import settings
+from django.contrib.sites.models import Site, RequestSite, get_current_site
+from django.core.exceptions import ObjectDoesNotExist
+from django.http import HttpRequest
+from django.test import TestCase
+
+
+class SitesFrameworkTests(TestCase):
+
+    def setUp(self):
+        Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
+        self.old_Site_meta_installed = Site._meta.installed
+        Site._meta.installed = True
+
+    def tearDown(self):
+        Site._meta.installed = self.old_Site_meta_installed
+
+    def test_save_another(self):
+        # Regression for #17415
+        # On some backends the sequence needs reset after save with explicit ID.
+        # Test that there is no sequence collisions by saving another site.
+        Site(domain="example2.com", name="example2.com").save()
+
+    def test_site_manager(self):
+        # Make sure that get_current() does not return a deleted Site object.
+        s = Site.objects.get_current()
+        self.assertTrue(isinstance(s, Site))
+        s.delete()
+        self.assertRaises(ObjectDoesNotExist, Site.objects.get_current)
+
+    def test_site_cache(self):
+        # After updating a Site object (e.g. via the admin), we shouldn't return a
+        # bogus value from the SITE_CACHE.
+        site = Site.objects.get_current()
+        self.assertEqual(u"example.com", site.name)
+        s2 = Site.objects.get(id=settings.SITE_ID)
+        s2.name = "Example site"
+        s2.save()
+        site = Site.objects.get_current()
+        self.assertEqual(u"Example site", site.name)
+
+    def test_get_current_site(self):
+        # Test that the correct Site object is returned
+        request = HttpRequest()
+        request.META = {
+            "SERVER_NAME": "example.com",
+            "SERVER_PORT": "80",
+        }
+        site = get_current_site(request)
+        self.assertTrue(isinstance(site, Site))
+        self.assertEqual(site.id, settings.SITE_ID)
+
+        # Test that an exception is raised if the sites framework is installed
+        # but there is no matching Site
+        site.delete()
+        self.assertRaises(ObjectDoesNotExist, get_current_site, request)
+
+        # A RequestSite is returned if the sites framework is not installed
+        Site._meta.installed = False
+        site = get_current_site(request)
+        self.assertTrue(isinstance(site, RequestSite))
+        self.assertEqual(site.name, u"example.com")
Index: django/contrib/sites/tests/__init__.py
===================================================================
--- django/contrib/sites/tests/__init__.py	(revision 0)
+++ django/contrib/sites/tests/__init__.py	(revision 0)
@@ -0,0 +1,3 @@
+from django.contrib.sites.tests.base import SitesFrameworkTests
+from django.contrib.sites.tests.context_processors import ContextProcessorTest
+from django.contrib.sites.tests.context_processors import RequestSiteContextTest
Index: django/contrib/sites/tests/urls.py
===================================================================
--- django/contrib/sites/tests/urls.py	(revision 0)
+++ django/contrib/sites/tests/urls.py	(revision 0)
@@ -0,0 +1,6 @@
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('',
+    (r'^context_processors/$', 'django.views.generic.simple.direct_to_template',
+        {'template': 'sites/context_processors_test.html'}),
+)
Index: django/contrib/sites/tests/context_processors.py
===================================================================
--- django/contrib/sites/tests/context_processors.py	(revision 0)
+++ django/contrib/sites/tests/context_processors.py	(revision 0)
@@ -0,0 +1,57 @@
+import os
+from django.test import TestCase
+from django.conf import settings
+from django.test.client import RequestFactory
+from django.contrib.sites.models import Site, RequestSite
+
+class ContextProcessorTest(TestCase):
+    urls = 'django.contrib.sites.tests.urls'
+    
+    def setUp(self):
+        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
+        settings.TEMPLATE_DIRS = (
+            os.path.join(
+                os.path.dirname(__file__),
+                'templates'
+            ),
+        )
+    
+    def tearDown(self):
+        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
+    
+    def test_context_processor(self):
+        site_obj = Site.objects.get_current()
+        response = self.client.get('/context_processors/')
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'site.name: %s' % site_obj.name)
+        self.assertContains(response, 'site.domain: %s' % site_obj.domain)
+    
+class RequestSiteContextTest(TestCase):
+    urls = 'django.contrib.sites.tests.urls'
+    
+    def setUp(self):
+        self.old_TEMPLATE_DIRS = settings.TEMPLATE_DIRS
+        settings.TEMPLATE_DIRS = (
+            os.path.join(
+                os.path.dirname(__file__),
+                'templates'
+            ),
+        )
+        self.old_INSTALLED_APPS = settings.INSTALLED_APPS
+        list_of_apps = list(settings.INSTALLED_APPS)
+        list_of_apps.remove('django.contrib.sites')
+        settings.INSTALLED_APPS = tuple(list_of_apps)
+        self.factory = RequestFactory()
+
+    def tearDown(self):
+        settings.TEMPLATE_DIRS = self.old_TEMPLATE_DIRS
+        settings.INSTALLED_APPS = self.old_INSTALLED_APPS
+
+    def test_context_processor_without_sites_framework(self):
+        request = self.factory.get('/context_processors/', SERVER_NAME='test.example.com')
+        response = self.client.get(request.path, **request.META)
+        site_obj = RequestSite(request)
+        self.assertEqual(response.status_code, 200)
+        self.assertContains(response, 'site.name: %s' % site_obj.name)
+        self.assertContains(response, 'site.domain: %s' % site_obj.domain)
+        
Index: django/contrib/sites/tests/templates/sites/context_processors_test.html
===================================================================
--- django/contrib/sites/tests/templates/sites/context_processors_test.html	(revision 0)
+++ django/contrib/sites/tests/templates/sites/context_processors_test.html	(revision 0)
@@ -0,0 +1,2 @@
+site.name: {{ site.name }}
+site.domain: {{ site.domain }}
Index: django/contrib/sites/tests.py
===================================================================
--- django/contrib/sites/tests.py	(revision 17914)
+++ django/contrib/sites/tests.py	(working copy)
@@ -1,62 +0,0 @@
-from django.conf import settings
-from django.contrib.sites.models import Site, RequestSite, get_current_site
-from django.core.exceptions import ObjectDoesNotExist
-from django.http import HttpRequest
-from django.test import TestCase
-
-
-class SitesFrameworkTests(TestCase):
-
-    def setUp(self):
-        Site(id=settings.SITE_ID, domain="example.com", name="example.com").save()
-        self.old_Site_meta_installed = Site._meta.installed
-        Site._meta.installed = True
-
-    def tearDown(self):
-        Site._meta.installed = self.old_Site_meta_installed
-
-    def test_save_another(self):
-        # Regression for #17415
-        # On some backends the sequence needs reset after save with explicit ID.
-        # Test that there is no sequence collisions by saving another site.
-        Site(domain="example2.com", name="example2.com").save()
-
-    def test_site_manager(self):
-        # Make sure that get_current() does not return a deleted Site object.
-        s = Site.objects.get_current()
-        self.assertTrue(isinstance(s, Site))
-        s.delete()
-        self.assertRaises(ObjectDoesNotExist, Site.objects.get_current)
-
-    def test_site_cache(self):
-        # After updating a Site object (e.g. via the admin), we shouldn't return a
-        # bogus value from the SITE_CACHE.
-        site = Site.objects.get_current()
-        self.assertEqual(u"example.com", site.name)
-        s2 = Site.objects.get(id=settings.SITE_ID)
-        s2.name = "Example site"
-        s2.save()
-        site = Site.objects.get_current()
-        self.assertEqual(u"Example site", site.name)
-
-    def test_get_current_site(self):
-        # Test that the correct Site object is returned
-        request = HttpRequest()
-        request.META = {
-            "SERVER_NAME": "example.com",
-            "SERVER_PORT": "80",
-        }
-        site = get_current_site(request)
-        self.assertTrue(isinstance(site, Site))
-        self.assertEqual(site.id, settings.SITE_ID)
-
-        # Test that an exception is raised if the sites framework is installed
-        # but there is no matching Site
-        site.delete()
-        self.assertRaises(ObjectDoesNotExist, get_current_site, request)
-
-        # A RequestSite is returned if the sites framework is not installed
-        Site._meta.installed = False
-        site = get_current_site(request)
-        self.assertTrue(isinstance(site, RequestSite))
-        self.assertEqual(site.name, u"example.com")
Index: django/contrib/sites/context_processors.py
===================================================================
--- django/contrib/sites/context_processors.py	(revision 0)
+++ django/contrib/sites/context_processors.py	(revision 0)
@@ -0,0 +1,17 @@
+from django.contrib.sites.models import Site, RequestSite
+from django.core.exceptions import ImproperlyConfigured
+from django.db import models
+
+def site(request):
+    """Sets in the present context information about the current site."""
+    # CurrentSiteManager already handles prevention of spurious database calls
+    # If the user does not have the Sites framework installed, for template
+    # purposes, which will be read-only, a RequestSite object is an appropriate
+    # fallback.
+    
+    try:
+        site_app = models.get_app('sites')
+        site_obj = Site.objects.get_current()
+    except ImproperlyConfigured:
+        site_obj = RequestSite(request)
+    return {'site': site_obj}
Index: django/contrib/auth/views.py
===================================================================
--- django/contrib/auth/views.py	(revision 17914)
+++ django/contrib/auth/views.py	(working copy)
@@ -62,7 +62,6 @@
     context = {
         'form': form,
         redirect_field_name: redirect_to,
-        'site': current_site,
         'site_name': current_site.name,
     }
     if extra_context is not None:
