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

git-svn-id: http://code.djangoproject.com/svn/django/trunk@14066 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Simon Meers 2010-10-09 07:45:52 +00:00
parent 307e71a734
commit d81faf356c
4 changed files with 44 additions and 46 deletions

View File

@ -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 configuration and apps for a particular Web site. A project can contain
multiple apps. An app can be in multiple projects. multiple apps. An app can be in multiple projects.
In this tutorial, we'll create our poll app in the :file:`mysite` directory, Your apps can live anywhere on your `Python path`_. In this tutorial we will
for simplicity. As a consequence, the app will be coupled to the project -- create our poll app in the :file:`mysite` directory for simplicity.
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.
To create your app, make sure you're in the :file:`mysite` directory and type To create your app, make sure you're in the :file:`mysite` directory and type
this command: this command:
@ -369,7 +367,7 @@ But first we need to tell our project that the ``polls`` app is installed.
Django installation. Django installation.
Edit the :file:`settings.py` file again, and change the 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:: it'll look like this::
INSTALLED_APPS = ( INSTALLED_APPS = (
@ -377,10 +375,10 @@ it'll look like this::
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', '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: command:
.. code-block:: bash .. 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 up the project's environment for you. "Setting up the environment" involves two
things: 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. 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``. package has to be on ``sys.path``.
We've already seen one example of this: the :setting:`INSTALLED_APPS` We've already seen one example of this: the :setting:`INSTALLED_APPS`
@ -502,16 +500,16 @@ things:
.. admonition:: Bypassing manage.py .. admonition:: Bypassing manage.py
If you'd rather not use ``manage.py``, no problem. Just make sure ``mysite`` 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 and ``polls`` are at the root level on the Python path (i.e., ``import mysite``
set the ``DJANGO_SETTINGS_MODULE`` environment variable to and ``import polls`` work) and set the ``DJANGO_SETTINGS_MODULE`` environment
``mysite.settings``. variable to ``mysite.settings``.
For more information on all of this, see the :doc:`django-admin.py For more information on all of this, see the :doc:`django-admin.py
documentation </ref/django-admin>`. documentation </ref/django-admin>`.
Once you're in the shell, explore the :doc:`database API </topics/db/queries>`:: 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. # No polls are in the system yet.
>>> Poll.objects.all() >>> 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 Save these changes and start a new Python interactive shell by running
``python manage.py shell`` again:: ``python manage.py shell`` again::
>>> from mysite.polls.models import Poll, Choice >>> from polls.models import Poll, Choice
# Make sure our __unicode__() addition worked. # Make sure our __unicode__() addition worked.
>>> Poll.objects.all() >>> Poll.objects.all()

View File

@ -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 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:: ``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 from django.contrib import admin
admin.site.register(Poll) admin.site.register(Poll)
@ -239,7 +239,7 @@ Yet.
There are two ways to solve this problem. The first is to register ``Choice`` 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:: 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) admin.site.register(Choice)

View File

@ -84,10 +84,10 @@ Time for an example. Edit ``mysite/urls.py`` so it looks like this::
admin.autodiscover() admin.autodiscover()
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^polls/$', 'mysite.polls.views.index'), (r'^polls/$', 'polls.views.index'),
(r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'), (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
(r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'), (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
(r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'), (r'^polls/(?P<poll_id>\d+)/vote/$', 'polls.views.vote'),
(r'^admin/', include(admin.site.urls)), (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`` the :setting:`ROOT_URLCONF` setting. It finds the variable named ``urlpatterns``
and traverses the regular expressions in order. When it finds a regular and traverses the regular expressions in order. When it finds a regular
expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the expression that matches -- ``r'^polls/(?P<poll_id>\d+)/$'`` -- it loads the
function ``detail()`` from ``mysite/polls/views.py``. Finally, function ``detail()`` from ``polls/views.py``. Finally, it calls that
it calls that ``detail()`` function like so:: ``detail()`` function like so::
detail(request=<HttpRequest object>, poll_id='23') 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 -- unless you have a sick sense of humor, in which case you can do something
like this:: 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. 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/ 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' object has no attribute 'index'
This error happened because you haven't written a function ``index()`` in the 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 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 messages tell you which view Django tried (and failed to find, because you
haven't written any views yet). 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:: and put the following Python code in it::
from django.http import HttpResponse 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 view, which displays the latest 5 poll questions in the system, separated by
commas, according to publication date:: commas, according to publication date::
from mysite.polls.models import Poll from polls.models import Poll
from django.http import HttpResponse from django.http import HttpResponse
def index(request): 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:: So let's use Django's template system to separate the design from Python::
from django.template import Context, loader from django.template import Context, loader
from mysite.polls.models import Poll from polls.models import Poll
from django.http import HttpResponse from django.http import HttpResponse
def index(request): def index(request):
@ -279,7 +279,7 @@ template. Django provides a shortcut. Here's the full ``index()`` view,
rewritten:: rewritten::
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from mysite.polls.models import Poll from polls.models import Poll
def index(request): def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')[:5] 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:: the URLconf, you may notice there's a fair bit of redundancy in it::
urlpatterns = patterns('', urlpatterns = patterns('',
(r'^polls/$', 'mysite.polls.views.index'), (r'^polls/$', 'polls.views.index'),
(r'^polls/(?P<poll_id>\d+)/$', 'mysite.polls.views.detail'), (r'^polls/(?P<poll_id>\d+)/$', 'polls.views.detail'),
(r'^polls/(?P<poll_id>\d+)/results/$', 'mysite.polls.views.results'), (r'^polls/(?P<poll_id>\d+)/results/$', 'polls.views.results'),
(r'^polls/(?P<poll_id>\d+)/vote/$', 'mysite.polls.views.vote'), (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 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 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:: 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/$', 'index'),
(r'^polls/(?P<poll_id>\d+)/$', 'detail'), (r'^polls/(?P<poll_id>\d+)/$', 'detail'),
(r'^polls/(?P<poll_id>\d+)/results/$', 'results'), (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 app is specific to the app, not to the Django installation -- so let's move the
URLs within the app directory. 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 ``mysite/urls.py`` to remove the poll-specific URLs and insert an
:func:`~django.conf.urls.defaults.include`:: :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('', 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/'`` * Django will find the match at ``'^polls/'``
* Then, Django will strip off the matching text (``"polls/"``) and send the * 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. 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 URLconf by removing the leading "polls/" from each line, and removing the
lines registering the admin site:: lines registering the admin site::
urlpatterns = patterns('mysite.polls.views', urlpatterns = patterns('polls.views',
(r'^$', 'index'), (r'^$', 'index'),
(r'^(?P<poll_id>\d+)/$', 'detail'), (r'^(?P<poll_id>\d+)/$', 'detail'),
(r'^(?P<poll_id>\d+)/results/$', 'results'), (r'^(?P<poll_id>\d+)/results/$', 'results'),

View File

@ -74,13 +74,13 @@ created a URLconf for the polls application that includes this line::
(r'^(?P<poll_id>\d+)/vote/$', 'vote'), (r'^(?P<poll_id>\d+)/vote/$', 'vote'),
We also created a dummy implementation of the ``vote()`` function. Let's 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.shortcuts import get_object_or_404, render_to_response
from django.http import HttpResponseRedirect, HttpResponse from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.template import RequestContext from django.template import RequestContext
from mysite.polls.models import Choice, Poll from polls.models import Choice, Poll
# ... # ...
def vote(request, poll_id): def vote(request, poll_id):
p = get_object_or_404(Poll, pk=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 # Always return an HttpResponseRedirect after successfully dealing
# with POST data. This prevents data from being posted twice if a # with POST data. This prevents data from being posted twice if a
# user hits the Back button. # 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: 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 * from django.conf.urls.defaults import *
urlpatterns = patterns('mysite.polls.views', urlpatterns = patterns('polls.views',
(r'^$', 'index'), (r'^$', 'index'),
(r'^(?P<poll_id>\d+)/$', 'detail'), (r'^(?P<poll_id>\d+)/$', 'detail'),
(r'^(?P<poll_id>\d+)/results/$', 'results'), (r'^(?P<poll_id>\d+)/results/$', 'results'),
@ -232,7 +232,7 @@ tutorial so far::
Change it like so:: Change it like so::
from django.conf.urls.defaults import * from django.conf.urls.defaults import *
from mysite.polls.models import Poll from polls.models import Poll
info_dict = { info_dict = {
'queryset': Poll.objects.all(), 'queryset': Poll.objects.all(),
@ -242,7 +242,7 @@ Change it like so::
(r'^$', 'django.views.generic.list_detail.object_list', info_dict), (r'^$', 'django.views.generic.list_detail.object_list', info_dict),
(r'^(?P<object_id>\d+)/$', 'django.views.generic.list_detail.object_detail', 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'), 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: We're using two generic views here: