Commit 824ca0d6 authored by Simon Meers's avatar Simon Meers
Browse files

[1.2.X] Fixed #14255 -- factor project name out of app imports in tutorial....

[1.2.X] Fixed #14255 -- factor project name out of app imports in tutorial. Thanks to adamend for the report and initial patch.

Backport of r14066 from trunk.


git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14067 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent b2bd6c9d
Loading
Loading
Loading
Loading
+12 −14
Original line number Diff line number Diff line
@@ -268,10 +268,8 @@ so you can focus on writing code rather than creating directories.
    configuration and apps for a particular Web site. A project can contain
    multiple apps. An app can be in multiple projects.

In this tutorial, we'll create our poll app in the :file:`mysite` directory,
for simplicity. As a consequence, the app will be coupled to the project --
that is, Python code within the poll app will refer to ``mysite.polls``.
Later in this tutorial, we'll discuss decoupling your apps for distribution.
Your apps can live anywhere on your `Python path`_. In this tutorial we will
create our poll app in the :file:`mysite` directory for simplicity.

To create your app, make sure you're in the :file:`mysite` directory and type
this command:
@@ -369,7 +367,7 @@ But first we need to tell our project that the ``polls`` app is installed.
    Django installation.

Edit the :file:`settings.py` file again, and change the
:setting:`INSTALLED_APPS` setting to include the string ``'mysite.polls'``. So
:setting:`INSTALLED_APPS` setting to include the string ``'polls'``. So
it'll look like this::

    INSTALLED_APPS = (
@@ -377,10 +375,10 @@ it'll look like this::
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.sites',
        'mysite.polls'
        'polls'
    )

Now Django knows ``mysite`` includes the ``polls`` app. Let's run another
Now Django knows to include the ``polls`` app. Let's run another
command:

.. code-block:: bash
@@ -488,9 +486,9 @@ We're using this instead of simply typing "python", because ``manage.py`` sets
up the project's environment for you. "Setting up the environment" involves two
things:

    * Putting ``mysite`` on ``sys.path``. For flexibility, several pieces of
    * Putting ``polls`` on ``sys.path``. For flexibility, several pieces of
      Django refer to projects in Python dotted-path notation (e.g.
      ``'mysite.polls.models'``). In order for this to work, the ``mysite``
      ``'polls.models'``). In order for this to work, the ``polls``
      package has to be on ``sys.path``.

      We've already seen one example of this: the :setting:`INSTALLED_APPS`
@@ -502,16 +500,16 @@ things:
.. admonition:: Bypassing manage.py

    If you'd rather not use ``manage.py``, no problem. Just make sure ``mysite``
    is at the root level on the Python path (i.e., ``import mysite`` works) and
    set the ``DJANGO_SETTINGS_MODULE`` environment variable to
    ``mysite.settings``.
    and ``polls`` are at the root level on the Python path (i.e., ``import mysite``
    and ``import polls`` work) and set the ``DJANGO_SETTINGS_MODULE`` environment
    variable to ``mysite.settings``.

    For more information on all of this, see the :doc:`django-admin.py
    documentation </ref/django-admin>`.

Once you're in the shell, explore the :doc:`database API </topics/db/queries>`::

    >>> from mysite.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()
@@ -619,7 +617,7 @@ Note the addition of ``import datetime`` to reference Python's standard
Save these changes and start a new Python interactive shell by running
``python manage.py shell`` again::

    >>> from mysite.polls.models import Poll, Choice
    >>> from polls.models import Poll, Choice

    # Make sure our __unicode__() addition worked.
    >>> Poll.objects.all()
+2 −2
Original line number Diff line number Diff line
@@ -103,7 +103,7 @@ Just one thing to do: We need to tell the admin that ``Poll``
objects have an admin interface. To do this, create a file called
``admin.py`` in your ``polls`` directory, and edit it to look like this::

    from mysite.polls.models import Poll
    from polls.models import Poll
    from django.contrib import admin

    admin.site.register(Poll)
