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:
parent
307e71a734
commit
d81faf356c
|
@ -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()
|
||||||
|
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue