Browse Source

Fixed #20910 -- Added a "snippet" sphinx directive to allow prefixing a filename.

Thanks Marc Tamlyn for the suggestion.
M Nasimul Haque 11 years ago
parent
commit
d07d6ae116

+ 1 - 0
AUTHORS

@@ -282,6 +282,7 @@ answer newbie questions, and generally made Django that much better:
     Scot Hacker <shacker@birdhouse.org>
     dAniel hAhler
     hambaloney
+    Nasimul Haque <nasim.haque@gmail.com>
     Will Hardy <django@willhardy.com.au>
     Brian Harring <ferringb@gmail.com>
     Brant Harris

+ 134 - 0
docs/_ext/djangodocs.py

@@ -5,11 +5,15 @@ import json
 import os
 import re
 
+from docutils import nodes
+from docutils.parsers.rst import directives
+
 from sphinx import addnodes, __version__ as sphinx_ver
 from sphinx.builders.html import StandaloneHTMLBuilder
 from sphinx.writers.html import SmartyPantsHTMLTranslator
 from sphinx.util.console import bold
 from sphinx.util.compat import Directive
+from sphinx.util.nodes import set_source_info
 
 # RE for option descriptions without a '--' prefix
 simple_option_desc_re = re.compile(
@@ -53,6 +57,136 @@ def setup(app):
     app.add_directive('versionchanged', VersionDirective)
     app.add_builder(DjangoStandaloneHTMLBuilder)
 
+    # register the snippet directive
+    app.add_directive('snippet', SnippetWithFilename)
+    # register a node for snippet directive so that the xml parser
+    # knows how to handle the enter/exit parsing event
+    app.add_node(snippet_with_filename,
+                 html=(visit_snippet, depart_snippet_literal),
+                 latex=(visit_snippet_latex, depart_snippet_latex),
+                 man=(visit_snippet_literal, depart_snippet_literal),
+                 text=(visit_snippet_literal, depart_snippet_literal),
+                 texinfo=(visit_snippet_literal, depart_snippet_literal))
+
+
+class snippet_with_filename(nodes.literal_block):
+    """
+    Subclass the literal_block to override the visit/depart event handlers
+    """
+    pass
+
+
+def visit_snippet_literal(self, node):
+    """
+    default literal block handler
+    """
+    self.visit_literal_block(node)
+
+
+def depart_snippet_literal(self, node):
+    """
+    default literal block handler
+    """
+    self.depart_literal_block(node)
+
+
+def visit_snippet(self, node):
+    """
+    HTML document generator visit handler
+    """
+    lang = self.highlightlang
+    linenos = node.rawsource.count('\n') >= self.highlightlinenothreshold - 1
+    fname = node['filename']
+    highlight_args = node.get('highlight_args', {})
+    if node.has_key('language'):
+        # code-block directives
+        lang = node['language']
+        highlight_args['force'] = True
+    if node.has_key('linenos'):
+        linenos = node['linenos']
+
+    def warner(msg):
+        self.builder.warn(msg, (self.builder.current_docname, node.line))
+
+    highlighted = self.highlighter.highlight_block(node.rawsource, lang,
+                                                   warn=warner,
+                                                   linenos=linenos,
+                                                   **highlight_args)
+    starttag = self.starttag(node, 'div', suffix='',
+                             CLASS='highlight-%s' % lang)
+    self.body.append(starttag)
+    self.body.append('<div class="snippet-filename">%s</div>\n''' % (fname,))
+    self.body.append(highlighted)
+    self.body.append('</div>\n')
+    raise nodes.SkipNode
+
+
+def visit_snippet_latex(self, node):
+    """
+    Latex document generator visit handler
+    """
+    self.verbatim = ''
+
+
+def depart_snippet_latex(self, node):
+    """
+    Latex document generator depart handler.
+    """
+    code = self.verbatim.rstrip('\n')
+    lang = self.hlsettingstack[-1][0]
+    linenos = code.count('\n') >= self.hlsettingstack[-1][1] - 1
+    fname = node['filename']
+    highlight_args = node.get('highlight_args', {})
+    if 'language' in node:
+        # code-block directives
+        lang = node['language']
+        highlight_args['force'] = True
+    if 'linenos' in node:
+        linenos = node['linenos']
+
+    def warner(msg):
+        self.builder.warn(msg, (self.curfilestack[-1], node.line))
+
+    hlcode = self.highlighter.highlight_block(code, lang, warn=warner,
+                                              linenos=linenos,
+                                              **highlight_args)
+
+    self.body.append('\n{\\colorbox[rgb]{0.9,0.9,0.9}'
+                     '{\\makebox[\\textwidth][l]'
+                     '{\\small\\texttt{%s}}}}\n' % (fname,))
+
+    if self.table:
+        hlcode = hlcode.replace('\\begin{Verbatim}',
+                                '\\begin{OriginalVerbatim}')
+        self.table.has_problematic = True
+        self.table.has_verbatim = True
+
+    hlcode = hlcode.rstrip()[:-14]  # strip \end{Verbatim}
+    hlcode = hlcode.rstrip() + '\n'
+    self.body.append('\n' + hlcode + '\\end{%sVerbatim}\n' %
+                     (self.table and 'Original' or ''))
+    self.verbatim = None
+
+
+class SnippetWithFilename(Directive):
+    """
+    The 'snippet' directive that allows to add the filename (optional)
+    of a code snippet in the document. This is modeled after CodeBlock.
+    """
+    has_content = True
+    optional_arguments = 1
+    option_spec = {'filename': directives.unchanged_required}
+
+    def run(self):
+        code = u'\n'.join(self.content)
+
+        literal = snippet_with_filename(code, code)
+        if self.arguments:
+            literal['language'] = self.arguments[0]
+        literal['filename'] = self.options['filename']
+        set_source_info(self, literal)
+        return [literal]
+
 
 class VersionDirective(Directive):
     has_content = True

+ 3 - 0
docs/_theme/djangodocs/static/djangodocs.css

@@ -100,6 +100,9 @@ pre { font-size:small; background:#E0FFB8; border:1px solid #94da3a; border-widt
 dt .literal, table .literal { background:none; }
 #bd a.reference { text-decoration: none; }
 #bd a.reference tt.literal { border-bottom: 1px #234f32 dotted; }
+div.snippet-filename { color: white; background-color: #234F32; margin: 0; padding: 2px 5px; width: 100%; font-family: monospace; font-size: small; line-height: 1.3em; }
+div.snippet-filename + div.highlight > pre { margin-top: 0; }
+div.snippet-filename + pre { margin-top: 0; }
 
 /* Restore colors of pygments hyperlinked code */
 #bd .highlight .k a:link, #bd .highlight .k a:visited { color: #000000; text-decoration: none; border-bottom: 1px dotted #000000; }

+ 90 - 80
docs/intro/reusable-apps.txt

@@ -120,112 +120,122 @@ this. For a small app like polls, this process isn't too difficult.
 1. First, create a parent directory for ``polls``, outside of your Django
    project. Call this directory ``django-polls``.
 
-.. admonition::  Choosing a name for your app
+   .. admonition::  Choosing a name for your app
 
-   When choosing a name for your package, check resources like PyPI to avoid
-   naming conflicts with existing packages. It's often useful to prepend
-   ``django-`` to your module name when creating a package to distribute.
-   This helps others looking for Django apps identify your app as Django
-   specific.
+       When choosing a name for your package, check resources like PyPI to avoid
+       naming conflicts with existing packages. It's often useful to prepend
+       ``django-`` to your module name when creating a package to distribute.
+       This helps others looking for Django apps identify your app as Django
+       specific.
 
 2. Move the ``polls`` directory into the ``django-polls`` directory.
 
-3. Create a file ``django-polls/README.rst`` with the following contents::
+3. Create a file ``django-polls/README.rst`` with the following contents:
 
-    =====
-    Polls
-    =====
+   .. snippet::
+       :filename: django-polls/README.rst
 
-    Polls is a simple Django app to conduct Web-based polls. For each
-    question, visitors can choose between a fixed number of answers.
+       =====
+       Polls
+       =====
 
-    Detailed documentation is in the "docs" directory.
+       Polls is a simple Django app to conduct Web-based polls. For each
+       question, visitors can choose between a fixed number of answers.
 
-    Quick start
-    -----------
+       Detailed documentation is in the "docs" directory.
 
-    1. Add "polls" to your INSTALLED_APPS setting like this::
+       Quick start
+       -----------
 
-          INSTALLED_APPS = (
-              ...
-              'polls',
-          )
+       1. Add "polls" to your INSTALLED_APPS setting like this::
 
-    2. Include the polls URLconf in your project urls.py like this::
+           INSTALLED_APPS = (
+               ...
+               'polls',
+           )
 
-          url(r'^polls/', include('polls.urls')),
+       2. Include the polls URLconf in your project urls.py like this::
 
-    3. Run `python manage.py migrate` to create the polls models.
+           url(r'^polls/', include('polls.urls')),
 
-    4. Start the development server and visit http://127.0.0.1:8000/admin/
-       to create a poll (you'll need the Admin app enabled).
+       3. Run `python manage.py migrate` to create the polls models.
 
-    5. Visit http://127.0.0.1:8000/polls/ to participate in the poll.
+       4. Start the development server and visit http://127.0.0.1:8000/admin/
+          to create a poll (you'll need the Admin app enabled).
+
+       5. Visit http://127.0.0.1:8000/polls/ to participate in the poll.
 
 4. Create a ``django-polls/LICENSE`` file. Choosing a license is beyond the
-scope of this tutorial, but suffice it to say that code released publicly
-without a license is *useless*. Django and many Django-compatible apps are
-distributed under the BSD license; however, you're free to pick your own
-license. Just be aware that your licensing choice will affect who is able
-to use your code.
+   scope of this tutorial, but suffice it to say that code released publicly
+   without a license is *useless*. Django and many Django-compatible apps are
+   distributed under the BSD license; however, you're free to pick your own
+   license. Just be aware that your licensing choice will affect who is able
+   to use your code.
 
 5. Next we'll create a ``setup.py`` file which provides details about how to
-build and install the app.  A full explanation of this file is beyond the
-scope of this tutorial, but the `distribute docs
-<http://packages.python.org/distribute/setuptools.html>`_ have a good explanation.
-Create a file ``django-polls/setup.py`` with the following contents::
-
-    import os
-    from setuptools import setup
-
-    README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read()
-
-    # allow setup.py to be run from any path
-    os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
-
-    setup(
-        name='django-polls',
-        version='0.1',
-        packages=['polls'],
-        include_package_data=True,
-        license='BSD License',  # example license
-        description='A simple Django app to conduct Web-based polls.',
-        long_description=README,
-        url='http://www.example.com/',
-        author='Your Name',
-        author_email='yourname@example.com',
-        classifiers=[
-            'Environment :: Web Environment',
-            'Framework :: Django',
-            'Intended Audience :: Developers',
-            'License :: OSI Approved :: BSD License', # example license
-            'Operating System :: OS Independent',
-            'Programming Language :: Python',
-            # replace these appropriately if you are using Python 3
-            'Programming Language :: Python :: 2',
-            'Programming Language :: Python :: 2.7',
-            'Topic :: Internet :: WWW/HTTP',
-            'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
-        ],
-    )
-
-.. admonition:: I thought you said we were going to use ``distribute``?
-
-    Distribute is a drop-in replacement for ``setuptools``. Even though we
-    appear to import from ``setuptools``, since we have ``distribute``
-    installed, it will override the import.
+   build and install the app.  A full explanation of this file is beyond the
+   scope of this tutorial, but the `distribute docs
+   <http://packages.python.org/distribute/setuptools.html>`_ have a good
+   explanation. Create a file ``django-polls/setup.py`` with the following
+   contents:
+
+   .. snippet::
+       :filename: django-polls/setup.py
+
+       import os
+       from setuptools import setup
+
+       README = open(os.path.join(os.path.dirname(__file__), 'README.rst')).read()
+
+       # allow setup.py to be run from any path
+       os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir)))
+
+       setup(
+           name='django-polls',
+           version='0.1',
+           packages=['polls'],
+           include_package_data=True,
+           license='BSD License',  # example license
+           description='A simple Django app to conduct Web-based polls.',
+           long_description=README,
+           url='http://www.example.com/',
+           author='Your Name',
+           author_email='yourname@example.com',
+           classifiers=[
+               'Environment :: Web Environment',
+               'Framework :: Django',
+               'Intended Audience :: Developers',
+               'License :: OSI Approved :: BSD License', # example license
+               'Operating System :: OS Independent',
+               'Programming Language :: Python',
+               # replace these appropriately if you are using Python 3
+               'Programming Language :: Python :: 2',
+               'Programming Language :: Python :: 2.7',
+               'Topic :: Internet :: WWW/HTTP',
+               'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
+           ],
+       )
+
+   .. admonition:: I thought you said we were going to use ``distribute``?
+
+       Distribute is a drop-in replacement for ``setuptools``. Even though we
+       appear to import from ``setuptools``, since we have ``distribute``
+       installed, it will override the import.
 
 6. Only Python modules and packages are included in the package by default. To
    include additional files, we'll need to create a ``MANIFEST.in`` file. The
    distribute docs referred to in the previous step discuss this file in more
    details. To include the templates, the ``README.rst`` and our ``LICENSE``
    file, create a file ``django-polls/MANIFEST.in`` with the following
-   contents::
+   contents:
+
+   .. snippet::
+       :filename: django-polls/MANIFEST.in
 
-    include LICENSE
-    include README.rst
-    recursive-include polls/static *
-    recursive-include polls/templates *
+       include LICENSE
+       include README.rst
+       recursive-include polls/static *
+       recursive-include polls/templates *
 
 7. It's optional, but recommended, to include detailed documentation with your
    app. Create an empty directory ``django-polls/docs`` for future

+ 16 - 4
docs/intro/tutorial01.txt

@@ -344,7 +344,10 @@ the text of the choice and a vote tally. Each ``Choice`` is associated with a
 ``Question``.
 
 These concepts are represented by simple Python classes. Edit the
-:file:`polls/models.py` file so it looks like this::
+:file:`polls/models.py` file so it looks like this:
+
+.. snippet::
+    :filename: polls/models.py
 
     from django.db import models
 
@@ -415,7 +418,10 @@ But first we need to tell our project that the ``polls`` app is installed.
 
 Edit the :file:`mysite/settings.py` file again, and change the
 :setting:`INSTALLED_APPS` setting to include the string ``'polls'``. So it'll
-look like this::
+look like this:
+
+.. snippet::
+    :filename: mysite/settings.py
 
     INSTALLED_APPS = (
         'django.contrib.admin',
@@ -589,7 +595,10 @@ of this object. Let's fix that by editing the ``Question`` model (in the
 ``polls/models.py`` file) and adding a
 :meth:`~django.db.models.Model.__unicode__` method to both ``Question`` and
 ``Choice``. On Python 3, simply replace ``__unicode__`` by ``__str__`` in the
-following example::
+following example:
+
+.. snippet::
+    :filename: polls/models.py
 
     from django.db import models
 
@@ -633,7 +642,10 @@ admin.
     luck, things should Just Work for you.
 
 Note these are normal Python methods. Let's add a custom method, just for
-demonstration::
+demonstration:
+
+.. snippet::
+    :filename: polls/models.py
 
     import datetime
     from django.utils import timezone

+ 44 - 11
docs/intro/tutorial02.txt

@@ -79,7 +79,10 @@ But where's our poll app? It's not displayed on the admin index page.
 
 Just one thing to do: we need to tell the admin that ``Question``
 objects have an admin interface. To do this, open the :file:`polls/admin.py`
-file, and edit it to look like this::
+file, and edit it to look like this:
+
+.. snippet::
+    :filename: polls/admin.py
 
     from django.contrib import admin
     from polls.models import Question
@@ -156,7 +159,10 @@ to customize how the admin form looks and works. You'll do this by telling
 Django the options you want when you register the object.
 
 Let's see how this works by re-ordering the fields on the edit form. Replace
-the ``admin.site.register(Question)`` line with::
+the ``admin.site.register(Question)`` line with:
+
+.. snippet::
+    :filename: polls/admin.py
 
     from django.contrib import admin
     from polls.models import Question
@@ -181,7 +187,10 @@ This isn't impressive with only two fields, but for admin forms with dozens
 of fields, choosing an intuitive order is an important usability detail.
 
 And speaking of forms with dozens of fields, you might want to split the form
-up into fieldsets::
+up into fieldsets:
+
+.. snippet::
+    :filename: polls/admin.py
 
     from django.contrib import admin
     from polls.models import Question
@@ -204,7 +213,10 @@ Here's what our form looks like now:
 You can assign arbitrary HTML classes to each fieldset. Django provides a
 ``"collapse"`` class that displays a particular fieldset initially collapsed.
 This is useful when you have a long form that contains a number of fields that
-aren't commonly used::
+aren't commonly used:
+
+.. snippet::
+    :filename: polls/admin.py
 
         from django.contrib import admin
         from polls.models import Question
@@ -228,7 +240,10 @@ the admin page doesn't display choices.
 Yet.
 
 There are two ways to solve this problem. The first is to register ``Choice``
-with the admin just as we did with ``Question``. That's easy::
+with the admin just as we did with ``Question``. That's easy:
+
+.. snippet::
+    :filename: polls/admin.py
 
     from django.contrib import admin
     from polls.models import Choice
@@ -258,7 +273,10 @@ It'd be better if you could add a bunch of Choices directly when you create the
 ``Question`` object. Let's make that happen.
 
 Remove the ``register()`` call for the ``Choice`` model. Then, edit the ``Question``
-registration code to read::
+registration code to read:
+
+.. snippet::
+    :filename: polls/admin.py
 
     from django.contrib import admin
     from polls.models import Choice, Question
@@ -302,7 +320,10 @@ that you can't remove the original three slots. This image shows an added slot:
 One small problem, though. It takes a lot of screen space to display all the
 fields for entering related ``Choice`` objects. For that reason, Django offers a
 tabular way of displaying inline related objects; you just need to change
-the ``ChoiceInline`` declaration to read::
+the ``ChoiceInline`` declaration to read:
+
+.. snippet::
+    :filename: polls/admin.py
 
     class ChoiceInline(admin.TabularInline):
         #...
@@ -330,14 +351,20 @@ Here's what it looks like at this point:
 By default, Django displays the ``str()`` of each object. But sometimes it'd be
 more helpful if we could display individual fields. To do that, use the
 ``list_display`` admin option, which is a tuple of field names to display, as
-columns, on the change list page for the object::
+columns, on the change list page for the object:
+
+.. snippet::
+    :filename: polls/admin.py
 
     class QuestionAdmin(admin.ModelAdmin):
         # ...
         list_display = ('question_text', 'pub_date')
 
 Just for good measure, let's also include the ``was_published_recently`` custom
-method from Tutorial 1::
+method from Tutorial 1:
+
+.. snippet::
+    :filename: polls/admin.py
 
     class QuestionAdmin(admin.ModelAdmin):
         # ...
@@ -356,7 +383,10 @@ underscores replaced with spaces), and that each line contains the string
 representation of the output.
 
 You can improve that by giving that method (in :file:`polls/models.py`) a few
-attributes, as follows::
+attributes, as follows:
+
+.. snippet::
+    :filename: polls/admin.py
 
     class Question(models.Model):
         # ...
@@ -417,7 +447,10 @@ whatever user your server runs.) However, keeping your templates within the
 project is a good convention to follow.
 
 Open your settings file (:file:`mysite/settings.py`, remember) and add a
-:setting:`TEMPLATE_DIRS` setting::
+:setting:`TEMPLATE_DIRS` setting:
+
+.. snippet::
+    :filename: mysite/settings.py
 
     TEMPLATE_DIRS = [os.path.join(BASE_DIR, 'templates')]
 

+ 52 - 15
docs/intro/tutorial03.txt

@@ -84,7 +84,10 @@ Your app directory should now look like::
         urls.py
         views.py
 
-In the ``polls/urls.py`` file include the following code::
+In the ``polls/urls.py`` file include the following code:
+
+.. snippet::
+    :filename: polls/urls.py
 
     from django.conf.urls import patterns, url
 
@@ -96,7 +99,10 @@ In the ``polls/urls.py`` file include the following code::
 
 The next step is to point the root URLconf at the ``polls.urls`` module. In
 ``mysite/urls.py`` insert an :func:`~django.conf.urls.include`, leaving you
-with::
+with:
+
+.. snippet::
+    :filename: mysite/urls.py
 
     from django.conf.urls import patterns, include, url
 
@@ -172,7 +178,10 @@ Writing more views
 ==================
 
 Now let's add a few more views to ``polls/views.py``. These views are
-slightly different, because they take an argument::
+slightly different, because they take an argument:
+
+.. snippet::
+    :filename: polls/views.py
 
     def detail(request, question_id):
         return HttpResponse("You're looking at question %s." % question_id)
