Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

magic-removal: Fixes #1599, Refs #1464 -- Updated all tutorials for n…

…ew syntax, changes in manage.py, etc.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2632 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit d1083f15fbdf073d768677f683a1e3b5136e3e41 1 parent 218035c
@freakboy3742 freakboy3742 authored
View
50 docs/tutorial01.txt
@@ -24,7 +24,7 @@ Initial setup
If this is your first time using Django, you'll have to take care of some
initial setup.
-Run the command ``django-admin.py startproject myproject``. That'll create a
+Run the command ``django-admin.py startproject myproject``. This will create a
``myproject`` directory in your current directory.
(``django-admin.py`` should be on your system path if you installed Django via
@@ -125,9 +125,10 @@ database's connection parameters:
database's interactive prompt.
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.
+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, ``INSTALLED_APPS`` contains the following apps, all of which come
with Django::
@@ -285,12 +286,9 @@ to include the string ``'myproject.polls'``. So it'll look like this::
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
- 'myproject.polls',
+ 'myproject.polls'
)
-(Don't forget the trailing comma, because of Python's rule about single-value
-tuples: Without a trailing comma, Python wouldn't know this was a tuple.)
-
Now Django knows ``myproject`` includes the ``polls`` app. Let's run another command::
python manage.py sql polls
@@ -331,6 +329,12 @@ Note the following:
quotes. The author of this tutorial runs PostgreSQL, so the example
output is in PostgreSQL syntax.
+ * The `sql` command doesn't actually run the SQL in your database - it just
+ prints it to the screen so that you can see what SQL Django thinks is required.
+ If you wanted to, you could copy and paste this SQL into your database prompt.
+ However, as we will see shortly, Django provides an easier way of committing
+ the SQL to the database.
+
If you're interested, also run the following commands:
* ``python manage.py sqlinitialdata polls`` -- Outputs any initial data
@@ -343,8 +347,8 @@ If you're interested, also run the following commands:
* ``python manage.py sqlindexes polls`` -- Outputs the ``CREATE INDEX``
statements for this app.
- * ``python manage.py sqlall polls`` -- A combination of 'sql' and
- 'sqlinitialdata'.
+ * ``python manage.py sqlall polls`` -- A combination of all the SQL from
+ the 'sql', 'sqlinitialdata', and 'sqlindexes' commands.
Looking at the output of those commands can help you understand what's actually
happening under the hood.
@@ -353,9 +357,11 @@ Now, run ``syncdb`` again to create those model tables in your database::
python manage.py syncdb
-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.
+The ``syncdb`` command runs the sql from 'sqlall' on your database for all apps
+in ``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. ``syncdb`` can be called as often
+as you like, and it will only ever create the tables that don't exist.
Read the `django-admin.py documentation`_ for full information on what the
``manage.py`` utility can do.
@@ -454,10 +460,11 @@ representations are used throughout Django's automatically-generated admin.
Note these are normal Python methods. Let's add a custom method, just for
demonstration::
+ import datetime
+ # ...
class Poll(models.Model):
# ...
def was_published_today(self):
- import datetime
return self.pub_date.date() == datetime.date.today()
Note the addition of ``import datetime`` to reference Python's standard
@@ -488,8 +495,6 @@ Let's jump back into the Python interactive shell by running
Traceback (most recent call last):
...
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.
@@ -502,14 +507,15 @@ Let's jump back into the Python interactive shell by running
>>> 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.
+ # 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
+ # of available choices and returns the new Choice object.
>>> p = Poll.objects.get(pk=1)
- >>> p.choice_set.add(choice='Not much', votes=0)
+ >>> p.choice_set.create(choice='Not much', votes=0)
Not much
- >>> p.choice_set.add(choice='The sky', votes=0)
+ >>> p.choice_set.create(choice='The sky', votes=0)
The sky
- >>> c = p.choice_set.add(choice='Just hacking again', votes=0)
+ >>> c = p.choice_set.create(choice='Just hacking again', votes=0)
# Choice objects have API access to their related Poll objects.
>>> c.poll
@@ -518,7 +524,7 @@ Let's jump back into the Python interactive shell by running
# And vice versa: Poll objects get access to Choice objects.
>>> p.choice_set.all()
[Not much, The sky, Just hacking again]
- >>> p.choice_set.all().count()
+ >>> p.choice_set.count()
3
# The API automatically follows relationships as far as you need.
View
16 docs/tutorial02.txt
@@ -31,22 +31,13 @@ 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 ``INSTALLED_APPS`` setting.
- * Run the command ``python manage.py install admin``. This will create an
- extra database table that the admin needs.
+ * Run ``python manage.py syncdb``. Since you have added a new application
+ to ``INSTALLED_APPS``, the database tables need to be updated.
* Edit your ``myproject/urls.py`` file and uncomment the line below
"Uncomment this for admin:". This file is a URLconf; we'll dig into
URLconfs in the next tutorial. For now, all you need to know is that it
maps URL roots to applications.
-Create a user account
-=====================
-
-Run the following command to create a superuser account for your admin site::
-
- python manage.py createsuperuser
-
-The script will prompt you for a username, e-mail address and password (twice).
-
Start the development server
============================
@@ -96,7 +87,8 @@ creating an empty class means "give this object an admin interface using
all the default options."
Now reload the Django admin page to see your changes. Note that you don't have
-to restart the development server -- it auto-reloads code.
+to restart the development server -- the server will auto-reloads your project,
+so any modifications code will be seen immediately in your browser.
Explore the free admin functionality
====================================
View
72 docs/tutorial03.txt
@@ -74,25 +74,27 @@ Time for an example. Edit ``myproject/urls.py`` so it looks like this::
urlpatterns = patterns('',
(r'^polls/$', 'myproject.polls.views.index'),
- (r'^polls/(\d+)/$', 'myproject.polls.views.detail'),
- (r'^polls/(\d+)/results/$', 'myproject.polls.views.results'),
- (r'^polls/(\d+)/vote/$', 'myproject.polls.views.vote'),
+ (r'^polls/(?P<poll_id>\d+)/$', 'myproject.polls.views.detail'),
+ (r'^polls/(?P<poll_id>\d+)/results/$', 'myproject.polls.views.results'),
+ (r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'),
)
This is worth a review. When somebody requests a page from your Web site --
say, "/polls/23/", Django will load this Python module, because it's pointed to
by the ``ROOT_URLCONF`` setting. It finds the variable named ``urlpatterns``
and traverses the regular expressions in order. When it finds a regular
-expression that matches -- ``r'^polls/(\d+)/$'`` -- it loads the
+expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
associated Python package/module: ``myproject.polls.views.detail``. That
corresponds to the function ``detail()`` in ``myproject/polls/views.py``.
Finally, it calls that ``detail()`` function like so::
detail(request=<HttpRequest object>, poll_id='23')
-The ``poll_id='23'`` part comes from ``(\d+)``. Using parenthesis around a
+The ``poll_id='23'`` part comes from ``(?P<poll_id>\d+)``. Using parenthesis around a
pattern "captures" the text matched by that pattern and sends it as an argument
-to the view function.
+to the view function; the ``?P<poll_id>`` defines the name that will be used to
+identify the matched pattern; and \d+ is a regular experession to match a sequence of
+digits (i.e., a number).
Because the URL patterns are regular expressions, there really is no limit on
what you can do with them. And there's no need to add URL cruft such as
@@ -185,29 +187,29 @@ in Tutorial 1. Here's one stab at the ``index()`` view, which displays the
latest 5 poll questions in the system, separated by commas, according to
publication date::
- from django.models.polls import polls
- from django.http import HttpResponse
+ from myproject.polls.models import Poll
+ from django.http import HttpResponse
- def index(request):
- latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
- output = ', '.join([p.question for p in latest_poll_list])
- return HttpResponse(output)
+ def index(request):
+ latest_poll_list = Poll.objects.all().order_by('-pub_date')
+ output = ', '.join([p.question for p in latest_poll_list])
+ return HttpResponse(output)
There's a problem here, though: The page's design is hard-coded in the view. If
you want to change the way the page looks, you'll have to edit this Python code.
So let's use Django's template system to separate the design from Python::
- from django.template import Context, loader
- from django.models.polls import polls
- from django.http import HttpResponse
+ from django.template import Context, loader
+ from myproject.polls.models import Poll
+ from django.http import HttpResponse
- def index(request):
- latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
- t = loader.get_template('polls/index')
- c = Context({
- 'latest_poll_list': latest_poll_list,
- })
- return HttpResponse(t.render(c))
+ def index(request):
+ latest_poll_list = Poll.objects.all().order_by('-pub_date')
+ t = loader.get_template('polls/index')
+ c = Context({
+ 'latest_poll_list': latest_poll_list,
+ })
+ return HttpResponse(t.render(c))
That code loads the template called "polls/index" and passes it a context. The
context is a dictionary mapping template variable names to Python objects.
@@ -254,11 +256,11 @@ It's a very common idiom to load a template, fill a context and return an
``HttpResponse`` object with the result of the rendered template. Django
provides a shortcut. Here's the full ``index()`` view, rewritten::
- from django.shortcuts import render_to_response
- from django.models.polls import polls
+ from django.shortcuts import render_to_response
+ from myproject.polls.models import Poll
- def index(request):
- latest_poll_list = polls.get_list(order_by=['-pub_date'], limit=5)
+ def index(request):
+ latest_poll_list = Poll.objects.all().order_by('-pub_date')
return render_to_response('polls/index', {'latest_poll_list': latest_poll_list})
Note that we no longer need to import ``loader``, ``Context`` or
@@ -275,12 +277,13 @@ Now, let's tackle the poll detail view -- the page that displays the question
for a given poll. Here's the view::
from django.http import Http404
- def detail(request, poll_id):
- try:
- p = polls.get_object(pk=poll_id)
- except polls.PollDoesNotExist:
- raise Http404
- return render_to_response('polls/detail', {'poll': p})
+ # ...
+ def detail(request, poll_id):
+ try:
+ p = Poll.objects.get(pk=poll_id)
+ except Poll.DoesNotExist:
+ raise Http404
+ return render_to_response('polls/detail', {'poll': p})
The new concept here: The view raises the ``django.http.Http404``
exception if a poll with the requested ID doesn't exist.
@@ -292,9 +295,10 @@ It's a very common idiom to use ``get_object()`` and raise ``Http404`` if the
object doesn't exist. Django provides a shortcut. Here's the ``detail()`` view,
rewritten::
- from django.shortcuts import get_object_or_404
+ from django.shortcuts import render_to_response, get_object_or_404
+ # ...
def detail(request, poll_id):
- p = get_object_or_404(polls, pk=poll_id)
+ p = get_object_or_404(Poll, pk=poll_id)
return render_to_response('polls/detail', {'poll': p})
The ``get_object_or_404()`` function takes a Django model module as its first
View
56 docs/tutorial04.txt
@@ -18,7 +18,7 @@ template contains an HTML ``<form>`` element::
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form action="/polls/{{ poll.id }}/vote/" method="post">
- {% for choice in poll.get_choice_list %}
+ {% for choice in poll.choice_set.all %}
<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />
<label for="choice{{ forloop.counter }}">{{ choice.choice }}</label><br />
{% endfor %}
@@ -41,22 +41,22 @@ A quick rundown:
Django; it's just good Web development practice.
Now, let's create a Django view that handles the submitted data and does
-something with it. Remember, in `Tutorial 3`_, we create a URLconf that
-included this line::
+something with it. Remember, in `Tutorial 3`_, we create a URLconf for the
+polls application that includes this line::
- (r'^polls/(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'),
+ (r'^(?P<poll_id>\d+)/vote/$', 'myproject.polls.views.vote'),
So let's create a ``vote()`` function in ``myproject/polls/views.py``::
from django.shortcuts import get_object_or_404, render_to_response
- from django.http import HttpResponseRedirect
+ from django.http import Http404,HttpResponseRedirect
from myproject.polls.models import Choice, Poll
-
+ # ...
def vote(request, poll_id):
p = get_object_or_404(Poll, pk=poll_id)
try:
selected_choice = p.choice_set.filter(pk=request.POST['choice'])
- except (KeyError, choices.ChoiceDoesNotExist):
+ except (KeyError, Choice.DoesNotExist):
# Redisplay the poll voting form.
return render_to_response('polls/detail', {
'poll': p,
@@ -113,7 +113,7 @@ Now, create a ``results.html`` template::
<h1>{{ poll.question }}</h1>
<ul>
- {% for choice in poll.get_choice_list %}
+ {% for choice in poll.choice_set.all %}
<li>{{ choice.choice }} -- {{ choice.votes }} vote{{ choice.votes|pluralize }}</li>
{% endfor %}
</ul>
@@ -185,37 +185,45 @@ We're using two generic views here: ``object_list`` and ``object_detail``.
Respectively, those two views abstract the concepts of "display a list of
objects" and "display a detail page for a particular type of object."
- * Each generic view needs to know which model its acting on. This
- is done using a QuerySet.
+ * Each generic view needs to know what data it will be acting upon. This
+ data is provided in a dictionary. The ``queryset`` key in this dictionary
+ points to the list of objects to be manipulated by the generic view.
- * The ``object_detail`` generic view expects that the ID value captured
- from the URL is called ``"object_id"``, so we've changed ``poll_id`` to
+ * The ``object_detail`` generic view expects the ID value captured
+ from the URL to be called ``"object_id"``, so we've changed ``poll_id`` to
``object_id`` for the generic views.
By default, the ``object_detail`` generic view uses a template called
-``<app_label>/<module_name>_detail``. In our case, it'll use the template
-``"polls/polls_detail"``. Thus, rename your ``polls/detail.html`` template to
-``polls/polls_detail.html``, and change the ``render_to_response()`` line in
+``<app name>/<module name>_detail``. In our case, it'll use the template
+``"polls/poll_detail"``. Thus, rename your ``polls/detail.html`` template to
+``polls/poll_detail.html``, and change the ``render_to_response()`` line in
``vote()``.
Similarly, the ``object_list`` generic view uses a template called
-``<app_label>/<module_name>_list``. Thus, rename ``polls/index.html`` to
-``polls/polls_list.html``.
+``<app name>/<module name>_list``. Thus, rename ``poll/index.html`` to
+``polls/poll_list.html``.
Because we have more than one entry in the URLconf that uses ``object_detail``
for the polls app, we manually specify a template name for the results view:
``template_name='polls/results'``. Otherwise, both views would use the same
template. Note that we use ``dict()`` to return an altered dictionary in place.
-The generic views pass ``object`` and ``object_list`` to their templates, so
-change your templates so that ``latest_poll_list`` becomes ``object_list`` and
-``poll`` becomes ``object``.
+In previous versions of the tutorial, the templates have been provided with a context
+that contains the ``poll` and ``latest_poll_list`` context variables. However,
+the generic views provide the variables ``object`` and ``object_list`` as context.
+Therefore, you need to change your templates to match the new context variables.
+Go through your templates, and modify any reference to ``latest_poll_list`` to
+``object_list``, and change any reference to ``poll`` to ``object``.
+
+You can now delete the ``index()``, ``detail()`` and ``results()`` views
+from ``polls/views.py``. We don't need them anymore -- they have been replaced
+by generic views.
-In the ``vote()`` view, change the template call from ``polls/detail`` to
-``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``.
+The ``vote()`` view is still required. However, it must be modified to match
+the new templates and context variables. Change the template call from ``polls/detail``
+to ``polls/polls_detail``, and pass ``object`` in the context instead of ``poll``.
-Finally, you can delete the ``index()``, ``detail()`` and ``results()`` views
-from ``polls/views.py``. We don't need them anymore.
+Run the server, and use your new polling app based on generic views.
For full details on generic views, see the `generic views documentation`_.
Please sign in to comment.
Something went wrong with that request. Please try again.