Permalink
Browse files

Fixed #17715 -- Updated the tutorial for time zone support, plus a fe…

…w other improvements.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17591 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
1 parent 26d12af commit e0d78f898fb4000236881f447c9435f3395f3349 @aaugustin aaugustin committed Feb 26, 2012
View
@@ -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 @@ def __init__(self):
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
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
@@ -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
@@ -18,16 +18,16 @@ 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
=======================
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,30 +342,35 @@ 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:
.. image:: _images/admin13t.png
: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.

0 comments on commit e0d78f8

Please sign in to comment.