@@ -185,7 +194,10 @@ slightly different, because they take an argument::
         return HttpResponse("You're voting on question %s." % question_id)
 
 Wire these new views into the ``polls.urls`` module by adding the following
-:func:`~django.conf.urls.url` calls::
+:func:`~django.conf.urls.url` calls:
+
+.. snippet::
+    :filename: polls/urls.py
 
     from django.conf.urls import patterns, url
 
@@ -269,7 +281,10 @@ All Django wants is that :class:`~django.http.HttpResponse`. Or an exception.
 Because it's convenient, let's use Django's own database API, which we covered
 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::
+commas, according to publication date:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.http import HttpResponse
 
@@ -327,7 +342,8 @@ Django simply as ``polls/index.html``.
 
 Put the following code in that template:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/index.html
 
     {% if latest_question_list %}
         <ul>
@@ -339,7 +355,10 @@ Put the following code in that template:
         <p>No polls are available.</p>
     {% endif %}
 
-Now let's update our ``index`` view in ``polls/views.py`` to use the template::
+Now let's update our ``index`` view in ``polls/views.py`` to use the template:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.http import HttpResponse
     from django.template import RequestContext, loader
@@ -369,7 +388,10 @@ A shortcut: :func:`~django.shortcuts.render`
 It's a very common idiom to load a template, fill a context and return an
 :class:`~django.http.HttpResponse` object with the result of the rendered
 template. Django provides a shortcut. Here's the full ``index()`` view,
-rewritten::
+rewritten:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.shortcuts import render
 
@@ -395,7 +417,10 @@ Raising a 404 error
 ===================
 
 Now, let's tackle the question detail view -- the page that displays the question text
-for a given poll. Here's the view::
+for a given poll. Here's the view:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.http import Http404
     from django.shortcuts import render
@@ -414,7 +439,10 @@ if a question with the requested ID doesn't exist.
 
 We'll discuss what you could put in that ``polls/detail.html`` template a bit
 later, but if you'd like to quickly get the above example working, a file
-containing just::
+containing just:
+
+.. snippet:: html+django
+    :filename: polls/templates/polls/detail.html
 
     {{ question }}
 
@@ -425,7 +453,10 @@ A shortcut: :func:`~django.shortcuts.get_object_or_404`
 
 It's a very common idiom to use :meth:`~django.db.models.query.QuerySet.get`
 and raise :exc:`~django.http.Http404` if the object doesn't exist. Django
-provides a shortcut. Here's the ``detail()`` view, rewritten::
+provides a shortcut. Here's the ``detail()`` view, rewritten:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.shortcuts import render, get_object_or_404
 
@@ -466,7 +497,8 @@ Back to the ``detail()`` view for our poll application. Given the context
 variable ``question``, here's what the ``polls/detail.html`` template might look
 like:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/detail.html
 
     <h1>{{ question.question_text }}</h1>
     <ul>
@@ -549,7 +581,10 @@ make it so that Django knows which app view to create for a url when using the
 
 The answer is to add namespaces to your root URLconf. In the ``mysite/urls.py``
 file (the project's ``urls.py``, not the application's), go ahead and change
-it to include namespacing::
+it to include namespacing:
+
+.. snippet::
+    :filename: mysite/urls.py
 
     from django.conf.urls import patterns, include, url
 
@@ -563,13 +598,15 @@ it to include namespacing::
 
 Now change your ``polls/index.html`` template from:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/index.html
 
     <li><a href="{% url 'detail' question.id %}">{{ question.question_text }}</a></li>
 
 to point at the namespaced detail view:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/index.html
 
     <li><a href="{% url 'polls:detail' question.id %}">{{ question.question_text }}</a></li>
 

+ 24 - 7
docs/intro/tutorial04.txt

@@ -12,7 +12,8 @@ Write a simple form
 Let's update our poll detail template ("polls/detail.html") from the last
 tutorial, so that the template contains an HTML ``<form>`` element:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/detail.html
 
     <h1>{{ question.question_text }}</h1>
 
@@ -54,12 +55,18 @@ A quick rundown:
 
 Now, let's create a Django view that handles the submitted data and does
 something with it. Remember, in :doc:`Tutorial 3 </intro/tutorial03>`, we
-created a URLconf for the polls application that includes this line::
+created a URLconf for the polls application that includes this line:
+
+.. snippet::
+    :filename: polls/urls.py
 
     url(r'^(?P<question_id>\d+)/vote/$', views.vote, name='vote'),
 
 We also created a dummy implementation of the ``vote()`` function. Let's
-create a real version. Add the following to ``polls/views.py``::
+create a real version. Add the following to ``polls/views.py``:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.shortcuts import get_object_or_404, render
     from django.http import HttpResponseRedirect, HttpResponse
@@ -134,7 +141,10 @@ object. For more on :class:`~django.http.HttpRequest` objects, see the
 :doc:`request and response documentation </ref/request-response>`.
 
 After somebody votes in a question, the ``vote()`` view redirects to the results
-page for the question. Let's write that view::
+page for the question. Let's write that view:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.shortcuts import get_object_or_404, render
 
@@ -149,7 +159,8 @@ redundancy later.
 
 Now, create a ``polls/results.html`` template:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/results.html
 
     <h1>{{ question.question_text }}</h1>
 
@@ -205,7 +216,10 @@ Read on for details.
 Amend URLconf
 -------------
 
-First, open the ``polls/urls.py`` URLconf and change it like so::
+First, open the ``polls/urls.py`` URLconf and change it like so:
+
+.. snippet::
+    :filename: polls/urls.py
 
     from django.conf.urls import patterns, url
 
@@ -223,7 +237,10 @@ Amend views
 
 Next, we're going to remove our old ``index``, ``detail``, and ``results``
 views and use Django's generic views instead. To do so, open the
-``polls/views.py`` file and change it like so::
+``polls/views.py`` file and change it like so:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.shortcuts import get_object_or_404, render
     from django.http import HttpResponseRedirect

+ 39 - 10
docs/intro/tutorial05.txt

@@ -160,7 +160,10 @@ A conventional place for an application's tests is in the application's
 ``tests.py`` file; the testing system will automatically find tests in any file
 whose name begins with ``test``.
 
-Put the following in the ``tests.py`` file in the ``polls`` application::
+Put the following in the ``tests.py`` file in the ``polls`` application:
+
+.. snippet::
+    :filename: polls/tests.py
 
     import datetime
 
@@ -236,7 +239,10 @@ Fixing the bug
 We already know what the problem is: ``Question.was_published_recently()`` should
 return ``False`` if its ``pub_date`` is in the future. Amend the method in
 ``models.py``, so that it will only return ``True`` if the date is also in the
-past::
+past:
+
+.. snippet::
+    :filename: polls/models.py
 
     def was_published_recently(self):
         now = timezone.now()
@@ -268,7 +274,10 @@ method; in fact, it would be positively embarrassing if in fixing one bug we had
 introduced another.
 
 Add two more test methods to the same class, to test the behavior of the method
-more comprehensively::
+more comprehensively:
+
+.. snippet::
+    :filename: polls/tests.py
 
     def test_was_published_recently_with_old_question(self):
         """
@@ -382,7 +391,10 @@ The list of polls shows polls that aren't published yet (i.e. those that have a
 ``pub_date`` in the future). Let's fix that.
 
 In :doc:`Tutorial 4 </intro/tutorial04>` we introduced a class-based view,
-based on :class:`~django.views.generic.list.ListView`::
+based on :class:`~django.views.generic.list.ListView`:
+
+.. snippet::
+    :filename: polls/views.py
 
     class IndexView(generic.ListView):
         template_name = 'polls/index.html'
@@ -397,11 +409,17 @@ places into the context.
 
 We need to amend the ``get_queryset`` method and change it so that it also
 checks the date by comparing it with ``timezone.now()``. First we need to add
-an import::
+an import:
+
+.. snippet::
+    :filename: polls/views.py
 
     from django.utils import timezone
 
-and then we must amend the ``get_queryset`` method like so::
+and then we must amend the ``get_queryset`` method like so:
+
+.. snippet::
+    :filename: polls/views.py
 
     def get_queryset(self):
         """
@@ -426,12 +444,18 @@ are listed.  You don't want to have to do that *every single time you make any
 change that might affect this* - so let's also create a test, based on our
 :djadmin:`shell` session above.
 
-Add the following to ``polls/tests.py``::
+Add the following to ``polls/tests.py``:
+
+.. snippet::
+    :filename: polls/tests.py
 
     from django.core.urlresolvers import reverse
 
 and we'll create a factory method to create questions as well as a new test
-class::
+class:
+
+.. snippet::
+    :filename: polls/tests.py
 
     def create_question(question_text, days):
         """
@@ -532,8 +556,10 @@ Testing the ``DetailView``
 
 What we have works well; however, even though future questions don't appear in
 the *index*, users can still reach them if they know or guess the right URL. So
-we need to add a similar  constraint to ``DetailView``::
+we need to add a similar  constraint to ``DetailView``:
 
+.. snippet::
+    :filename: polls/views.py
 
     class DetailView(generic.DetailView):
         ...
@@ -545,7 +571,10 @@ we need to add a similar  constraint to ``DetailView``::
 
 And of course, we will add some tests, to check that a ``Question`` whose
 ``pub_date`` is in the past can be displayed, and that one with a ``pub_date``
-in the future is not::
+in the future is not:
+
+.. snippet::
+    :filename: polls/tests.py
 
     class QuestionIndexDetailTests(TestCase):
         def test_detail_view_with_a_future_question(self):

+ 6 - 3
docs/intro/tutorial06.txt

@@ -56,7 +56,8 @@ reference the path for templates.
 
 Put the following code in that stylesheet (``polls/static/polls/style.css``):
 
-.. code-block:: css
+.. snippet:: css
+    :filename: polls/static/polls/style.css
 
     li a {
         color: green;
@@ -64,7 +65,8 @@ Put the following code in that stylesheet (``polls/static/polls/style.css``):
 
 Next, add the following at the top of ``polls/templates/polls/index.html``:
 
-.. code-block:: html+django
+.. snippet:: html+django
+    :filename: polls/templates/polls/index.html
 
     {% load staticfiles %}
 
@@ -88,7 +90,8 @@ called ``background.gif``. In other words, put your image in
 
 Then, add to your stylesheet (``polls/static/polls/style.css``):
 
-.. code-block:: css
+.. snippet:: css
+    :filename: polls/static/polls/style.css
 
     body {
         background: white url("images/background.gif") no-repeat right bottom;