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.
"""
def __repr__(self):
return "<UTC>"
def utcoffset(self, dt):
return ZERO
@ -60,6 +63,9 @@ class LocalTimezone(tzinfo):
self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
tzinfo.__init__(self)
def __repr__(self):
return "<LocalTimezone>"
def utcoffset(self, dt):
if self._isdst(dt):
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
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
</ref/django-admin>` from some place on your path, such as
:file:`/usr/local/bin`.
@ -192,13 +192,13 @@ Database setup
Now, edit :file:`mysite/settings.py`. It's a normal Python module with
module-level variables representing Django settings. Change the
following keys in the :setting:`DATABASES` ``'default'`` item to match
your databases connection settings.
your database connection settings.
* :setting:`ENGINE <DATABASE-ENGINE>` -- Either
``'django.db.backends.postgresql_psycopg2'``,
``'django.db.backends.mysql'`` or
``'django.db.backends.sqlite3'``. Other backends are
:setting:`also available <DATABASE-ENGINE>`.
``'django.db.backends.mysql'``, ``'django.db.backends.sqlite3'`` or
``'django.db.backends.oracle'``. Other backends are :setting:`also available
<DATABASE-ENGINE>`.
* :setting:`NAME` -- The name of your database. If you're using
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
machine (not used for SQLite).
If you're new to databases, we recommend simply using SQLite (by
setting :setting:`ENGINE` to ``'django.db.backends.sqlite3'``). SQLite
is included as part of Python 2.5 and later, so you won't need to
install anything else.
If you're new to databases, we recommend simply using SQLite by setting
:setting:`ENGINE` to ``'django.db.backends.sqlite3'`` and :setting:`NAME` to
the place where you'd like to store the database. SQLite is included as part
of Python 2.5 and later, so you won't need to install anything else.
.. note::
@ -233,11 +233,14 @@ install anything else.
If you're using SQLite, you don't need to create anything beforehand - the
database file will be created automatically when it is needed.
While you're editing :file:`settings.py`, 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.
While you're editing :file:`settings.py`, set :setting:`TIME_ZONE` to your
time zone. The default value isn't correct for you, unless you happen to live
near Chicago.
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
come with Django:
@ -414,6 +417,12 @@ it'll look like this::
'django.contrib.contenttypes',
'django.contrib.sessions',
'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',
)
@ -437,7 +446,7 @@ statements for the polls app):
);
CREATE TABLE "polls_choice" (
"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,
"votes" integer NOT NULL
);
@ -454,7 +463,7 @@ Note the following:
* Primary keys (IDs) are added automatically. (You can override this, too.)
* 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``
statement.
@ -501,12 +510,12 @@ Now, run :djadmin:`syncdb` again to create those model tables in your database:
python manage.py syncdb
The :djadmin:`syncdb` command runs the sql from 'sqlall' on your database for
all apps in :setting:`INSTALLED_APPS` that don't already exist in your database.
This creates all the tables, initial data and indexes for any apps you have
added to your project since the last time you ran syncdb. :djadmin:`syncdb` can
be called as often as you like, and it will only ever create the tables that
don't exist.
The :djadmin:`syncdb` command runs the sql from :djadmin:`sqlall` on your
database for all apps in :setting:`INSTALLED_APPS` that don't already exist in
your database. This creates all the tables, initial data and indexes for any
apps you have added to your project since the last time you ran syncdb.
:djadmin:`syncdb` can be called as often as you like, and it will only ever
create the tables that don't exist.
Read the :doc:`django-admin.py documentation </ref/django-admin>` for full
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>`::
>>> 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.
>>> Poll.objects.all()
[]
# Create a new Poll.
>>> import datetime
>>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())
# Support for time zones is enabled in the default settings file, so
# 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.
>>> 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.
>>> p.question
"What's up?"
"What's new?"
>>> 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().
>>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
>>> p.question = "What's up?"
>>> p.save()
# 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::
import datetime
from django.utils import timezone
# ...
class Poll(models.Model):
# ...
def was_published_today(self):
return self.pub_date.date() == datetime.date.today()
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
Note the addition of ``import datetime`` to reference Python's standard
``datetime`` module.
Note the addition of ``import datetime`` and ``from django.utils import
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
``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: What's up?>]
# Get the poll whose year is 2007.
>>> Poll.objects.get(pub_date__year=2007)
# Get the poll whose year is 2012.
>>> Poll.objects.get(pub_date__year=2012)
<Poll: What's up?>
>>> 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.
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_today()
False
>>> p.was_published_recently()
True
# 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
@ -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.
# Use double underscores to separate relationships.
# 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.
>>> Choice.objects.filter(poll__pub_date__year=2007)
# Find all Choices for any poll whose pub_date is in 2012.
>>> Choice.objects.filter(poll__pub_date__year=2012)
[<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
# 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
unified interface for site administrators to edit content.
The admin isn't necessarily intended to be used by site visitors; it's for
site managers.
The admin isn't intended to be used by site visitors; it's for site
managers.
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
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
to :setting:`INSTALLED_APPS`, the database tables need to be updated.
@ -101,7 +101,7 @@ the Django admin index page:
.. image:: _images/admin02t.png
: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.
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.
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
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,
@ -337,12 +342,12 @@ columns, on the change list page for the object::
# ...
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::
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:
@ -350,17 +355,22 @@ Now the poll change list page looks like this:
:alt: Polls change list page, updated
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
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
underscores replaced with spaces). But you can change that by giving that
method (in ``models.py``) a ``short_description`` attribute::
case of the ``was_published_recently`` header, because sorting by the output
of an arbitrary method is not supported. Also note that the column header for
``was_published_recently`` is, by default, the name of the method (with
underscores replaced with spaces), and that each line contains the string
representation of the output.
You can improve that by giving that method (in ``models.py``) a few
attributes, as follows::
class Poll(models.Model):
# ...
def was_published_today(self):
return self.pub_date.date() == datetime.date.today()
was_published_today.short_description = 'Published today?'
def was_published_recently(self):
return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
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
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
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
filter options for DateTimeFields: "Any date," "Today," "Past 7 days,"
"This month," "This year."
Because ``pub_date`` is a :class:`~django.db.models.fields.DateTimeField`,
Django knows to give appropriate filter options: "Any date," "Today," "Past 7
days," "This month," "This year."
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.
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
think they should.