Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added docs/sites.txt -- documentation on the sites framework

git-svn-id: http://code.djangoproject.com/svn/django/trunk@2958 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit e3839f32e5c3c9492c0a29b3af4da28f38a3ccda 1 parent d31f190
Adrian Holovaty adrianholovaty authored
6 docs/add_ons.txt
View
@@ -77,7 +77,11 @@ sites
A light framework that lets you operate multiple Web sites off of the same
database and Django installation. It gives you hooks for associating objects to
-one or more sites. This is not yet documented.
+one or more sites.
+
+See the `sites documentation`_.
+
+.. _sites documentation: http://www.djangoproject.com/documentation/sites/
syndication
===========
3  docs/authentication.txt
View
@@ -355,7 +355,7 @@ variables:
* ``next``: The URL to redirect to after successful login. This may contain
a query string, too.
* ``site_name``: The name of the current ``Site``, according to the
- ``SITE_ID`` setting.
+ ``SITE_ID`` setting. See the `site framework docs`_.
Here's a sample ``registration/login.html`` template you can use as a starting
point. It assumes you have a ``base.html`` template that defines a ``content``
@@ -382,6 +382,7 @@ block::
{% endblock %}
.. _forms documentation: http://www.djangoproject.com/documentation/forms/
+.. _site framework docs: http://www.djangoproject.com/documentation/sites/
Limiting access to logged-in users that pass a test
---------------------------------------------------
4 docs/settings.txt
View
@@ -619,6 +619,10 @@ The ID, as an integer, of the current site in the ``django_site`` database
table. This is used so that application data can hook into specific site(s)
and a single database can manage content for multiple sites.
+See the `site framework docs`_.
+
+.. _site framework docs: http://www.djangoproject.com/documentation/sites/
+
TEMPLATE_CONTEXT_PROCESSORS
---------------------------
256 docs/sites.txt
View
@@ -0,0 +1,256 @@
+=====================
+The "sites" framework
+=====================
+
+Django comes with an optional "sites" framework. It's a hook for associating
+objects and functionality to particular Web sites, and it's a holding place for
+the domain names and "verbose" names of your Django-powered sites.
+
+Use it if your single Django installation powers more than one site and you
+need to differentiate between those sites in some way.
+
+The whole sites framework is based on two simple concepts:
+
+ * The ``Site`` model, found in ``django.contrib.sites``, has ``domain`` and
+ ``name`` fields.
+ * The ``SITE_ID`` setting specifies the database ID of the ``Site`` object
+ associated with that particular settings file.
+
+How you use this is up to you, but Django uses it in a couple of ways
+automatically via simple conventions.
+
+Example usage
+=============
+
+Why would you use sites? It's best explained through examples.
+
+Associating content with multiple sites
+---------------------------------------
+
+The Django-powered sites LJWorld.com_ and Lawrence.com_ are operated by the
+same news organization -- the Lawrence Journal-World newspaper in Lawrence,
+Kansas. LJWorld.com focuses on news, while Lawrence.com focuses on local
+entertainment. But sometimes editors want to publish an article on *both*
+sites.
+
+The brain-dead way of solving the problem would be to require site producers to
+publish the same story twice: once for LJWorld.com and again for Lawrence.com.
+But that's inefficient for site producers, and it's redundant to store
+multiple copies of the same story in the database.
+
+The better solution is simple: Both sites use the same article database, and an
+article is associated with one or more sites. In Django model terminology,
+that's represented by a ``ManyToManyField`` in the ``Article`` model::
+
+ from django.db import models
+ from django.contrib.sites.models import Site
+
+ class Article(models.Model):
+ headline = models.CharField(maxlength=200)
+ # ...
+ sites = models.ManyToManyField(Site)
+
+This accomplishes several things quite nicely:
+
+ * It lets the site producers edit all content -- on both sites -- in a
+ single interface (the Django admin).
+
+ * It means the same story doesn't have to be published twice in the
+ database; it only has a single record in the database.
+
+ * It lets the site developers use the same Django view code for both sites.
+ The view code that displays a given story just checks to make sure the
+ requested story is on the current site. It looks something like this::
+
+ from django.conf import settings
+
+ def article_detail(request, article_id):
+ try:
+ a = Article.objects.get(id=article_id, sites__id__exact=settings.SITE_ID)
+ except Article.DoesNotExist:
+ raise Http404
+ # ...
+
+.. _ljworld.com: http://www.ljworld.com/
+.. _lawrence.com: http://www.lawrence.com/
+
+Associating content with a single site
+--------------------------------------
+
+Similarly, you can associate a model to the ``Site`` model in a many-to-one
+relationship, using ``ForeignKey``.
+
+For example, if an article is only allowed on a single site, you'd use a model
+like this::
+
+ from django.db import models
+ from django.contrib.sites.models import Site
+
+ class Article(models.Model):
+ headline = models.CharField(maxlength=200)
+ # ...
+ site = models.ForeignKey(Site)
+
+This has the same benefits as described in the last section.
+
+Hooking into the current site from views
+----------------------------------------
+
+On a lower level, you can use the sites framework in your Django views to do
+particular things based on what site in which the view is being called.
+For example::
+
+ from django.conf import settings
+
+ def my_view(request):
+ if settings.SITE_ID == 3:
+ # Do something.
+ else:
+ # Do something else.
+
+Of course, it's ugly to hard-code the site IDs like that. This sort of
+hard-coding is best for hackish fixes that you need done quickly. A slightly
+cleaner way of accomplishing the same thing is to check the current site's
+domain::
+
+ from django.conf import settings
+ from django.contrib.sites.models import Site
+
+ def my_view(request):
+ current_site = Site.objects.get(id=settings.SITE_ID)
+ if current_site.domain == 'foo.com':
+ # Do something
+ else:
+ # Do something else.
+
+The idiom of retrieving the ``Site`` object for the value of
+``settings.SITE_ID`` is quite common, so the ``Site`` model's manager has a
+``get_current()`` method. This example is equivalent to the previous one::
+
+ from django.contrib.sites.models import Site
+
+ def my_view(request):
+ current_site = Site.objects.get_current()
+ if current_site.domain == 'foo.com':
+ # Do something
+ else:
+ # Do something else.
+
+Getting the current domain for display
+--------------------------------------
+
+LJWorld.com and Lawrence.com both have e-mail alert functionality, which lets
+readers sign up to get notifications when news happens. It's pretty basic: A
+reader signs up on a Web form, and he immediately gets an e-mail saying,
+"Thanks for your subscription."
+
+It'd be inefficient and redundant to implement this signup-processing code
+twice, so the sites use the same code behind the scenes. But the "thank you for
+signing up" notice needs to be different for each site. By using ``Site``
+objects, we can abstract the "thank you" notice to use the values of the
+current site's ``name`` and ``domain``.
+
+Here's an example of what the form-handling view looks like::
+
+ from django.contrib.sites.models import Site
+ from django.core.mail import send_mail
+
+ def register_for_newsletter(request):
+ # Check form values, etc., and subscribe the user.
+ # ...
+
+ current_site = Site.objects.get_current()
+ send_mail('Thanks for subscribing to %s alerts' % current_site.name,
+ 'Thanks for your subscription. We appreciate it.\n\n-The %s team.' % current_site.name,
+ 'editor@%s' % current_site.domain,
+ [user.email])
+
+ # ...
+
+On Lawrence.com, this e-mail has the subject line "Thanks for subscribing to
+lawrence.com alerts." On LJWorld.com, the e-mail has the subject "Thanks for
+subscribing to LJWorld.com alerts." Same goes for the e-mail'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 (``TEMPLATE_DIRS``), you could simply farm out
+to the template system like so::
+
+ from django.core.mail import send_mail
+ from django.template import loader, Context
+
+ 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({}))
+ send_mail(subject, message, 'editor@ljworld.com', [user.email])
+
+ # ...
+
+In this case, you'd have to create ``subject.txt`` and ``message.txt`` template
+files for both the LJWorld.com and Lawrence.com template directories. That
+gives you more flexibility, but it's also more complex.
+
+It's a good idea to exploit the ``Site`` objects as much as possible, to remove
+unneeded complexity and redundancy.
+
+Getting the current domain for full URLs
+----------------------------------------
+
+Django's ``get_absolute_url()`` convention is nice for getting your objects'
+URL without the domain name, but in some cases you might want to display the
+full URL -- with ``http://`` and the domain and everything -- for an object.
+To do this, you can use the sites framework. A simple example::
+
+ >>> from django.contrib.sites.models import Site
+ >>> obj = MyModel.objects.get(id=3)
+ >>> obj.get_absolute_url()
+ '/mymodel/objects/3/'
+ >>> Site.objects.get_current().domain
+ 'example.com'
+ >>> 'http://%s%s' % (Site.objects.get_current().domain, obj.get_absolute_url())
+ 'http://example.com/mymodel/objects/3/'
+
+How Django uses the sites framework
+===================================
+
+Although it's not required that you use the sites framework, it's strongly
+encouraged, because Django takes advantage of it in a few places. Even if your
+Django installation is powering only a single site, you should take the two
+seconds to create the site object with your ``domain`` and ``name``, and point
+to its ID in your ``SITE_ID`` setting.
+
+Here's how Django uses the sites framework:
+
+ * In the `redirects framework`_, each redirect object is associated with a
+ particular site. When Django searches for a redirect, it takes into
+ account the current ``SITE_ID``.
+
+ * In the comments framework, each comment is associated with a particular
+ site. When a comment is posted, its ``site`` is set to the current
+ ``SITE_ID``, and when comments are listed via the appropriate template
+ tag, only the comments for the current site are displayed.
+
+ * In the `flatpages framework`_, each flatpage is associated with a
+ particular site. When a flatpage is created, you specify its ``site``,
+ and the ``FlatpageFallbackMiddleware`` checks the current ``SITE_ID`` in
+ retrieving flatpages to display.
+
+ * In the `syndication framework`_, the templates for ``title`` and
+ ``description`` automatically have access to a variable ``{{{ site }}}``,
+ which is the ``Site`` object representing the current site. Also, the
+ hook for providing item URLs will use the ``domain`` from the current
+ ``Site`` object if you don't specify a fully-qualified domain.
+
+ * In the `authentication framework`_, the ``django.contrib.auth.views.login``
+ view passes the current ``Site`` name to the template as ``{{{ site_name }}}``.
+
+ * The shortcut view (``django.views.defaults.shortcut``) uses the domain of
+ the current ``Site`` object when calculating an object's URL.
+
+.. _redirects framework: http://www.djangoproject.com/documentation/redirects/
+.. _flatpages framework: http://www.djangoproject.com/documentation/flatpages/
+.. _syndication framework: http://www.djangoproject.com/documentation/syndication/
+.. _authentication framework: http://www.djangoproject.com/documentation/syndication/
Please sign in to comment.
Something went wrong with that request. Please try again.