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
|
@ -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
|
||||
|
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 17 KiB |
|
@ -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.
|
||||
|
@ -544,8 +553,11 @@ Once you're in the shell, explore the :doc:`database API </topics/db/queries>`::
|
|||
[]
|
||||
|
||||
# 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.
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|