Fixed #17715 -- Updated the tutorial for time zone support, plus a few other improvements.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17591 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Aymeric Augustin 2012-02-26 21:17:58 +00:00
parent 26d12af6fd
commit e0d78f898f
7 changed files with 88 additions and 56 deletions

View File

@ -32,6 +32,9 @@ class UTC(tzinfo):
Used only when pytz isn't available. Used only when pytz isn't available.
""" """
def __repr__(self):
return "<UTC>"
def utcoffset(self, dt): def utcoffset(self, dt):
return ZERO return ZERO
@ -60,6 +63,9 @@ class LocalTimezone(tzinfo):
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
tzinfo.__init__(self) tzinfo.__init__(self)
def __repr__(self):
return "<LocalTimezone>"
def utcoffset(self, dt): def utcoffset(self, dt):
if self._isdst(dt): if self._isdst(dt):
return self.DSTOFFSET return self.DSTOFFSET

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -70,7 +70,7 @@ This will create a ``mysite`` directory in your current directory.
:doc:`django-admin.py </ref/django-admin>` should be on your system path if you :doc:`django-admin.py </ref/django-admin>` should be on your system path if you
installed Django via ``python setup.py``. If it's not on your path, you can find installed Django via ``python setup.py``. If it's not on your path, you can find
it in ``site-packages/django/bin``, where ```site-packages``` is a directory it in ``site-packages/django/bin``, where ``site-packages`` is a directory
within your Python installation. Consider symlinking to :doc:`django-admin.py within your Python installation. Consider symlinking to :doc:`django-admin.py
</ref/django-admin>` from some place on your path, such as </ref/django-admin>` from some place on your path, such as
:file:`/usr/local/bin`. :file:`/usr/local/bin`.
@ -192,13 +192,13 @@ Database setup
Now, edit :file:`mysite/settings.py`. It's a normal Python module with Now, edit :file:`mysite/settings.py`. It's a normal Python module with
module-level variables representing Django settings. Change the module-level variables representing Django settings. Change the
following keys in the :setting:`DATABASES` ``'default'`` item to match following keys in the :setting:`DATABASES` ``'default'`` item to match
your databases connection settings. your database connection settings.
* :setting:`ENGINE <DATABASE-ENGINE>` -- Either * :setting:`ENGINE <DATABASE-ENGINE>` -- Either
``'django.db.backends.postgresql_psycopg2'``, ``'django.db.backends.postgresql_psycopg2'``,
``'django.db.backends.mysql'`` or ``'django.db.backends.mysql'``, ``'django.db.backends.sqlite3'`` or
``'django.db.backends.sqlite3'``. Other backends are ``'django.db.backends.oracle'``. Other backends are :setting:`also available
:setting:`also available <DATABASE-ENGINE>`. <DATABASE-ENGINE>`.
* :setting:`NAME` -- The name of your database. If you're using * :setting:`NAME` -- The name of your database. If you're using
SQLite, the database will be a file on your computer; in that SQLite, the database will be a file on your computer; in that
@ -219,10 +219,10 @@ your databases connection settings.
an empty string if your database server is on the same physical an empty string if your database server is on the same physical
machine (not used for SQLite). machine (not used for SQLite).
If you're new to databases, we recommend simply using SQLite (by If you're new to databases, we recommend simply using SQLite by setting
setting :setting:`ENGINE` to ``'django.db.backends.sqlite3'``). SQLite :setting:`ENGINE` to ``'django.db.backends.sqlite3'`` and :setting:`NAME` to
is included as part of Python 2.5 and later, so you won't need to the place where you'd like to store the database. SQLite is included as part
install anything else. of Python 2.5 and later, so you won't need to install anything else.
.. note:: .. note::
@ -233,11 +233,14 @@ install anything else.
If you're using SQLite, you don't need to create anything beforehand - the If you're using SQLite, you don't need to create anything beforehand - the
database file will be created automatically when it is needed. database file will be created automatically when it is needed.
While you're editing :file:`settings.py`, take note of the While you're editing :file:`settings.py`, set :setting:`TIME_ZONE` to your
:setting:`INSTALLED_APPS` setting towards the bottom of the file. That variable time zone. The default value isn't correct for you, unless you happen to live
holds the names of all Django applications that are activated in this Django near Chicago.
instance. Apps can be used in multiple projects, and you can package and
distribute them for use by others in their projects. Also, take note of the :setting:`INSTALLED_APPS` setting towards the bottom of
the file. That variable holds the names of all Django applications that are
activated in this Django instance. Apps can be used in multiple projects, and
you can package and distribute them for use by others in their projects.
By default, :setting:`INSTALLED_APPS` contains the following apps, all of which By default, :setting:`INSTALLED_APPS` contains the following apps, all of which
come with Django: come with Django:
@ -414,6 +417,12 @@ it'll look like this::
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
# 'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'polls', 'polls',
) )
@ -437,7 +446,7 @@ statements for the polls app):
); );
CREATE TABLE "polls_choice" ( CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY, "id" serial NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"), "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id") DEFERRABLE INITIALLY DEFERRED,
"choice" varchar(200) NOT NULL, "choice" varchar(200) NOT NULL,
"votes" integer NOT NULL "votes" integer NOT NULL
); );
@ -454,7 +463,7 @@ Note the following:
* Primary keys (IDs) are added automatically. (You can override this, too.) * Primary keys (IDs) are added automatically. (You can override this, too.)
* By convention, Django appends ``"_id"`` to the foreign key field name. * By convention, Django appends ``"_id"`` to the foreign key field name.
Yes, you can override this, as well. (Yes, you can override this, as well.)
* The foreign key relationship is made explicit by a ``REFERENCES`` * The foreign key relationship is made explicit by a ``REFERENCES``
statement. statement.
@ -501,12 +510,12 @@ Now, run :djadmin:`syncdb` again to create those model tables in your database:
python manage.py syncdb python manage.py syncdb
The :djadmin:`syncdb` command runs the sql from 'sqlall' on your database for The :djadmin:`syncdb` command runs the sql from :djadmin:`sqlall` on your
all apps in :setting:`INSTALLED_APPS` that don't already exist in your database. database for all apps in :setting:`INSTALLED_APPS` that don't already exist in
This creates all the tables, initial data and indexes for any apps you have your database. This creates all the tables, initial data and indexes for any
added to your project since the last time you ran syncdb. :djadmin:`syncdb` can apps you have added to your project since the last time you ran syncdb.
be called as often as you like, and it will only ever create the tables that :djadmin:`syncdb` can be called as often as you like, and it will only ever
don't exist. create the tables that don't exist.
Read the :doc:`django-admin.py documentation </ref/django-admin>` for full Read the :doc:`django-admin.py documentation </ref/django-admin>` for full
information on what the ``manage.py`` utility can do. information on what the ``manage.py`` utility can do.
@ -537,15 +546,18 @@ the Python import path to your :file:`settings.py` file.
Once you're in the shell, explore the :doc:`database API </topics/db/queries>`:: Once you're in the shell, explore the :doc:`database API </topics/db/queries>`::
>>> from polls.models import Poll, Choice # Import the model classes we just wrote. >>> from polls.models import Poll, Choice # Import the model classes we just wrote.
# No polls are in the system yet. # No polls are in the system yet.
>>> Poll.objects.all() >>> Poll.objects.all()
[] []
# Create a new Poll. # Create a new Poll.
>>> import datetime # Support for time zones is enabled in the default settings file, so
>>> p = Poll(question="What's up?", pub_date=datetime.datetime.now()) # Django expects a datetime with tzinfo for pub_date. Use timezone.now()
# instead of datetime.datetime.now() and it will do the right thing.
>>> from django.utils import timezone
>>> p = Poll(question="What's new?", pub_date=timezone.now())
# Save the object into the database. You have to call save() explicitly. # Save the object into the database. You have to call save() explicitly.
>>> p.save() >>> p.save()
@ -559,12 +571,12 @@ Once you're in the shell, explore the :doc:`database API </topics/db/queries>`::
# Access database columns via Python attributes. # Access database columns via Python attributes.
>>> p.question >>> p.question
"What's up?" "What's new?"
>>> p.pub_date >>> p.pub_date
datetime.datetime(2007, 7, 15, 12, 00, 53) datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
# Change values by changing the attributes, then calling save(). # Change values by changing the attributes, then calling save().
>>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0) >>> p.question = "What's up?"
>>> p.save() >>> p.save()
# objects.all() displays all the polls in the database. # objects.all() displays all the polls in the database.
@ -617,14 +629,18 @@ Note these are normal Python methods. Let's add a custom method, just for
demonstration:: demonstration::
import datetime import datetime
from django.utils import timezone
# ... # ...
class Poll(models.Model): class Poll(models.Model):
# ... # ...
def was_published_today(self): def was_published_recently(self):
return self.pub_date.date() == datetime.date.today() return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
Note the addition of ``import datetime`` to reference Python's standard Note the addition of ``import datetime`` and ``from django.utils import
``datetime`` module. timezone``, to reference Python's standard :mod:`datetime` module and Django's
time zone-related utilities in :mod:`django.utils.timezone` respectively. If
you aren't familiar with time zone handling in Python, you can learn more in
the :doc:`time zone support docs </topics/i18n/timezones>`.
Save these changes and start a new Python interactive shell by running Save these changes and start a new Python interactive shell by running
``python manage.py shell`` again:: ``python manage.py shell`` again::
@ -642,8 +658,8 @@ Save these changes and start a new Python interactive shell by running
>>> Poll.objects.filter(question__startswith='What') >>> Poll.objects.filter(question__startswith='What')
[<Poll: What's up?>] [<Poll: What's up?>]
# Get the poll whose year is 2007. # Get the poll whose year is 2012.
>>> Poll.objects.get(pub_date__year=2007) >>> Poll.objects.get(pub_date__year=2012)
<Poll: What's up?> <Poll: What's up?>
>>> Poll.objects.get(id=2) >>> Poll.objects.get(id=2)
@ -659,8 +675,8 @@ Save these changes and start a new Python interactive shell by running
# Make sure our custom method worked. # Make sure our custom method worked.
>>> p = Poll.objects.get(pk=1) >>> p = Poll.objects.get(pk=1)
>>> p.was_published_today() >>> p.was_published_recently()
False True
# Give the Poll a couple of Choices. The create call constructs a new # Give the Poll a couple of Choices. The create call constructs a new
# choice object, does the INSERT statement, adds the choice to the set # choice object, does the INSERT statement, adds the choice to the set
@ -693,8 +709,8 @@ Save these changes and start a new Python interactive shell by running
# The API automatically follows relationships as far as you need. # The API automatically follows relationships as far as you need.
# Use double underscores to separate relationships. # Use double underscores to separate relationships.
# This works as many levels deep as you want; there's no limit. # This works as many levels deep as you want; there's no limit.
# Find all Choices for any poll whose pub_date is in 2007. # Find all Choices for any poll whose pub_date is in 2012.
>>> Choice.objects.filter(poll__pub_date__year=2007) >>> Choice.objects.filter(poll__pub_date__year=2012)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# Let's delete one of the choices. Use delete() for that. # Let's delete one of the choices. Use delete() for that.

View File

@ -18,8 +18,8 @@ automatically-generated admin site.
displayed on the public site. Django solves the problem of creating a displayed on the public site. Django solves the problem of creating a
unified interface for site administrators to edit content. unified interface for site administrators to edit content.
The admin isn't necessarily intended to be used by site visitors; it's for The admin isn't intended to be used by site visitors; it's for site
site managers. managers.
Activate the admin site Activate the admin site
======================= =======================
@ -27,7 +27,7 @@ Activate the admin site
The Django admin site is not activated by default -- it's an opt-in thing. To The Django admin site is not activated by default -- it's an opt-in thing. To
activate the admin site for your installation, do these three things: activate the admin site for your installation, do these three things:
* Add ``"django.contrib.admin"`` to your :setting:`INSTALLED_APPS` setting. * Uncomment ``"django.contrib.admin"`` in the :setting:`INSTALLED_APPS` setting.
* Run ``python manage.py syncdb``. Since you have added a new application * Run ``python manage.py syncdb``. Since you have added a new application
to :setting:`INSTALLED_APPS`, the database tables need to be updated. to :setting:`INSTALLED_APPS`, the database tables need to be updated.
@ -101,7 +101,7 @@ the Django admin index page:
.. image:: _images/admin02t.png .. image:: _images/admin02t.png
:alt: Django admin index page :alt: Django admin index page
You should see a few other types of editable content, including groups, users You should see a few types of editable content, including groups, users
and sites. These are core features Django ships with by default. and sites. These are core features Django ships with by default.
Make the poll app modifiable in the admin Make the poll app modifiable in the admin
@ -169,6 +169,11 @@ The bottom part of the page gives you a couple of options:
* Delete -- Displays a delete confirmation page. * Delete -- Displays a delete confirmation page.
If the value of "Date published" doesn't match the time when you created the
poll in Tutorial 1, it probably means you forgot to set the correct value for
the :setting:`TIME_ZONE` setting. Change it, reload the page, and check that
the correct value appears.
Change the "Date published" by clicking the "Today" and "Now" shortcuts. Then Change the "Date published" by clicking the "Today" and "Now" shortcuts. Then
click "Save and continue editing." Then click "History" in the upper right. click "Save and continue editing." Then click "History" in the upper right.
You'll see a page listing all changes made to this object via the Django admin, You'll see a page listing all changes made to this object via the Django admin,
@ -337,12 +342,12 @@ columns, on the change list page for the object::
# ... # ...
list_display = ('question', 'pub_date') list_display = ('question', 'pub_date')
Just for good measure, let's also include the ``was_published_today`` custom Just for good measure, let's also include the ``was_published_recently`` custom
method from Tutorial 1:: method from Tutorial 1::
class PollAdmin(admin.ModelAdmin): class PollAdmin(admin.ModelAdmin):
# ... # ...
list_display = ('question', 'pub_date', 'was_published_today') list_display = ('question', 'pub_date', 'was_published_recently')
Now the poll change list page looks like this: Now the poll change list page looks like this:
@ -350,17 +355,22 @@ Now the poll change list page looks like this:
:alt: Polls change list page, updated :alt: Polls change list page, updated
You can click on the column headers to sort by those values -- except in the You can click on the column headers to sort by those values -- except in the
case of the ``was_published_today`` header, because sorting by the output of case of the ``was_published_recently`` header, because sorting by the output
an arbitrary method is not supported. Also note that the column header for of an arbitrary method is not supported. Also note that the column header for
``was_published_today`` is, by default, the name of the method (with ``was_published_recently`` is, by default, the name of the method (with
underscores replaced with spaces). But you can change that by giving that underscores replaced with spaces), and that each line contains the string
method (in ``models.py``) a ``short_description`` attribute:: representation of the output.
You can improve that by giving that method (in ``models.py``) a few
attributes, as follows::
class Poll(models.Model): class Poll(models.Model):
# ... # ...
def was_published_today(self): def was_published_recently(self):
return self.pub_date.date() == datetime.date.today() return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
was_published_today.short_description = 'Published today?' was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
Edit your admin.py file again and add an improvement to the Poll change list page: Filters. Add the Edit your admin.py file again and add an improvement to the Poll change list page: Filters. Add the
following line to ``PollAdmin``:: following line to ``PollAdmin``::
@ -374,9 +384,9 @@ That adds a "Filter" sidebar that lets people filter the change list by the
:alt: Polls change list page, updated :alt: Polls change list page, updated
The type of filter displayed depends on the type of field you're filtering on. The type of filter displayed depends on the type of field you're filtering on.
Because ``pub_date`` is a DateTimeField, Django knows to give the default Because ``pub_date`` is a :class:`~django.db.models.fields.DateTimeField`,
filter options for DateTimeFields: "Any date," "Today," "Past 7 days," Django knows to give appropriate filter options: "Any date," "Today," "Past 7
"This month," "This year." days," "This month," "This year."
This is shaping up well. Let's add some search capability:: This is shaping up well. Let's add some search capability::
@ -397,7 +407,7 @@ At top level, it displays all available years. Then it drills down to months
and, ultimately, days. and, ultimately, days.
Now's also a good time to note that change lists give you free pagination. The Now's also a good time to note that change lists give you free pagination. The
default is to display 50 items per page. Change-list pagination, search boxes, default is to display 100 items per page. Change-list pagination, search boxes,
filters, date-hierarchies and column-header-ordering all work together like you filters, date-hierarchies and column-header-ordering all work together like you
think they should. think they should.