2006-05-22 12:48:44 +08:00
|
|
|
=====================
|
|
|
|
The "sites" framework
|
|
|
|
=====================
|
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
.. module:: django.contrib.sites
|
2010-10-09 16:12:50 +08:00
|
|
|
:synopsis: Lets you operate multiple Web sites from the same database and
|
2008-08-24 06:25:40 +08:00
|
|
|
Django project
|
|
|
|
|
2006-05-22 12:48:44 +08:00
|
|
|
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.
|
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
The sites framework is mainly based on a simple model:
|
2008-08-24 06:25:40 +08:00
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
.. class:: models.Site
|
2011-02-18 08:58:34 +08:00
|
|
|
|
|
|
|
A model for storing the ``domain`` and ``name`` attributes of a Web site.
|
|
|
|
The :setting:`SITE_ID` setting specifies the database ID of the
|
|
|
|
:class:`~django.contrib.sites.models.Site` object associated with that
|
|
|
|
particular settings file.
|
|
|
|
|
|
|
|
.. attribute:: domain
|
|
|
|
|
|
|
|
The domain name associated with the Web site.
|
|
|
|
|
|
|
|
.. attribute:: name
|
|
|
|
|
|
|
|
A human-readable "verbose" name for the Web site.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
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,
|
2008-08-24 06:25:40 +08:00
|
|
|
that's represented by a :class:`~django.db.models.ManyToManyField` in the
|
|
|
|
``Article`` model::
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.contrib.sites.models import Site
|
|
|
|
|
|
|
|
class Article(models.Model):
|
2007-08-05 13:14:46 +08:00
|
|
|
headline = models.CharField(max_length=200)
|
2006-05-22 12:48:44 +08:00
|
|
|
# ...
|
|
|
|
sites = models.ManyToManyField(Site)
|
|
|
|
|
|
|
|
This accomplishes several things quite nicely:
|
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* It lets the site producers edit all content -- on both sites -- in a
|
|
|
|
single interface (the Django admin).
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* It means the same story doesn't have to be published twice in the
|
|
|
|
database; it only has a single record in the database.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
* 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::
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
from django.contrib.sites.shortcuts import get_current_site
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2011-10-14 08:12:01 +08:00
|
|
|
def article_detail(request, article_id):
|
|
|
|
try:
|
2014-01-18 06:27:04 +08:00
|
|
|
a = Article.objects.get(id=article_id, sites__id=get_current_site(request).id)
|
2011-10-14 08:12:01 +08:00
|
|
|
except Article.DoesNotExist:
|
|
|
|
raise Http404
|
|
|
|
# ...
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
.. _ljworld.com: http://www.ljworld.com/
|
|
|
|
.. _lawrence.com: http://www.lawrence.com/
|
|
|
|
|
|
|
|
Associating content with a single site
|
|
|
|
--------------------------------------
|
|
|
|
|
2011-02-18 08:58:34 +08:00
|
|
|
Similarly, you can associate a model to the
|
|
|
|
:class:`~django.contrib.sites.models.Site`
|
2008-08-24 06:25:40 +08:00
|
|
|
model in a many-to-one relationship, using
|
2011-02-18 08:58:34 +08:00
|
|
|
:class:`~django.db.models.ForeignKey`.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
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):
|
2007-08-05 13:14:46 +08:00
|
|
|
headline = models.CharField(max_length=200)
|
2006-05-22 12:48:44 +08:00
|
|
|
# ...
|
|
|
|
site = models.ForeignKey(Site)
|
|
|
|
|
|
|
|
This has the same benefits as described in the last section.
|
|
|
|
|
2010-08-28 19:59:14 +08:00
|
|
|
.. _hooking-into-current-site-from-views:
|
|
|
|
|
2006-05-22 12:48:44 +08:00
|
|
|
Hooking into the current site from views
|
|
|
|
----------------------------------------
|
|
|
|
|
Fixed #14386, #8960, #10235, #10909, #10608, #13845, #14377 - standardize Site/RequestSite usage in various places.
Many thanks to gabrielhurley for putting most of this together. Also to
bmihelac, arthurk, qingfeng, hvendelbo, petr.pulc@s-cape.cz, Hraban for
reports and some initial patches.
The patch also contains some whitespace/PEP8 fixes.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@13980 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2010-10-04 22:20:47 +08:00
|
|
|
You can use the sites framework in your Django views to do
|
2008-01-02 13:01:54 +08:00
|
|
|
particular things based on the site in which the view is being called.
|
2006-05-22 12:48:44 +08:00
|
|
|
For example::
|
|
|
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
|
|
|
def my_view(request):
|
|
|
|
if settings.SITE_ID == 3:
|
|
|
|
# Do something.
|
2012-11-17 19:49:28 +08:00
|
|
|
pass
|
2006-05-22 12:48:44 +08:00
|
|
|
else:
|
|
|
|
# Do something else.
|
2012-11-17 19:49:28 +08:00
|
|
|
pass
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
Of course, it's ugly to hard-code the site IDs like that. This sort of
|
2012-09-29 02:10:22 +08:00
|
|
|
hard-coding is best for hackish fixes that you need done quickly. The
|
2006-05-22 12:48:44 +08:00
|
|
|
cleaner way of accomplishing the same thing is to check the current site's
|
|
|
|
domain::
|
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
from django.contrib.sites.shortcuts import get_current_site
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
def my_view(request):
|
2012-09-29 02:10:22 +08:00
|
|
|
current_site = get_current_site(request)
|
2006-05-22 12:48:44 +08:00
|
|
|
if current_site.domain == 'foo.com':
|
|
|
|
# Do something
|
2012-11-17 19:49:28 +08:00
|
|
|
pass
|
2006-05-22 12:48:44 +08:00
|
|
|
else:
|
|
|
|
# Do something else.
|
2012-11-17 19:49:28 +08:00
|
|
|
pass
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2012-11-17 19:49:28 +08:00
|
|
|
This has also the advantage of checking if the sites framework is installed,
|
2014-01-26 04:54:25 +08:00
|
|
|
and return a :class:`~django.contrib.sites.requests.RequestSite` instance if
|
|
|
|
it is not.
|
2012-09-29 02:10:22 +08:00
|
|
|
|
|
|
|
If you don't have access to the request object, you can use the
|
|
|
|
``get_current()`` method of the :class:`~django.contrib.sites.models.Site`
|
|
|
|
model's manager. You should then ensure that your settings file does contain
|
|
|
|
the :setting:`SITE_ID` setting. This example is equivalent to the previous one::
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
from django.contrib.sites.models import Site
|
|
|
|
|
2012-09-29 02:10:22 +08:00
|
|
|
def my_function_without_request():
|
2006-05-22 12:48:44 +08:00
|
|
|
current_site = Site.objects.get_current()
|
|
|
|
if current_site.domain == 'foo.com':
|
|
|
|
# Do something
|
2012-11-17 19:49:28 +08:00
|
|
|
pass
|
2006-05-22 12:48:44 +08:00
|
|
|
else:
|
|
|
|
# Do something else.
|
2012-11-17 19:49:28 +08:00
|
|
|
pass
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
Getting the current domain for display
|
|
|
|
--------------------------------------
|
|
|
|
|
2011-04-02 00:10:22 +08:00
|
|
|
LJWorld.com and Lawrence.com both have email alert functionality, which lets
|
2006-05-22 12:48:44 +08:00
|
|
|
readers sign up to get notifications when news happens. It's pretty basic: A
|
2013-11-30 21:37:15 +08:00
|
|
|
reader signs up on a Web form and immediately gets an email saying,
|
2006-05-22 12:48:44 +08:00
|
|
|
"Thanks for your subscription."
|
|
|
|
|
2014-03-01 10:03:46 +08:00
|
|
|
It'd be inefficient and redundant to implement this sign up processing code
|
2006-05-22 12:48:44 +08:00
|
|
|
twice, so the sites use the same code behind the scenes. But the "thank you for
|
2008-08-24 06:25:40 +08:00
|
|
|
signing up" notice needs to be different for each site. By using
|
|
|
|
:class:`~django.contrib.sites.models.Site`
|
2006-05-22 12:48:44 +08:00
|
|
|
objects, we can abstract the "thank you" notice to use the values of the
|
2008-08-24 06:25:40 +08:00
|
|
|
current site's :attr:`~django.contrib.sites.models.Site.name` and
|
|
|
|
:attr:`~django.contrib.sites.models.Site.domain`.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
Here's an example of what the form-handling view looks like::
|
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
from django.contrib.sites.shortcuts import get_current_site
|
2006-05-22 12:48:44 +08:00
|
|
|
from django.core.mail import send_mail
|
|
|
|
|
|
|
|
def register_for_newsletter(request):
|
|
|
|
# Check form values, etc., and subscribe the user.
|
|
|
|
# ...
|
|
|
|
|
2012-09-29 02:10:22 +08:00
|
|
|
current_site = get_current_site(request)
|
2006-05-22 12:48:44 +08:00
|
|
|
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])
|
|
|
|
|
|
|
|
# ...
|
|
|
|
|
2011-04-02 00:10:22 +08:00
|
|
|
On Lawrence.com, this email has the subject line "Thanks for subscribing to
|
|
|
|
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.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
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
|
2012-11-17 19:49:28 +08:00
|
|
|
different template directories (:setting:`TEMPLATE_DIRS`), you could simply
|
|
|
|
farm out to the template system like so::
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
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])
|
|
|
|
|
|
|
|
# ...
|
|
|
|
|
2012-11-17 19:49:28 +08:00
|
|
|
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 gives you more flexibility, but it's also more complex.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2008-11-03 04:43:20 +08:00
|
|
|
It's a good idea to exploit the :class:`~django.contrib.sites.models.Site`
|
2008-08-24 06:25:40 +08:00
|
|
|
objects as much as possible, to remove unneeded complexity and redundancy.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
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/'
|
|
|
|
|
2013-02-08 23:32:09 +08:00
|
|
|
.. _enabling-the-sites-framework:
|
2012-11-17 19:49:28 +08:00
|
|
|
|
Simplified default project template.
Squashed commit of:
commit 508ec9144b35c50794708225b496bde1eb5e60aa
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 22:50:55 2013 +0100
Tweaked default settings file.
* Explained why BASE_DIR exists.
* Added a link to the database configuration options, and put it in its
own section.
* Moved sensitive settings that must be changed for production at the
top.
commit 6515fd2f1aa73a86dc8dbd2ccf512ddb6b140d57
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 14:35:21 2013 +0100
Documented the simplified app & project templates in the changelog.
commit 2c5b576c2ea91d84273a019b3d0b3b8b4da72f23
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 13:59:27 2013 +0100
Minor fixes in tutorials 5 and 6.
commit 55a51531be8104f21b3cca3f6bf70b0a7139a041
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 13:51:11 2013 +0100
Updated tutorial 2 for the new project template.
commit 29ddae87bdaecff12dd31b16b000c01efbde9e20
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 11:58:54 2013 +0100
Updated tutorial 1 for the new project template.
commit 0ecb9f6e2514cfd26a678a280d471433375101a3
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 11:29:13 2013 +0100
Adjusted the default URLconf detection to account for the admin.
It's now enabled by default.
commit 5fb4da0d3d09dac28dd94e3fde92b9d4335c0565
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 10:36:55 2013 +0100
Added security warnings for the most sensitive settings.
commit 718d84bd8ac4a42fb4b28ec93965de32680f091e
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 23:24:06 2013 +0100
Used an absolute path for the SQLite database.
This ensures the settings file works regardless of which directory
django-admin.py / manage.py is invoked from.
BASE_DIR got a +1 from a BDFL and another core dev. It doesn't involve
the concept of a "Django project"; it's just a convenient way to express
relative paths within the source code repository for non-Python files.
Thanks Jacob Kaplan-Moss for the suggestion.
commit 1b559b4bcda622e10909b68fe5cab90db6727dd9
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 23:22:40 2013 +0100
Removed STATIC_ROOT from the default settings template.
It isn't necessary in development, and it confuses beginners to no end.
Thanks Carl Meyer for the suggestion.
commit a55f141a500bb7c9a1bc259bbe1954c13b199671
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 23:21:43 2013 +0100
Removed MEDIA_ROOT/URL from default settings template.
Many sites will never deal with user-uploaded files, and MEDIA_ROOT is
complicated to explain.
Thanks Carl Meyer for the suggestion.
commit 44bf2f2441420fd9429ee9fe1f7207f92dd87e70
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:22:09 2013 +0100
Removed logging config.
This configuration is applied regardless of the value of LOGGING;
duplicating it in LOGGING is confusing.
commit eac747e848eaed65fd5f6f254f0a7559d856f88f
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:05:31 2013 +0100
Enabled the locale middleware by default.
USE_I18N is True by default, and doesn't work well without
LocaleMiddleware.
commit d806c62b2d00826dc2688c84b092627b8d571cab
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:03:16 2013 +0100
Enabled clickjacking protection by default.
commit 99152c30e6a15003f0b6737dc78e87adf462aacb
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:01:48 2013 +0100
Reorganized settings in logical sections, and trimmed comments.
commit d37ffdfcb24b7e0ec7cc113d07190f65fb12fb8a
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:54:11 2013 +0100
Avoided misleading TEMPLATE_DEBUG = DEBUG.
According to the docs TEMPLATE_DEBUG works only when DEBUG = True.
commit 15d9478d3a9850e85841e7cf09cf83050371c6bf
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:46:25 2013 +0100
Removed STATICFILES_FINDERS/TEMPLATE_LOADERS from default settings file.
Only developers with special needs ever need to change these settings.
commit 574da0eb5bfb4570883756914b4dbd7e20e1f61e
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:45:01 2013 +0100
Removed STATICFILES/TEMPLATES_DIRS from default settings file.
The current best practice is to put static files and templates in
applications, for easier testing and deployment.
commit 8cb18dbe56629aa1be74718a07e7cc66b4f9c9f0
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:24:16 2013 +0100
Removed settings related to email reporting from default settings file.
While handy for small scale projects, it isn't exactly a best practice.
commit 8ecbfcb3638058f0c49922540f874a7d802d864f
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 18:54:43 2013 +0100
Documented how to enable the sites framework.
commit 23fc91a6fa67d91ddd9d71b1c3e0dc26bdad9841
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:28:59 2013 +0100
Disabled the sites framework by default.
RequestSite does the job for single-domain websites.
commit c4d82eb8afc0eb8568bf9c4d12644272415e3960
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 00:08:33 2013 +0100
Added a default admin.py to the application template.
Thanks Ryan D Hiebert for the suggestion.
commit 4071dc771e5c44b1c5ebb9beecefb164ae465e22
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 10:59:49 2013 +0100
Enabled the admin by default.
Everyone uses the admin.
commit c807a31f8d89e7e7fd97380e3023f7983a8b6fcb
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 10:57:05 2013 +0100
Removed admindocs from default project template.
commit 09e4ce0e652a97da1a9e285046a91c8ad7a9189c
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:32:52 2013 +0100
Added links to the settings documentation.
commit 5b8f5eaef364eb790fcde6f9e86f7d266074cca8
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 11:06:54 2013 +0100
Used a significant example for URLconf includes.
commit 908e91d6fcee2a3cb51ca26ecdf12a6a24e69ef8
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:22:31 2013 +0100
Moved code comments about WSGI to docs, and rewrote said docs.
commit 50417e51996146f891d08ca8b74dcc736a581932
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 15:51:50 2013 +0100
Normalized the default application template.
Removed the default test that 1 + 1 = 2, because it's been committed
way too many times, in too many projects.
Added an import of `render` for views, because the first view will
often be:
def home(request):
return render(request, "mysite/home.html")
2013-01-28 22:51:50 +08:00
|
|
|
Enabling the sites framework
|
|
|
|
============================
|
|
|
|
|
|
|
|
To enable the sites framework, follow these steps:
|
|
|
|
|
|
|
|
1. Add ``'django.contrib.sites'`` to your :setting:`INSTALLED_APPS`
|
|
|
|
setting.
|
|
|
|
|
|
|
|
2. Define a :setting:`SITE_ID` setting::
|
|
|
|
|
|
|
|
SITE_ID = 1
|
|
|
|
|
2013-07-25 23:19:36 +08:00
|
|
|
3. Run :djadmin:`migrate`.
|
2012-11-17 19:49:28 +08:00
|
|
|
|
|
|
|
``django.contrib.sites`` registers a
|
2013-07-30 18:52:52 +08:00
|
|
|
:data:`~django.db.models.signals.post_migrate` signal handler which creates a
|
Simplified default project template.
Squashed commit of:
commit 508ec9144b35c50794708225b496bde1eb5e60aa
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 22:50:55 2013 +0100
Tweaked default settings file.
* Explained why BASE_DIR exists.
* Added a link to the database configuration options, and put it in its
own section.
* Moved sensitive settings that must be changed for production at the
top.
commit 6515fd2f1aa73a86dc8dbd2ccf512ddb6b140d57
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 14:35:21 2013 +0100
Documented the simplified app & project templates in the changelog.
commit 2c5b576c2ea91d84273a019b3d0b3b8b4da72f23
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 13:59:27 2013 +0100
Minor fixes in tutorials 5 and 6.
commit 55a51531be8104f21b3cca3f6bf70b0a7139a041
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 13:51:11 2013 +0100
Updated tutorial 2 for the new project template.
commit 29ddae87bdaecff12dd31b16b000c01efbde9e20
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 11:58:54 2013 +0100
Updated tutorial 1 for the new project template.
commit 0ecb9f6e2514cfd26a678a280d471433375101a3
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 11:29:13 2013 +0100
Adjusted the default URLconf detection to account for the admin.
It's now enabled by default.
commit 5fb4da0d3d09dac28dd94e3fde92b9d4335c0565
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 10:36:55 2013 +0100
Added security warnings for the most sensitive settings.
commit 718d84bd8ac4a42fb4b28ec93965de32680f091e
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 23:24:06 2013 +0100
Used an absolute path for the SQLite database.
This ensures the settings file works regardless of which directory
django-admin.py / manage.py is invoked from.
BASE_DIR got a +1 from a BDFL and another core dev. It doesn't involve
the concept of a "Django project"; it's just a convenient way to express
relative paths within the source code repository for non-Python files.
Thanks Jacob Kaplan-Moss for the suggestion.
commit 1b559b4bcda622e10909b68fe5cab90db6727dd9
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 23:22:40 2013 +0100
Removed STATIC_ROOT from the default settings template.
It isn't necessary in development, and it confuses beginners to no end.
Thanks Carl Meyer for the suggestion.
commit a55f141a500bb7c9a1bc259bbe1954c13b199671
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 23:21:43 2013 +0100
Removed MEDIA_ROOT/URL from default settings template.
Many sites will never deal with user-uploaded files, and MEDIA_ROOT is
complicated to explain.
Thanks Carl Meyer for the suggestion.
commit 44bf2f2441420fd9429ee9fe1f7207f92dd87e70
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:22:09 2013 +0100
Removed logging config.
This configuration is applied regardless of the value of LOGGING;
duplicating it in LOGGING is confusing.
commit eac747e848eaed65fd5f6f254f0a7559d856f88f
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:05:31 2013 +0100
Enabled the locale middleware by default.
USE_I18N is True by default, and doesn't work well without
LocaleMiddleware.
commit d806c62b2d00826dc2688c84b092627b8d571cab
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:03:16 2013 +0100
Enabled clickjacking protection by default.
commit 99152c30e6a15003f0b6737dc78e87adf462aacb
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 22:01:48 2013 +0100
Reorganized settings in logical sections, and trimmed comments.
commit d37ffdfcb24b7e0ec7cc113d07190f65fb12fb8a
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:54:11 2013 +0100
Avoided misleading TEMPLATE_DEBUG = DEBUG.
According to the docs TEMPLATE_DEBUG works only when DEBUG = True.
commit 15d9478d3a9850e85841e7cf09cf83050371c6bf
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:46:25 2013 +0100
Removed STATICFILES_FINDERS/TEMPLATE_LOADERS from default settings file.
Only developers with special needs ever need to change these settings.
commit 574da0eb5bfb4570883756914b4dbd7e20e1f61e
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:45:01 2013 +0100
Removed STATICFILES/TEMPLATES_DIRS from default settings file.
The current best practice is to put static files and templates in
applications, for easier testing and deployment.
commit 8cb18dbe56629aa1be74718a07e7cc66b4f9c9f0
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:24:16 2013 +0100
Removed settings related to email reporting from default settings file.
While handy for small scale projects, it isn't exactly a best practice.
commit 8ecbfcb3638058f0c49922540f874a7d802d864f
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 18:54:43 2013 +0100
Documented how to enable the sites framework.
commit 23fc91a6fa67d91ddd9d71b1c3e0dc26bdad9841
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:28:59 2013 +0100
Disabled the sites framework by default.
RequestSite does the job for single-domain websites.
commit c4d82eb8afc0eb8568bf9c4d12644272415e3960
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Tue Jan 29 00:08:33 2013 +0100
Added a default admin.py to the application template.
Thanks Ryan D Hiebert for the suggestion.
commit 4071dc771e5c44b1c5ebb9beecefb164ae465e22
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 10:59:49 2013 +0100
Enabled the admin by default.
Everyone uses the admin.
commit c807a31f8d89e7e7fd97380e3023f7983a8b6fcb
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 10:57:05 2013 +0100
Removed admindocs from default project template.
commit 09e4ce0e652a97da1a9e285046a91c8ad7a9189c
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:32:52 2013 +0100
Added links to the settings documentation.
commit 5b8f5eaef364eb790fcde6f9e86f7d266074cca8
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 11:06:54 2013 +0100
Used a significant example for URLconf includes.
commit 908e91d6fcee2a3cb51ca26ecdf12a6a24e69ef8
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 16:22:31 2013 +0100
Moved code comments about WSGI to docs, and rewrote said docs.
commit 50417e51996146f891d08ca8b74dcc736a581932
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date: Mon Jan 28 15:51:50 2013 +0100
Normalized the default application template.
Removed the default test that 1 + 1 = 2, because it's been committed
way too many times, in too many projects.
Added an import of `render` for views, because the first view will
often be:
def home(request):
return render(request, "mysite/home.html")
2013-01-28 22:51:50 +08:00
|
|
|
default site named ``example.com`` with the domain ``example.com``. This site
|
|
|
|
will also be created after Django creates the test database. To set the
|
|
|
|
correct name and domain for your project, you can use an :doc:`initial data
|
|
|
|
fixture </howto/initial-data>`.
|
2012-11-17 19:49:28 +08:00
|
|
|
|
2007-09-14 16:37:09 +08:00
|
|
|
Caching the current ``Site`` object
|
|
|
|
===================================
|
|
|
|
|
|
|
|
As the current site is stored in the database, each call to
|
|
|
|
``Site.objects.get_current()`` could result in a database query. But Django is a
|
|
|
|
little cleverer than that: on the first request, the current site is cached, and
|
|
|
|
any subsequent call returns the cached data instead of hitting the database.
|
|
|
|
|
|
|
|
If for any reason you want to force a database query, you can tell Django to
|
|
|
|
clear the cache using ``Site.objects.clear_cache()``::
|
|
|
|
|
|
|
|
# First call; current site fetched from database.
|
|
|
|
current_site = Site.objects.get_current()
|
|
|
|
# ...
|
|
|
|
|
|
|
|
# Second call; current site fetched from cache.
|
|
|
|
current_site = Site.objects.get_current()
|
|
|
|
# ...
|
|
|
|
|
|
|
|
# Force a database query for the third call.
|
|
|
|
Site.objects.clear_cache()
|
|
|
|
current_site = Site.objects.get_current()
|
|
|
|
|
2006-05-22 13:22:45 +08:00
|
|
|
The ``CurrentSiteManager``
|
|
|
|
==========================
|
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
.. class:: managers.CurrentSiteManager
|
2006-05-22 13:22:45 +08:00
|
|
|
|
2010-05-09 14:43:18 +08:00
|
|
|
If :class:`~django.contrib.sites.models.Site` plays a key role in your
|
|
|
|
application, consider using the helpful
|
|
|
|
:class:`~django.contrib.sites.managers.CurrentSiteManager` in your
|
2010-08-20 03:27:44 +08:00
|
|
|
model(s). It's a model :doc:`manager </topics/db/managers>` that
|
2010-05-09 14:43:18 +08:00
|
|
|
automatically filters its queries to include only objects associated
|
|
|
|
with the current :class:`~django.contrib.sites.models.Site`.
|
2008-08-24 06:25:40 +08:00
|
|
|
|
|
|
|
Use :class:`~django.contrib.sites.managers.CurrentSiteManager` by adding it to
|
|
|
|
your model explicitly. For example::
|
2006-05-22 13:22:45 +08:00
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.contrib.sites.models import Site
|
|
|
|
from django.contrib.sites.managers import CurrentSiteManager
|
|
|
|
|
|
|
|
class Photo(models.Model):
|
|
|
|
photo = models.FileField(upload_to='/home/photos')
|
2007-08-05 13:14:46 +08:00
|
|
|
photographer_name = models.CharField(max_length=100)
|
2006-05-22 13:22:45 +08:00
|
|
|
pub_date = models.DateField()
|
|
|
|
site = models.ForeignKey(Site)
|
|
|
|
objects = models.Manager()
|
|
|
|
on_site = CurrentSiteManager()
|
|
|
|
|
|
|
|
With this model, ``Photo.objects.all()`` will return all ``Photo`` objects in
|
2008-08-24 06:25:40 +08:00
|
|
|
the database, but ``Photo.on_site.all()`` will return only the ``Photo`` objects
|
|
|
|
associated with the current site, according to the :setting:`SITE_ID` setting.
|
2006-05-22 13:22:45 +08:00
|
|
|
|
2006-05-22 13:22:58 +08:00
|
|
|
Put another way, these two statements are equivalent::
|
|
|
|
|
|
|
|
Photo.objects.filter(site=settings.SITE_ID)
|
|
|
|
Photo.on_site.all()
|
|
|
|
|
2010-05-09 14:43:18 +08:00
|
|
|
How did :class:`~django.contrib.sites.managers.CurrentSiteManager`
|
|
|
|
know which field of ``Photo`` was the
|
|
|
|
:class:`~django.contrib.sites.models.Site`? By default,
|
|
|
|
:class:`~django.contrib.sites.managers.CurrentSiteManager` looks for a
|
2011-02-18 08:58:34 +08:00
|
|
|
either a :class:`~django.db.models.ForeignKey` called
|
2010-05-09 14:43:18 +08:00
|
|
|
``site`` or a
|
2011-02-18 08:58:34 +08:00
|
|
|
:class:`~django.db.models.ManyToManyField` called
|
2010-05-09 14:43:18 +08:00
|
|
|
``sites`` to filter on. If you use a field named something other than
|
|
|
|
``site`` or ``sites`` to identify which
|
|
|
|
:class:`~django.contrib.sites.models.Site` objects your object is
|
|
|
|
related to, then you need to explicitly pass the custom field name as
|
|
|
|
a parameter to
|
|
|
|
:class:`~django.contrib.sites.managers.CurrentSiteManager` on your
|
|
|
|
model. The following model, which has a field called ``publish_on``,
|
|
|
|
demonstrates this::
|
2006-05-22 13:22:45 +08:00
|
|
|
|
|
|
|
from django.db import models
|
|
|
|
from django.contrib.sites.models import Site
|
|
|
|
from django.contrib.sites.managers import CurrentSiteManager
|
|
|
|
|
|
|
|
class Photo(models.Model):
|
|
|
|
photo = models.FileField(upload_to='/home/photos')
|
2007-08-05 13:14:46 +08:00
|
|
|
photographer_name = models.CharField(max_length=100)
|
2006-05-22 13:22:45 +08:00
|
|
|
pub_date = models.DateField()
|
|
|
|
publish_on = models.ForeignKey(Site)
|
|
|
|
objects = models.Manager()
|
|
|
|
on_site = CurrentSiteManager('publish_on')
|
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
If you attempt to use :class:`~django.contrib.sites.managers.CurrentSiteManager`
|
2011-02-18 08:58:34 +08:00
|
|
|
and pass a field name that doesn't exist, Django will raise a ``ValueError``.
|
2006-05-22 13:22:45 +08:00
|
|
|
|
2010-05-09 14:43:18 +08:00
|
|
|
Finally, note that you'll probably want to keep a normal
|
|
|
|
(non-site-specific) ``Manager`` on your model, even if you use
|
|
|
|
:class:`~django.contrib.sites.managers.CurrentSiteManager`. As
|
2010-08-20 03:27:44 +08:00
|
|
|
explained in the :doc:`manager documentation </topics/db/managers>`, if
|
2010-05-09 14:43:18 +08:00
|
|
|
you define a manager manually, then Django won't create the automatic
|
|
|
|
``objects = models.Manager()`` manager for you. Also note that certain
|
|
|
|
parts of Django -- namely, the Django admin site and generic views --
|
|
|
|
use whichever manager is defined *first* in the model, so if you want
|
|
|
|
your admin site to have access to all objects (not just site-specific
|
|
|
|
ones), put ``objects = models.Manager()`` in your model, before you
|
|
|
|
define :class:`~django.contrib.sites.managers.CurrentSiteManager`.
|
2006-05-22 13:22:45 +08:00
|
|
|
|
2013-11-19 04:16:09 +08:00
|
|
|
.. _site-middleware:
|
|
|
|
|
|
|
|
Site middleware
|
|
|
|
===============
|
|
|
|
|
|
|
|
.. versionadded:: 1.7
|
|
|
|
|
|
|
|
If you often use this pattern::
|
|
|
|
|
|
|
|
from django.contrib.sites.models import Site
|
|
|
|
|
|
|
|
def my_view(request):
|
|
|
|
site = Site.objects.get_current()
|
|
|
|
...
|
|
|
|
|
|
|
|
there is simple way to avoid repetitions. Add
|
2014-03-22 00:24:49 +08:00
|
|
|
:class:`django.contrib.sites.middleware.CurrentSiteMiddleware` to
|
2013-11-19 04:16:09 +08:00
|
|
|
:setting:`MIDDLEWARE_CLASSES`. The middleware sets the ``site`` attribute on
|
|
|
|
every request object, so you can use ``request.site`` to get the current site.
|
|
|
|
|
2006-05-22 12:48:44 +08:00
|
|
|
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
|
2008-08-24 06:25:40 +08:00
|
|
|
to its ID in your :setting:`SITE_ID` setting.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
|
|
|
Here's how Django uses the sites framework:
|
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
* In the :mod:`redirects framework <django.contrib.redirects>`, each
|
|
|
|
redirect object is associated with a particular site. When Django searches
|
2012-09-29 02:10:22 +08:00
|
|
|
for a redirect, it takes into account the current site.
|
2008-08-24 06:25:40 +08:00
|
|
|
|
|
|
|
* In the comments framework, each comment is associated with a particular
|
|
|
|
site. When a comment is posted, its
|
2012-09-29 02:10:22 +08:00
|
|
|
:class:`~django.contrib.sites.models.Site` is set to the current site,
|
|
|
|
and when comments are listed via the appropriate template tag, only the
|
|
|
|
comments for the current site are displayed.
|
2010-05-09 14:43:18 +08:00
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
* In the :mod:`flatpages framework <django.contrib.flatpages>`, each
|
|
|
|
flatpage is associated with a particular site. When a flatpage is created,
|
|
|
|
you specify its :class:`~django.contrib.sites.models.Site`, and the
|
|
|
|
:class:`~django.contrib.flatpages.middleware.FlatpageFallbackMiddleware`
|
2012-09-29 02:10:22 +08:00
|
|
|
checks the current site in retrieving flatpages to display.
|
2008-08-24 06:25:40 +08:00
|
|
|
|
|
|
|
* 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
|
|
|
|
the current :class:`~django.contrib.sites.models.Site` object if you don't
|
|
|
|
specify a fully-qualified domain.
|
|
|
|
|
|
|
|
* In the :mod:`authentication framework <django.contrib.auth>`, the
|
|
|
|
:func:`django.contrib.auth.views.login` view passes the current
|
|
|
|
:class:`~django.contrib.sites.models.Site` name to the template as
|
|
|
|
``{{ site_name }}``.
|
|
|
|
|
2013-08-15 07:27:16 +08:00
|
|
|
* The shortcut view (``django.contrib.contenttypes.views.shortcut``)
|
|
|
|
uses the domain of the current
|
|
|
|
:class:`~django.contrib.sites.models.Site` object when calculating
|
|
|
|
an object's URL.
|
2008-08-24 06:25:40 +08:00
|
|
|
|
|
|
|
* In the admin framework, the "view on site" link uses the current
|
|
|
|
:class:`~django.contrib.sites.models.Site` to work out the domain for the
|
|
|
|
site that it will redirect to.
|
2006-05-22 12:48:44 +08:00
|
|
|
|
2007-07-12 13:28:04 +08:00
|
|
|
``RequestSite`` objects
|
|
|
|
=======================
|
|
|
|
|
2008-08-24 06:25:40 +08:00
|
|
|
.. _requestsite-objects:
|
|
|
|
|
2010-08-20 03:27:44 +08:00
|
|
|
Some :doc:`django.contrib </ref/contrib/index>` applications take advantage of
|
2008-08-24 06:25:40 +08:00
|
|
|
the sites framework but are architected in a way that doesn't *require* the
|
2014-01-26 04:54:25 +08:00
|
|
|
sites framework to be installed in your database. (Some people don't want to,
|
|
|
|
or just aren't *able* to install the extra database table that the sites
|
|
|
|
framework requires.) For those cases, the framework provides a
|
|
|
|
:class:`django.contrib.sites.requests.RequestSite` class, which can be used as
|
|
|
|
a fallback when the database-backed sites framework is not available.
|
2008-08-24 06:25:40 +08:00
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
.. class:: requests.RequestSite
|
2011-02-18 08:58:34 +08:00
|
|
|
|
|
|
|
A class that shares the primary interface of
|
|
|
|
:class:`~django.contrib.sites.models.Site` (i.e., it has
|
|
|
|
``domain`` and ``name`` attributes) but gets its data from a Django
|
|
|
|
:class:`~django.http.HttpRequest` object rather than from a database.
|
|
|
|
|
|
|
|
.. method:: __init__(request)
|
|
|
|
|
|
|
|
Sets the ``name`` and ``domain`` attributes to the value of
|
|
|
|
:meth:`~django.http.HttpRequest.get_host`.
|
2012-09-20 04:39:14 +08:00
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
.. versionchanged:: 1.7
|
|
|
|
|
|
|
|
This class used to be defined in ``django.contrib.sites.models``.
|
2011-02-18 08:58:34 +08:00
|
|
|
|
2014-01-26 04:54:25 +08:00
|
|
|
A :class:`~django.contrib.sites.requests.RequestSite` object has a similar
|
|
|
|
interface to a normal :class:`~django.contrib.sites.models.Site` object,
|
|
|
|
except its :meth:`~django.contrib.sites.requests.RequestSite.__init__()`
|
|
|
|
method takes an :class:`~django.http.HttpRequest` object. It's able to deduce
|
|
|
|
the ``domain`` and ``name`` by looking at the request's domain. It has
|
|
|
|
``save()`` and ``delete()`` methods to match the interface of
|
2011-02-18 08:58:34 +08:00
|
|
|
:class:`~django.contrib.sites.models.Site`, but the methods raise
|
2014-01-26 04:54:25 +08:00
|
|
|
:exc:`~exceptions.NotImplementedError`..
|
|
|
|
|
|
|
|
``get_current_site`` shortcut
|
|
|
|
=============================
|
|
|
|
|
|
|
|
Finally, to avoid repetitive fallback code, the framework provides a
|
2014-02-02 22:16:55 +08:00
|
|
|
:func:`django.contrib.sites.shortcuts.get_current_site` function.
|
2014-01-26 04:54:25 +08:00
|
|
|
|
|
|
|
.. function:: shortcuts.get_current_site
|
|
|
|
|
|
|
|
A function that checks if ``django.contrib.sites`` is installed and
|
|
|
|
returns either the current :class:`~django.contrib.sites.models.Site`
|
|
|
|
object or a :class:`~django.contrib.sites.requests.RequestSite` object
|
|
|
|
based on the request.
|
|
|
|
|
|
|
|
.. versionchanged:: 1.7
|
|
|
|
|
|
|
|
This function used to be defined in ``django.contrib.sites.models``.
|