diff --git a/django/utils/timezone.py b/django/utils/timezone.py index 35bf297358..676f8f18af 100644 --- a/django/utils/timezone.py +++ b/django/utils/timezone.py @@ -32,6 +32,9 @@ class UTC(tzinfo): Used only when pytz isn't available. """ + def __repr__(self): + return "" + 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 "" + def utcoffset(self, dt): if self._isdst(dt): return self.DSTOFFSET diff --git a/docs/intro/_images/admin13.png b/docs/intro/_images/admin13.png index 64ed0580dc..4ae9dad8ab 100644 Binary files a/docs/intro/_images/admin13.png and b/docs/intro/_images/admin13.png differ diff --git a/docs/intro/_images/admin13t.png b/docs/intro/_images/admin13t.png index f9082b97c0..9ebdb50091 100644 Binary files a/docs/intro/_images/admin13t.png and b/docs/intro/_images/admin13t.png differ diff --git a/docs/intro/_images/admin14.png b/docs/intro/_images/admin14.png index 01fa2cc04b..61a7f44a0c 100644 Binary files a/docs/intro/_images/admin14.png and b/docs/intro/_images/admin14.png differ diff --git a/docs/intro/_images/admin14t.png b/docs/intro/_images/admin14t.png index 81f0a4836c..f62bb4a8c2 100644 Binary files a/docs/intro/_images/admin14t.png and b/docs/intro/_images/admin14t.png differ diff --git a/docs/intro/tutorial01.txt b/docs/intro/tutorial01.txt index 406259e132..208d6f3601 100644 --- a/docs/intro/tutorial01.txt +++ b/docs/intro/tutorial01.txt @@ -70,7 +70,7 @@ This will create a ``mysite`` directory in your current directory. :doc:`django-admin.py ` 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 ` 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 ` -- Either ``'django.db.backends.postgresql_psycopg2'``, - ``'django.db.backends.mysql'`` or - ``'django.db.backends.sqlite3'``. Other backends are - :setting:`also available `. + ``'django.db.backends.mysql'``, ``'django.db.backends.sqlite3'`` or + ``'django.db.backends.oracle'``. Other backends are :setting:`also available + `. * :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 ` 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 `:: - >>> 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 `:: # 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=) # 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 `. 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') [] - # 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.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) [, , ] # Let's delete one of the choices. Use delete() for that. diff --git a/docs/intro/tutorial02.txt b/docs/intro/tutorial02.txt index 1cd7136803..37f82fa6b5 100644 --- a/docs/intro/tutorial02.txt +++ b/docs/intro/tutorial02.txt @@ -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.