Skip to content

Commit

Permalink
magic-removal: Fixed #1464 -- Updated tutorial01 for magic-removal. T…
Browse files Browse the repository at this point in the history
…hanks, Jeremy D.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2527 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
adrianholovaty committed Mar 17, 2006
1 parent fd00f02 commit 4044218
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 84 deletions.
2 changes: 1 addition & 1 deletion docs/middleware.txt
Expand Up @@ -96,7 +96,7 @@ Also removes the content from any response to a HEAD request and sets the
``Date`` and ``Content-Length`` response-headers.

django.contrib.sessions.middleware.SessionMiddleware
--------------------------------------------
----------------------------------------------------

Enables session support. See the `session documentation`_.

Expand Down
2 changes: 1 addition & 1 deletion docs/templates_python.txt
Expand Up @@ -256,7 +256,7 @@ Using a ``Context`` as a stack comes in handy in some custom template tags, as
you'll see below.

Subclassing Context: RequestContext
----------------------------------
-----------------------------------

Django comes with a special ``Context`` class,
``django.template.RequestContext``, that acts slightly differently than
Expand Down
187 changes: 105 additions & 82 deletions docs/tutorial01.txt
Expand Up @@ -72,8 +72,8 @@ command line::
Validating models...
0 errors found.

Starting server on port 8000 with settings module 'myproject.settings'.
Go to http://127.0.0.1:8000/ for Django.
Django version 0.92, using settings 'myproject.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).

(If you get an error about ``DATABASE_ENGINE``, edit your ``settings.py`` file
Expand Down Expand Up @@ -124,30 +124,51 @@ database's connection parameters:
point. Do that with "``CREATE DATABASE database_name;``" within your
database's interactive prompt.

Run the following command to initialize your database with Django's core
database tables::
While you're editing ``settings.py``, take note of the ``INSTALLED_APPS``
setting. 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 distribute them.

python manage.py init
By default, ``INSTALLED_APPS`` contains the following apps, all of which come
with Django::

If you don't see any errors, it worked.
* ``django.contrib.auth`` -- An authentication system.
* ``django.contrib.contenttypes`` -- A framework for content types.
* ``django.contrib.sessions`` -- A session framework.
* ``django.contrib.sites`` -- A framework for managing multiple sites
with one Django installation.

These applications are included by default as a convenience for the common case.

Each of these applications makes use of at least one database table, though,
so we need to create the tables in the database before we can use them. To do
that, run the following command::

python manage.py syncdb

The ``syncdb`` command looks at the ``INSTALLED_APPS`` setting and creates any
necessary database tables according to the database settings in your
``settings.py`` file. You'll see a message for each database table it creates,
and you'll get a prompt asking you if you'd like to create a superuser account
for the authentication system. Go ahead and do that.

If you're interested, run the command-line client for your database and type
``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to
display the tables Django created.

.. admonition:: About those database tables
.. admonition:: For the minimalists

The tables created by ``manage.py init`` are for sessions, authentication
and other features Django provides. The next release of Django will have
a "lite" version of the ``init`` command that won't install any database
tables if you don't want them.
Like we said above, the default applications are included for the common
case, but not everybody needs them. If you don't need any or all of them,
feel free to comment-out or delete the appropriate line(s) from
``INSTALLED_APPS`` before running ``syncdb``. The ``syncdb`` command will
only create tables for apps in ``INSTALLED_APPS``.

Creating models
===============

Now that your environment -- a "project" -- is set up, you're set to start
doing work. (You won't have to take care of that boring administrative stuff
again.)
doing work.

Each application you write in Django consists of a Python package, somewhere
on your `Python path`_, that follows a certain convention. Django comes with a
Expand Down Expand Up @@ -176,9 +197,7 @@ That'll create a directory ``polls``, which is laid out like this::

polls/
__init__.py
models/
__init__.py
polls.py
models.py
views.py

This directory structure will house the poll application.
Expand All @@ -198,28 +217,28 @@ a question and a publication date. A choice has two fields: the text of the
choice and a vote tally. Each choice is associated with a poll.

These concepts are represented by simple Python classes. Edit the
``polls/models/polls.py`` file so it looks like this::
``polls/models.py`` file so it looks like this::

from django.core import meta
from django.db import models

class Poll(meta.Model):
question = meta.CharField(maxlength=200)
pub_date = meta.DateTimeField('date published')
class Poll(models.Model):
question = models.CharField(maxlength=200)
pub_date = models.DateTimeField('date published')

class Choice(meta.Model):
poll = meta.ForeignKey(Poll)
choice = meta.CharField(maxlength=200)
votes = meta.IntegerField()
class Choice(models.Model):
poll = models.ForeignKey(Poll)
choice = models.CharField(maxlength=200)
votes = models.IntegerField()

The code is straightforward. Each model is represented by a class that
subclasses ``django.core.meta.Model``. Each model has a number of class
subclasses ``django.db.models.Model``. Each model has a number of class
variables, each of which represents a database field in the model.

Each field is represented by an instance of a ``meta.*Field`` class -- e.g.,
``meta.CharField`` for character fields and ``meta.DateTimeField`` for
Each field is represented by an instance of a ``models.*Field`` class -- e.g.,
``models.CharField`` for character fields and ``models.DateTimeField`` for
datetimes. This tells Django what type of data each field holds.

The name of each ``meta.*Field`` instance (e.g. ``question`` or ``pub_date`` )
The name of each ``models.*Field`` instance (e.g. ``question`` or ``pub_date`` )
is the field's name, in machine-friendly format. You'll use this value in your
Python code, and your database will use it as the column name.

Expand All @@ -230,11 +249,11 @@ the machine-readable name. In this example, we've only defined a human-readable
name for ``Poll.pub_date``. For all other fields in this model, the field's
machine-readable name will suffice as its human-readable name.

Some ``meta.*Field`` classes have required elements. ``meta.CharField``, for
example, requires that you give it a ``maxlength``. That's used not only in the
database schema, but in validation, as we'll soon see.
Some ``Field`` classes have required elements. ``CharField``, for example,
requires that you give it a ``maxlength``. That's used not only in the database
schema, but in validation, as we'll soon see.

Finally, note a relationship is defined, using ``meta.ForeignKey``. That tells
Finally, note a relationship is defined, using ``models.ForeignKey``. That tells
Django each Choice is related to a single Poll. Django supports all the common
database relationships: many-to-ones, many-to-manys and one-to-ones.

Expand Down Expand Up @@ -262,6 +281,10 @@ Edit the ``settings.py`` file again, and change the ``INSTALLED_APPS`` setting
to include the string ``'myproject.polls'``. So it'll look like this::

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'myproject.polls',
)

Expand All @@ -275,12 +298,12 @@ Now Django knows ``myproject`` includes the ``polls`` app. Let's run another com
You should see the following (the CREATE TABLE SQL statements for the polls app)::

BEGIN;
CREATE TABLE "polls_polls" (
CREATE TABLE "polls_poll" (
"id" serial NOT NULL PRIMARY KEY,
"question" varchar(200) NOT NULL,
"pub_date" timestamp with time zone NOT NULL
);
CREATE TABLE "polls_choices" (
CREATE TABLE "polls_choice" (
"id" serial NOT NULL PRIMARY KEY,
"poll_id" integer NOT NULL REFERENCES "polls_polls" ("id"),
"choice" varchar(200) NOT NULL,
Expand All @@ -291,12 +314,12 @@ You should see the following (the CREATE TABLE SQL statements for the polls app)
Note the following:

* Table names are automatically generated by combining the name of the app
(``polls``) with a plural version of the object name (polls and choices).
(You can override this behavior.)
(``polls``) and the lowercase name of the model -- ``poll`` and
``choice``. (You can override this behavior.)

* Primary keys (IDs) are added automatically. (You can override this, too.)

* Django appends ``"_id"`` to the foreign key field name, by convention.
* By convention, Django appends ``"_id"`` to the foreign key field name.
Yes, you can override this, as well.

* The foreign key relationship is made explicit by a ``REFERENCES`` statement.
Expand All @@ -306,12 +329,12 @@ Note the following:
``integer primary key`` (SQLite) are handled for you automatically. Same
goes for quoting of field names -- e.g., using double quotes or single
quotes. The author of this tutorial runs PostgreSQL, so the example
output is inPostgreSQL syntax.
output is in PostgreSQL syntax.

If you're interested, also run the following commands:

* ``python manage.py sqlinitialdata polls`` -- Outputs the initial-data
inserts required for Django's admin framework.
* ``python manage.py sqlinitialdata polls`` -- Outputs any initial data
required for Django's admin framework and your models.

* ``python manage.py sqlclear polls`` -- Outputs the necessary ``DROP
TABLE`` statements for this app, according to which tables already exist
Expand All @@ -326,14 +349,13 @@ If you're interested, also run the following commands:
Looking at the output of those commands can help you understand what's actually
happening under the hood.

Now, run this command to create the database tables for the polls app
automatically::
Now, run ``syncdb`` again to create those model tables in your database::

python manage.py install polls
python manage.py syncdb

Behind the scenes, all that command does is take the output of
``python manage.py sqlall polls`` and execute it in the database pointed-to by
your Django settings file.
As a review, the ``syncdb`` command creates the tables for all apps in
``INSTALLED_APPS`` that don't already exist in your database. So you can run it
again and again, and it'll always just create the tables that don't exist.

Read the `django-admin.py documentation`_ for full information on what the
``manage.py`` utility can do.
Expand Down Expand Up @@ -374,17 +396,16 @@ things:

Once you're in the shell, explore the database API::

# Modules are dynamically created within django.models.
# Their names are plural versions of the model class names.
>>> from django.models.polls import polls, choices
# Import the model classes we just wrote.
>>> from myproject.polls.models import Poll, Choice

# No polls are in the system yet.
>>> polls.get_list()
>>> Poll.objects.all()
[]

# Create a new Poll.
>>> from datetime import datetime
>>> p = polls.Poll(question="What's up?", pub_date=datetime.now())
>>> p = Poll(question="What's up?", pub_date=datetime.now())

# Save the object into the database. You have to call save() explicitly.
>>> p.save()
Expand All @@ -407,20 +428,21 @@ Once you're in the shell, explore the database API::
>>> p.save()

# get_list() displays all the polls in the database.
>>> polls.get_list()
>>> Poll.objects.all()
[<Poll object>]


Wait a minute. ``<Poll object>`` is, utterly, an unhelpful representation of
this object. Let's fix that by editing the polls model
(in the ``polls/models/polls.py`` file) and adding a ``__repr__()`` method to
(in the ``polls/models.py`` file) and adding a ``__repr__()`` method to
both ``Poll`` and ``Choice``::

class Poll(meta.Model):
class Poll(models.Model):
# ...
def __repr__(self):
return self.question

class Choice(meta.Model):
class Choice(models.Model):
# ...
def __repr__(self):
return self.choice
Expand All @@ -432,81 +454,82 @@ representations are used throughout Django's automatically-generated admin.
Note these are normal Python methods. Let's add a custom method, just for
demonstration::

class Poll(meta.Model):
class Poll(models.Model):
# ...
def was_published_today(self):
import datetime
return self.pub_date.date() == datetime.date.today()

Note ``import datetime`` wasn't necessary. Each model method has access to
a handful of commonly-used variables for convenience, including the
``datetime`` module from the Python standard library.
Note the addition of ``import datetime`` to reference Python's standard
``datetime`` module.

Let's jump back into the Python interactive shell by running
``python manage.py shell`` again::

>>> from django.models.polls import polls, choices
>>> from myproject.polls.models import Poll, Choice

# Make sure our __repr__() addition worked.
>>> polls.get_list()
>>> Poll.objects.all()
[What's up?]

# Django provides a rich database lookup API that's entirely driven by
# keyword arguments.
>>> polls.get_object(id__exact=1)
What's up?
>>> polls.get_object(question__startswith='What')
What's up?
>>> Poll.objects.filter(id=1)
[What's up?]
>>> Poll.objects.filter(question__startswith='What')
[What's up?]

# Get the poll whose year is 2005. Of course, if you're going through this
# tutorial in another year, change as appropriate.
>>> polls.get_object(pub_date__year=2005)
>>> Poll.objects.get(pub_date__year=2005)
What's up?

>>> polls.get_object(id__exact=2)
>>> Poll.objects.get(id=2)
Traceback (most recent call last):
...
PollDoesNotExist: Poll does not exist for {'id__exact': 2}
>>> polls.get_list(question__startswith='What')
DoesNotExist: Poll does not exist for {'id': 2}
>>> Poll.objects.filter(question__startswith='What')
[What's up?]

# Lookup by a primary key is the most common case, so Django provides a
# shortcut for primary-key exact lookups.
# The following is identical to polls.get_object(id__exact=1).
>>> polls.get_object(pk=1)
# The following is identical to Poll.objects.get(id=1).
>>> Poll.objects.get(pk=1)
What's up?

# Make sure our custom method worked.
>>> p = polls.get_object(pk=1)
>>> p = Poll.objects.get(pk=1)
>>> p.was_published_today()
False

# Give the Poll a couple of Choices. Each one of these method calls does an
# INSERT statement behind the scenes and returns the new Choice object.
>>> p = polls.get_object(pk=1)
>>> p.add_choice(choice='Not much', votes=0)
>>> p = Poll.objects.get(pk=1)
>>> p.choice_set.add(choice='Not much', votes=0)
Not much
>>> p.add_choice(choice='The sky', votes=0)
>>> p.choice_set.add(choice='The sky', votes=0)
The sky
>>> c = p.add_choice(choice='Just hacking again', votes=0)
>>> c = p.choice_set.add(choice='Just hacking again', votes=0)

# Choice objects have API access to their related Poll objects.
>>> c.get_poll()
>>> c.poll
What's up?

# And vice versa: Poll objects get access to Choice objects.
>>> p.get_choice_list()
>>> p.choice_set.all()
[Not much, The sky, Just hacking again]
>>> p.get_choice_count()
>>> p.choice_set.all().count()
3

# 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 2005.
>>> choices.get_list(poll__pub_date__year=2005)
>>> Choice.objects.filter(poll__pub_date__year=2005)
[Not much, The sky, Just hacking again]

# Let's delete one of the choices. Use delete() for that.
>>> c = p.get_choice(choice__startswith='Just hacking')
>>> c = p.choice_set.filter(choice__startswith='Just hacking')
>>> c.delete()

For full details on the database API, see our `Database API reference`_.
Expand Down

0 comments on commit 4044218

Please sign in to comment.