@@ -239,7 +239,7 @@ Yet.
There are two ways to solve this problem. The first is to register ``Choice``
with the admin just as we did with ``Poll``. That's easy::

    from mysite.polls.models import Choice
    from polls.models import Choice

    admin.site.register(Choice)

+24 −24
Original line number Diff line number Diff line
@@ -84,10 +84,10 @@ Time for an example. Edit ``mysite/urls.py`` so it looks like this::
    admin.autodiscover()

    urlpatterns = patterns('',
        (r'^polls/$', 'mysite.polls.views.index'),
        (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
        (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'),
        (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
        (r'^polls/$', 'polls.views.index'),
        (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
        (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
        (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
        (r'^admin/', include(admin.site.urls)),
    )

@@ -96,8 +96,8 @@ This is worth a review. When somebody requests a page from your Web site -- say,
the :setting:`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/(?P<poll_id>\d+)/$'`` -- it loads the
function ``detail()`` from ``mysite/polls/views.py``. Finally,
it calls that ``detail()`` function like so::
function ``detail()`` from ``polls/views.py``. Finally, it calls that
``detail()`` function like so::

    detail(request=<HttpRequest object>, poll_id='23')

@@ -112,7 +112,7 @@ what you can do with them. And there's no need to add URL cruft such as ``.php``
-- unless you have a sick sense of humor, in which case you can do something
like this::

    (r'^polls/latest\.php$', 'mysite.polls.views.index'),
    (r'^polls/latest\.php$', 'polls.views.index'),

But, don't do that. It's silly.

@@ -148,17 +148,17 @@ You should get a pleasantly-colored error page with the following message::

    ViewDoesNotExist at /polls/

    Tried index in module mysite.polls.views. Error was: 'module'
    Tried index in module polls.views. Error was: 'module'
    object has no attribute 'index'

This error happened because you haven't written a function ``index()`` in the
module ``mysite/polls/views.py``.
module ``polls/views.py``.

Try "/polls/23/", "/polls/23/results/" and "/polls/23/vote/". The error
messages tell you which view Django tried (and failed to find, because you
haven't written any views yet).

Time to write the first view. Open the file ``mysite/polls/views.py``
Time to write the first view. Open the file ``polls/views.py``
and put the following Python code in it::

    from django.http import HttpResponse
@@ -207,7 +207,7 @@ in :doc:`Tutorial 1 </intro/tutorial01>`. 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 mysite.polls.models import Poll
    from polls.models import Poll
    from django.http import HttpResponse

    def index(request):
@@ -220,7 +220,7 @@ 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 mysite.polls.models import Poll
    from polls.models import Poll
    from django.http import HttpResponse

    def index(request):
@@ -279,7 +279,7 @@ template. Django provides a shortcut. Here's the full ``index()`` view,
rewritten::

    from django.shortcuts import render_to_response
    from mysite.polls.models import Poll
    from polls.models import Poll

    def index(request):
        latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5]
@@ -432,19 +432,19 @@ Take some time to play around with the views and template system. As you edit
the URLconf, you may notice there's a fair bit of redundancy in it::

    urlpatterns = patterns('',
        (r'^polls/$', 'mysite.polls.views.index'),
        (r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'),
        (r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'),
        (r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
        (r'^polls/$', 'polls.views.index'),
        (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
        (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
        (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
    )

Namely, ``mysite.polls.views`` is in every callback.
Namely, ``polls.views`` is in every callback.

Because this is a common case, the URLconf framework provides a shortcut for
common prefixes. You can factor out the common prefixes and add them as the
first argument to :func:`~django.conf.urls.defaults.patterns`, like so::

    urlpatterns = patterns('mysite.polls.views',
    urlpatterns = patterns('polls.views',
        (r'^polls/$', 'index'),
        (r'^polls/(?P<poll_id>\d+)/$', 'detail'),
        (r'^polls/(?P<poll_id>\d+)/results/$', 'results'),
@@ -470,7 +470,7 @@ We've been editing the URLs in ``mysite/urls.py``, but the URL design of an
app is specific to the app, not to the Django installation -- so let's move the
URLs within the app directory.

Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then, change
Copy the file ``mysite/urls.py`` to ``polls/urls.py``. Then, change
``mysite/urls.py`` to remove the poll-specific URLs and insert an
:func:`~django.conf.urls.defaults.include`::

@@ -479,7 +479,7 @@ Copy the file ``mysite/urls.py`` to ``mysite/polls/urls.py``. Then, change

    # ...
    urlpatterns = patterns('',
        (r'^polls/', include('mysite.polls.urls')),
        (r'^polls/', include('polls.urls')),
        # ...
    )

@@ -495,14 +495,14 @@ Here's what happens if a user goes to "/polls/34/" in this system:
    * Django will find the match at ``'^polls/'``

    * Then, Django will strip off the matching text (``"polls/"``) and send the
      remaining text -- ``"34/"`` -- to the 'mysite.polls.urls' URLconf for
      remaining text -- ``"34/"`` -- to the 'polls.urls' URLconf for
      further processing.

Now that we've decoupled that, we need to decouple the 'mysite.polls.urls'
Now that we've decoupled that, we need to decouple the 'polls.urls'
URLconf by removing the leading "polls/" from each line, and removing the
lines registering the admin site::

    urlpatterns = patterns('mysite.polls.views',
    urlpatterns = patterns('polls.views',
        (r'^$', 'index'),
        (r'^(?P<poll_id>\d+)/$', 'detail'),
        (r'^(?P<poll_id>\d+)/results/$', 'results'),
+6 −6
Original line number Diff line number Diff line
@@ -74,13 +74,13 @@ created a URLconf for the polls application that includes this line::
    (r'^(?P<poll_id>\d+)/vote/$', 'vote'),

We also created a dummy implementation of the ``vote()`` function. Let's
create a real version. Add the following to ``mysite/polls/views.py``::
create a real version. Add the following to ``polls/views.py``::

    from django.shortcuts import get_object_or_404, render_to_response
    from django.http import HttpResponseRedirect, HttpResponse
    from django.core.urlresolvers import reverse
    from django.template import RequestContext
    from mysite.polls.models import Choice, Poll
    from polls.models import Choice, Poll
    # ...
    def vote(request, poll_id):
        p = get_object_or_404(Poll, pk=poll_id)
@@ -98,7 +98,7 @@ create a real version. Add the following to ``mysite/polls/views.py``::
            # Always return an HttpResponseRedirect after successfully dealing
            # with POST data. This prevents data from being posted twice if a
            # user hits the Back button.
            return HttpResponseRedirect(reverse('mysite.polls.views.results', args=(p.id,)))
            return HttpResponseRedirect(reverse('polls.views.results', args=(p.id,)))

This code includes a few things we haven't covered yet in this tutorial:

@@ -222,7 +222,7 @@ tutorial so far::

    from django.conf.urls.defaults import *

    urlpatterns = patterns('mysite.polls.views',
    urlpatterns = patterns('polls.views',
        (r'^$', 'index'),
        (r'^(?P<poll_id>\d+)/$', 'detail'),
        (r'^(?P<poll_id>\d+)/results/$', 'results'),
@@ -232,7 +232,7 @@ tutorial so far::
Change it like so::

    from django.conf.urls.defaults import *
    from mysite.polls.models import Poll
    from polls.models import Poll

    info_dict = {
        'queryset': Poll.objects.all(),
@@ -242,7 +242,7 @@ Change it like so::
        (r'^$', 'django.views.generic.list_detail.object_list', info_dict),
        (r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', info_dict),
        url(r'^(?P<object_id>\d+)/results/$', 'django.views.generic.list_detail.object_detail', dict(info_dict, template_name='polls/results.html'), 'poll_results'),
        (r'^(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'),
        (r'^(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
    )

We're using two generic views here: