Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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...
commit e0d78f898fb4000236881f447c9435f3395f3349 1 parent 26d12af
Aymeric Augustin authored February 26, 2012
6  django/utils/timezone.py
@@ -32,6 +32,9 @@ class UTC(tzinfo):
32 32
     Used only when pytz isn't available.
33 33
     """
34 34
 
  35
+    def __repr__(self):
  36
+        return "<UTC>"
  37
+
35 38
     def utcoffset(self, dt):
36 39
         return ZERO
37 40
 
@@ -60,6 +63,9 @@ def __init__(self):
60 63
         self.DSTDIFF = self.DSTOFFSET - self.STDOFFSET
61 64
         tzinfo.__init__(self)
62 65
 
  66
+    def __repr__(self):
  67
+        return "<LocalTimezone>"
  68
+
63 69
     def utcoffset(self, dt):
64 70
         if self._isdst(dt):
65 71
             return self.DSTOFFSET
BIN  docs/intro/_images/admin13.png
BIN  docs/intro/_images/admin13t.png
BIN  docs/intro/_images/admin14.png
BIN  docs/intro/_images/admin14t.png
92  docs/intro/tutorial01.txt
@@ -70,7 +70,7 @@ This will create a ``mysite`` directory in your current directory.
70 70
 
71 71
 :doc:`django-admin.py </ref/django-admin>` should be on your system path if you
72 72
 installed Django via ``python setup.py``. If it's not on your path, you can find
73  
-it in ``site-packages/django/bin``, where ```site-packages``` is a directory
  73
+it in ``site-packages/django/bin``, where ``site-packages`` is a directory
74 74
 within your Python installation. Consider symlinking to :doc:`django-admin.py
75 75
 </ref/django-admin>` from some place on your path, such as
76 76
 :file:`/usr/local/bin`.
@@ -192,13 +192,13 @@ Database setup
192 192
 Now, edit :file:`mysite/settings.py`. It's a normal Python module with
193 193
 module-level variables representing Django settings. Change the
194 194
 following keys in the :setting:`DATABASES` ``'default'`` item to match
195  
-your databases connection settings.
  195
+your database connection settings.
196 196
 
197 197
 * :setting:`ENGINE <DATABASE-ENGINE>` -- Either
198 198
   ``'django.db.backends.postgresql_psycopg2'``,
199  
-  ``'django.db.backends.mysql'`` or
200  
-  ``'django.db.backends.sqlite3'``. Other backends are
201  
-  :setting:`also available <DATABASE-ENGINE>`.
  199
+  ``'django.db.backends.mysql'``, ``'django.db.backends.sqlite3'`` or
  200
+  ``'django.db.backends.oracle'``. Other backends are :setting:`also available
  201
+  <DATABASE-ENGINE>`.
202 202
 
203 203
 * :setting:`NAME` -- The name of your database. If you're using
204 204
   SQLite, the database will be a file on your computer; in that
@@ -219,10 +219,10 @@ your databases connection settings.
219 219
   an empty string if your database server is on the same physical
220 220
   machine (not used for SQLite).
221 221
 
222  
-If you're new to databases, we recommend simply using SQLite (by
223  
-setting :setting:`ENGINE` to ``'django.db.backends.sqlite3'``). SQLite
224  
-is included as part of Python 2.5 and later, so you won't need to
225  
-install anything else.
  222
+If you're new to databases, we recommend simply using SQLite by setting
  223
+:setting:`ENGINE` to ``'django.db.backends.sqlite3'`` and :setting:`NAME` to
  224
+the place where you'd like to store the database. SQLite is included as part
  225
+of Python 2.5 and later, so you won't need to install anything else.
226 226
 
227 227
 .. note::
228 228
 
@@ -233,11 +233,14 @@ install anything else.
233 233
     If you're using SQLite, you don't need to create anything beforehand - the
234 234
     database file will be created automatically when it is needed.
235 235
 
236  
-While you're editing :file:`settings.py`, take note of the
237  
-:setting:`INSTALLED_APPS` setting towards the bottom of the file. That variable
238  
-holds the names of all Django applications that are activated in this Django
239  
-instance. Apps can be used in multiple projects, and you can package and
240  
-distribute them for use by others in their projects.
  236
+While you're editing :file:`settings.py`, set :setting:`TIME_ZONE` to your
  237
+time zone. The default value isn't correct for you, unless you happen to live
  238
+near Chicago.
  239
+
  240
+Also, take note of the :setting:`INSTALLED_APPS` setting towards the bottom of
  241
+the file. That variable holds the names of all Django applications that are
  242
+activated in this Django instance. Apps can be used in multiple projects, and
  243
+you can package and distribute them for use by others in their projects.
241 244
 
242 245
 By default, :setting:`INSTALLED_APPS` contains the following apps, all of which
243 246
 come with Django:
@@ -414,6 +417,12 @@ it'll look like this::
414 417
         'django.contrib.contenttypes',
415 418
         'django.contrib.sessions',
416 419
         'django.contrib.sites',
  420
+        'django.contrib.messages',
  421
+        'django.contrib.staticfiles',
  422
+        # Uncomment the next line to enable the admin:
  423
+        # 'django.contrib.admin',
  424
+        # Uncomment the next line to enable admin documentation:
  425
+        # 'django.contrib.admindocs',
417 426
         'polls',
418 427
     )
419 428
 
@@ -437,7 +446,7 @@ statements for the polls app):
437 446
     );
438 447
     CREATE TABLE "polls_choice" (
439 448
         "id" serial NOT NULL PRIMARY KEY,
440  
-        "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"),
  449
+        "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id") DEFERRABLE INITIALLY DEFERRED,
441 450
         "choice" varchar(200) NOT NULL,
442 451
         "votes" integer NOT NULL
443 452
     );
@@ -454,7 +463,7 @@ Note the following:
454 463
 * Primary keys (IDs) are added automatically. (You can override this, too.)
455 464
 
456 465
 * By convention, Django appends ``"_id"`` to the foreign key field name.
457  
-  Yes, you can override this, as well.
  466
+  (Yes, you can override this, as well.)
458 467
 
459 468
 * The foreign key relationship is made explicit by a ``REFERENCES``
460 469
   statement.
@@ -501,12 +510,12 @@ Now, run :djadmin:`syncdb` again to create those model tables in your database:
501 510
 
502 511
     python manage.py syncdb
503 512
 
504  
-The :djadmin:`syncdb` command runs the sql from 'sqlall' on your database for
505  
-all apps in :setting:`INSTALLED_APPS` that don't already exist in your database.
506  
-This creates all the tables, initial data and indexes for any apps you have
507  
-added to your project since the last time you ran syncdb. :djadmin:`syncdb` can
508  
-be called as often as you like, and it will only ever create the tables that
509  
-don't exist.
  513
+The :djadmin:`syncdb` command runs the sql from :djadmin:`sqlall` on your
  514
+database for all apps in :setting:`INSTALLED_APPS` that don't already exist in
  515
+your database. This creates all the tables, initial data and indexes for any
  516
+apps you have added to your project since the last time you ran syncdb.
  517
+:djadmin:`syncdb` can be called as often as you like, and it will only ever
  518
+create the tables that don't exist.
510 519
 
511 520
 Read the :doc:`django-admin.py documentation </ref/django-admin>` for full
512 521
 information on what the ``manage.py`` utility can do.
@@ -537,15 +546,18 @@ the Python import path to your :file:`settings.py` file.
537 546
 
538 547
 Once you're in the shell, explore the :doc:`database API </topics/db/queries>`::
539 548
 
540  
-    >>> from polls.models import Poll, Choice # Import the model classes we just wrote.
  549
+    >>> from polls.models import Poll, Choice   # Import the model classes we just wrote.
541 550
 
542 551
     # No polls are in the system yet.
543 552
     >>> Poll.objects.all()
544 553
     []
545 554
 
546 555
     # Create a new Poll.
547  
-    >>> import datetime
548  
-    >>> p = Poll(question="What's up?", pub_date=datetime.datetime.now())
  556
+    # Support for time zones is enabled in the default settings file, so
  557
+    # Django expects a datetime with tzinfo for pub_date. Use timezone.now()
  558
+    # instead of datetime.datetime.now() and it will do the right thing.
  559
+    >>> from django.utils import timezone
  560
+    >>> p = Poll(question="What's new?", pub_date=timezone.now())
549 561
 
550 562
     # Save the object into the database. You have to call save() explicitly.
551 563
     >>> p.save()
@@ -559,12 +571,12 @@ Once you're in the shell, explore the :doc:`database API </topics/db/queries>`::
559 571
 
560 572
     # Access database columns via Python attributes.
561 573
     >>> p.question
562  
-    "What's up?"
  574
+    "What's new?"
563 575
     >>> p.pub_date
564  
-    datetime.datetime(2007, 7, 15, 12, 00, 53)
  576
+    datetime.datetime(2012, 2, 26, 13, 0, 0, 775217, tzinfo=<UTC>)
565 577
 
566 578
     # Change values by changing the attributes, then calling save().
567  
-    >>> p.pub_date = datetime.datetime(2007, 4, 1, 0, 0)
  579
+    >>> p.question = "What's up?"
568 580
     >>> p.save()
569 581
 
570 582
     # 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
617 629
 demonstration::
618 630
 
619 631
     import datetime
  632
+    from django.utils import timezone
620 633
     # ...
621 634
     class Poll(models.Model):
622 635
         # ...
623  
-        def was_published_today(self):
624  
-            return self.pub_date.date() == datetime.date.today()
  636
+        def was_published_recently(self):
  637
+            return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
625 638
 
626  
-Note the addition of ``import datetime`` to reference Python's standard
627  
-``datetime`` module.
  639
+Note the addition of ``import datetime`` and ``from django.utils import
  640
+timezone``, to reference Python's standard :mod:`datetime` module and Django's
  641
+time zone-related utilities in :mod:`django.utils.timezone` respectively. If
  642
+you aren't familiar with time zone handling in Python, you can learn more in
  643
+the :doc:`time zone support docs </topics/i18n/timezones>`.
628 644
 
629 645
 Save these changes and start a new Python interactive shell by running
630 646
 ``python manage.py shell`` again::
@@ -642,8 +658,8 @@ Save these changes and start a new Python interactive shell by running
642 658
     >>> Poll.objects.filter(question__startswith='What')
643 659
     [<Poll: What's up?>]
644 660
 
645  
-    # Get the poll whose year is 2007.
646  
-    >>> Poll.objects.get(pub_date__year=2007)
  661
+    # Get the poll whose year is 2012.
  662
+    >>> Poll.objects.get(pub_date__year=2012)
647 663
     <Poll: What's up?>
648 664
 
649 665
     >>> Poll.objects.get(id=2)
@@ -659,8 +675,8 @@ Save these changes and start a new Python interactive shell by running
659 675
 
660 676
     # Make sure our custom method worked.
661 677
     >>> p = Poll.objects.get(pk=1)
662  
-    >>> p.was_published_today()
663  
-    False
  678
+    >>> p.was_published_recently()
  679
+    True
664 680
 
665 681
     # Give the Poll a couple of Choices. The create call constructs a new
666 682
     # 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
693 709
     # The API automatically follows relationships as far as you need.
694 710
     # Use double underscores to separate relationships.
695 711
     # This works as many levels deep as you want; there's no limit.
696  
-    # Find all Choices for any poll whose pub_date is in 2007.
697  
-    >>> Choice.objects.filter(poll__pub_date__year=2007)
  712
+    # Find all Choices for any poll whose pub_date is in 2012.
  713
+    >>> Choice.objects.filter(poll__pub_date__year=2012)
698 714
     [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>]
699 715
 
700 716
     # Let's delete one of the choices. Use delete() for that.
46  docs/intro/tutorial02.txt
@@ -18,8 +18,8 @@ automatically-generated admin site.
18 18
     displayed on the public site. Django solves the problem of creating a
19 19
     unified interface for site administrators to edit content.
20 20
 
21  
-    The admin isn't necessarily intended to be used by site visitors; it's for
22  
-    site managers.
  21
+    The admin isn't intended to be used by site visitors; it's for site
  22
+    managers.
23 23
 
24 24
 Activate the admin site
25 25
 =======================
@@ -27,7 +27,7 @@ Activate the admin site
27 27
 The Django admin site is not activated by default -- it's an opt-in thing. To
28 28
 activate the admin site for your installation, do these three things:
29 29
 
30  
-* Add ``"django.contrib.admin"`` to your :setting:`INSTALLED_APPS` setting.
  30
+* Uncomment ``"django.contrib.admin"`` in the :setting:`INSTALLED_APPS` setting.
31 31
 
32 32
 * Run ``python manage.py syncdb``. Since you have added a new application
33 33
   to :setting:`INSTALLED_APPS`, the database tables need to be updated.
@@ -101,7 +101,7 @@ the Django admin index page:
101 101
 .. image:: _images/admin02t.png
102 102
    :alt: Django admin index page
103 103
 
104  
-You should see a few other types of editable content, including groups, users
  104
+You should see a few types of editable content, including groups, users
105 105
 and sites. These are core features Django ships with by default.
106 106
 
107 107
 Make the poll app modifiable in the admin
@@ -169,6 +169,11 @@ The bottom part of the page gives you a couple of options:
169 169
 
170 170
 * Delete -- Displays a delete confirmation page.
171 171
 
  172
+If the value of "Date published" doesn't match the time when you created the
  173
+poll in Tutorial 1, it probably means you forgot to set the correct value for
  174
+the :setting:`TIME_ZONE` setting. Change it, reload the page, and check that
  175
+the correct value appears.
  176
+
172 177
 Change the "Date published" by clicking the "Today" and "Now" shortcuts. Then
173 178
 click "Save and continue editing." Then click "History" in the upper right.
174 179
 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::
337 342
         # ...
338 343
         list_display = ('question', 'pub_date')
339 344
 
340  
-Just for good measure, let's also include the ``was_published_today`` custom
  345
+Just for good measure, let's also include the ``was_published_recently`` custom
341 346
 method from Tutorial 1::
342 347
 
343 348
     class PollAdmin(admin.ModelAdmin):
344 349
         # ...
345  
-        list_display = ('question', 'pub_date', 'was_published_today')
  350
+        list_display = ('question', 'pub_date', 'was_published_recently')
346 351
 
347 352
 Now the poll change list page looks like this:
348 353
 
@@ -350,17 +355,22 @@ Now the poll change list page looks like this:
350 355
    :alt: Polls change list page, updated
351 356
 
352 357
 You can click on the column headers to sort by those values -- except in the
353  
-case of the ``was_published_today`` header, because sorting by the output of
354  
-an arbitrary method is not supported. Also note that the column header for
355  
-``was_published_today`` is, by default, the name of the method (with
356  
-underscores replaced with spaces). But you can change that by giving that
357  
-method (in ``models.py``) a ``short_description`` attribute::
  358
+case of the ``was_published_recently`` header, because sorting by the output
  359
+of an arbitrary method is not supported. Also note that the column header for
  360
+``was_published_recently`` is, by default, the name of the method (with
  361
+underscores replaced with spaces), and that each line contains the string
  362
+representation of the output.
  363
+
  364
+You can improve that by giving that method (in ``models.py``) a few
  365
+attributes, as follows::
358 366
 
359 367
     class Poll(models.Model):
360 368
         # ...
361  
-        def was_published_today(self):
362  
-            return self.pub_date.date() == datetime.date.today()
363  
-        was_published_today.short_description = 'Published today?'
  369
+        def was_published_recently(self):
  370
+            return self.pub_date >= timezone.now() - datetime.timedelta(days=1)
  371
+        was_published_recently.admin_order_field = 'pub_date'
  372
+        was_published_recently.boolean = True
  373
+        was_published_recently.short_description = 'Published recently?'
364 374
 
365 375
 Edit your admin.py file again and add an improvement to the Poll change list page: Filters. Add the
366 376
 following line to ``PollAdmin``::
@@ -374,9 +384,9 @@ That adds a "Filter" sidebar that lets people filter the change list by the
374 384
    :alt: Polls change list page, updated
375 385
 
376 386
 The type of filter displayed depends on the type of field you're filtering on.
377  
-Because ``pub_date`` is a DateTimeField, Django knows to give the default
378  
-filter options for DateTimeFields: "Any date," "Today," "Past 7 days,"
379  
-"This month," "This year."
  387
+Because ``pub_date`` is a :class:`~django.db.models.fields.DateTimeField`,
  388
+Django knows to give appropriate filter options: "Any date," "Today," "Past 7
  389
+days," "This month," "This year."
380 390
 
381 391
 This is shaping up well. Let's add some search capability::
382 392
 
@@ -397,7 +407,7 @@ At top level, it displays all available years. Then it drills down to months
397 407
 and, ultimately, days.
398 408
 
399 409
 Now's also a good time to note that change lists give you free pagination. The
400  
-default is to display 50 items per page. Change-list pagination, search boxes,
  410
+default is to display 100 items per page. Change-list pagination, search boxes,
401 411
 filters, date-hierarchies and column-header-ordering all work together like you
402 412
 think they should.
403 413
 

0 notes on commit e0d78f8

Please sign in to comment.
Something went wrong with that request. Please try again.