From 5c7406b236b641ac1802d1471f04b27166909121 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Tue, 30 Oct 2012 15:53:56 -0400 Subject: [PATCH] [1.5.X] Fixed #16671 - Added a tutorial on reuseable apps Thank-you Katie Miller and Ben Sturmfels for the initial draft, as well as Russ and Carl for the reviews. Backport of 08cf54990a from master --- AUTHORS | 2 + docs/index.txt | 3 + docs/intro/index.txt | 13 +- docs/intro/reusable-apps.txt | 363 +++++++++++++++++++++++++++++++++++ docs/intro/tutorial03.txt | 6 + docs/intro/tutorial04.txt | 9 +- 6 files changed, 388 insertions(+), 8 deletions(-) create mode 100644 docs/intro/reusable-apps.txt diff --git a/AUTHORS b/AUTHORS index 5799b941ff0f3..6f9b410cca1d8 100644 --- a/AUTHORS +++ b/AUTHORS @@ -380,6 +380,7 @@ answer newbie questions, and generally made Django that much better: Christian Metts michal@plovarna.cz Slawek Mikula + Katie Miller Shawn Milochik mitakummaa@gmail.com Taylor Mitchell @@ -510,6 +511,7 @@ answer newbie questions, and generally made Django that much better: Johan C. Stöver Nowell Strite Thomas Stromberg + Ben Sturmfels Travis Swicegood Pascal Varet SuperJared diff --git a/docs/index.txt b/docs/index.txt index 5055edf7e7b9b..a6d9ed2b13e69 100644 --- a/docs/index.txt +++ b/docs/index.txt @@ -46,6 +46,9 @@ Are you new to Django or to programming? This is the place to start! :doc:`Part 3 ` | :doc:`Part 4 ` +* **Advanced Tutorials:** + :doc:`How to write reusable apps ` + The model layer =============== diff --git a/docs/intro/index.txt b/docs/intro/index.txt index 19290a53c61a1..afb1825b87820 100644 --- a/docs/intro/index.txt +++ b/docs/intro/index.txt @@ -6,31 +6,32 @@ place: read this material to quickly get up and running. .. toctree:: :maxdepth: 1 - + overview install tutorial01 tutorial02 tutorial03 tutorial04 + reusable-apps whatsnext - + .. seealso:: If you're new to Python_, you might want to start by getting an idea of what the language is like. Django is 100% Python, so if you've got minimal comfort with Python you'll probably get a lot more out of Django. - + If you're new to programming entirely, you might want to start with this `list of Python resources for non-programmers`_ - + If you already know a few other languages and want to get up to speed with Python quickly, we recommend `Dive Into Python`_ (also available in a `dead-tree version`_). If that's not quite your style, there are quite a few other `books about Python`_. - + .. _python: http://python.org/ .. _list of Python resources for non-programmers: http://wiki.python.org/moin/BeginnersGuide/NonProgrammers .. _dive into python: http://diveintopython.net/ .. _dead-tree version: http://www.amazon.com/exec/obidos/ASIN/1590593561/ref=nosim/jacobian20 - .. _books about Python: http://wiki.python.org/moin/PythonBooks \ No newline at end of file + .. _books about Python: http://wiki.python.org/moin/PythonBooks diff --git a/docs/intro/reusable-apps.txt b/docs/intro/reusable-apps.txt new file mode 100644 index 0000000000000..200051593c533 --- /dev/null +++ b/docs/intro/reusable-apps.txt @@ -0,0 +1,363 @@ +============================================= +Advanced tutorial: How to write reusable apps +============================================= + +This advanced tutorial begins where :doc:`Tutorial 4 ` left +off. We'll be turning our Web-poll into a standalone Python package you can +reuse in new projects and share with other people. + +If you haven't recently completed Tutorials 1–4, we encourage you to review +these so that your example project matches the one described below. + +Reusability matters +=================== + +It's a lot of work to design, build, test and maintain a web application. Many +Python and Django projects share common problems. Wouldn't it be great if we +could save some of this repeated work? + +Reusability is the way of life in Python. `The Python Package Index (PyPI) +`_ has a vast +range of packages you can use in your own Python programs. Check out `Django +Packages `_ for existing reusable apps you could +incorporate in your project. Django itself is also just a Python package. This +means that you can take existing Python packages or Django apps and compose +them into your own web project. You only need to write the parts that make +your project unique. + +Let's say you were starting a new project that needed a polls app like the one +we've been working on. How do you make this app reusable? Luckily, you're well +on the way already. In :doc:`Tutorial 3 `, we saw how we +could decouple polls from the project-level URLconf using an ``include``. +In this tutorial, we'll take further steps to make the app easy to use in new +projects and ready to publish for others to install and use. + +.. admonition:: Package? App? + + A Python `package `_ + provides a way of grouping related Python code for easy reuse. A package + contains one or more files of Python code (also known as "modules"). + + A package can be imported with ``import foo.bar`` or ``from foo import + bar``. For a directory (like ``polls``) to form a package, it must contain + a special file ``__init__.py``, even if this file is empty. + + A Django *app* is just a Python package that is specifically intended for + use in a Django project. An app may also use common Django conventions, + such as having a ``models.py`` file. + + Later on we use the term *packaging* to describe the process of making a + Python package easy for others to install. It can be a little confusing, we + know. + +Completing your reusable app +============================ + +After the previous tutorials, our project should look like this:: + + mysite/ + manage.py + mysite/ + __init__.py + settings.py + urls.py + wsgi.py + polls/ + admin.py + __init__.py + models.py + tests.py + urls.py + views.py + +You also have a directory somewhere called ``mytemplates`` which you created in +:doc:`Tutorial 2 `. You specified its location in the +TEMPLATE_DIRS setting. This directory should look like this:: + + mytemplates/ + admin/ + base_site.html + polls/ + detail.html + index.html + results.html + +The polls app is already a Python package, thanks to the ``polls/__init__.py`` +file. That's a great start, but we can't just pick up this package and drop it +into a new project. The polls templates are currently stored in the +project-wide ``mytemplates`` directory. To make the app self-contained, it +should also contain the necessary templates. + +Inside the ``polls`` app, create a new ``templates`` directory. Now move the +``polls`` template directory from ``mytemplates`` into the new +``templates``. Your project should now look like this:: + + mysite/ + manage.py + mysite/ + __init__.py + settings.py + urls.py + wsgi.py + polls/ + admin.py + __init__.py + models.py + templates/ + polls/ + detail.html + index.html + results.html + tests.py + urls.py + views.py + +Your project-wide templates directory should now look like this:: + + mytemplates/ + admin/ + base_site.html + +Looking good! Now would be a good time to confirm that your polls application +still works correctly. How does Django know how to find the new location of +the polls templates even though we didn't modify :setting:`TEMPLATE_DIRS`? +Django has a :setting:`TEMPLATE_LOADERS` setting which contains a list +of callables that know how to import templates from various sources. One of +the defaults is :class:`django.template.loaders.app_directories.Loader` which +looks for a "templates" subdirectory in each of the :setting:`INSTALLED_APPS`. + +The ``polls`` directory could now be copied into a new Django project and +immediately reused. It's not quite ready to be published though. For that, we +need to package the app to make it easy for others to install. + +.. admonition:: Why nested? + + Why create a ``polls`` directory under ``templates`` when we're + already inside the polls app? This directory is needed to avoid conflicts in + Django's ``app_directories`` template loader. For example, if two + apps had a template called ``base.html``, without the extra directory it + wouldn't be possible to distinguish between the two. It's a good convention + to use the name of your app for this directory. + +.. _installing-reusable-apps-prerequisites: + +Installing some prerequisites +============================= + +The current state of Python packaging is a bit muddled with various tools. For +this tutorial, we're going to use distribute_ to build our package. It's a +community-maintained fork of the older ``setuptools`` project. We'll also be +using `pip`_ to uninstall it after we're finished. You should install these +two packages now. If you need help, you can refer to :ref:`how to install +Django with pip`. You can install ``distribute`` +the same way. + +.. _distribute: http://pypi.python.org/pypi/distribute +.. _pip: http://pypi.python.org/pypi/pip + +Packaging your app +================== + +Python *packaging* refers to preparing your app in a specific format that can +be easily installed and used. Django itself is packaged very much like +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 + + 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.txt`` with the following contents:: + + ===== + Polls + ===== + + Polls is a simple Django app to conduct Web-based polls. For each + question, visitors can choose between a fixed number of answers. + + Detailed documentation is in the "docs" directory. + + Quick start + ----------- + + 1. Add "polls" to your INSTALLED_APPS setting like this:: + + INSTALLED_APPS = ( + ... + 'polls', + ) + + 2. Include the polls URLconf in your project urls.py like this:: + + url(r'^polls/', include('polls.urls')), + + 3. Run `python manage.py syncdb` to create the polls models. + + 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. + +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 +`_ 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.txt')).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', + 'Programming Language :: Python :: 2.6', + '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 and our LICENSE file, create a file + ``django-polls/MANIFEST.in`` with the following contents:: + + include LICENSE + 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 + documentation. Add an additional line to ``django-polls/MANIFEST.in``:: + + recursive-include docs * + + Note that the ``docs`` directory won't be included in your package unless + you add some files to it. Many Django apps also provide their documentation + online through sites like `readthedocs.org `_. + +8. Try building your package with ``python setup.py sdist`` (run from inside + ``django-polls``). This creates a directory called ``dist`` and builds your + new package, ``django-polls-0.1.tar.gz``. + +For more information on packaging, see `The Hitchhiker's Guide to Packaging +`_. + +Using your own package +====================== + +Since we moved the ``polls`` directory out of the project, it's no longer +working. We'll now fix this by installing our new ``django-polls`` package. + +.. admonition:: Installing as a system library + + The following steps install ``django-polls`` as a system library. In + general, it's best to avoid messing with your system libraries to avoid + breaking things. For this simple example though, the risk is low and it will + help with understanding packaging. We'll explain how to uninstall in + step 4. + + For experienced users, a neater way to manage your packages is to use + "virtualenv" (see below). + +1. Inside ``django-polls/dist``, untar the new package + ``django-polls-0.1.tar.gz`` (e.g. ``tar xzvf django-polls-0.1.tar.gz``). If + you're using Windows, you can download the command-line tool bsdtar_ to do + this, or you can use a GUI-based tool such as 7-zip_. + +2. Change into the directory created in step 1 (e.g. ``cd django-polls-0.1``). + +3. If you're using GNU/Linux, Mac OS X or some other flavor of Unix, enter the + command ``sudo python setup.py install`` at the shell prompt. If you're + using Windows, start up a command shell with administrator privileges and + run the command ``setup.py install``. + + With luck, your Django project should now work correctly again. Run the + server again to confirm this. + +4. To uninstall the package, use pip (you already :ref:`installed it + `, right?):: + + sudo pip uninstall django-polls + +.. _bsdtar: http://gnuwin32.sourceforge.net/packages/bsdtar.htm +.. _7-zip: http://www.7-zip.org/ +.. _pip: http://pypi.python.org/pypi/pip + +Publishing your app +=================== + +Now that we've packaged and tested ``django-polls``, it's ready to share with +the world! If this wasn't just an example, you could now: + +* Email the package to a friend. + +* Upload the package on your Web site. + +* Post the package on a public repository, such as `The Python Package Index + (PyPI) `_. + +For more information on PyPI, see the `Quickstart +`_ +section of The Hitchhiker's Guide to Packaging. One detail this guide mentions +is choosing the license under which your code is distributed. + +Installing Python packages with virtualenv +========================================== + +Earlier, we installed the polls app as a system library. This has some +disadvantages: + +* Modifying the system libraries can affect other Python software on your + system. + +* You won't be able to run multiple versions of this package (or others with + the same name). + +Typically, these situations only arise once you're maintaining several Django +projects. When they do, the best solution is to use `virtualenv +`_. This tool allows you to maintain multiple +isolated Python environments, each with its own copy of the libraries and +package namespace. diff --git a/docs/intro/tutorial03.txt b/docs/intro/tutorial03.txt index 169e6cd59fbef..5adfc9a49084d 100644 --- a/docs/intro/tutorial03.txt +++ b/docs/intro/tutorial03.txt @@ -315,6 +315,12 @@ Load the page in your Web browser, and you should see a bulleted-list containing the "What's up" poll from Tutorial 1. The link points to the poll's detail page. +.. admonition:: Organizing Templates + + Rather than one big templates directory, you can also store templates + within each app. We'll discuss this in more detail in the :doc:`reusable + apps tutorial`. + A shortcut: :func:`~django.shortcuts.render` -------------------------------------------- diff --git a/docs/intro/tutorial04.txt b/docs/intro/tutorial04.txt index 8909caf98bf6a..dfee82705636a 100644 --- a/docs/intro/tutorial04.txt +++ b/docs/intro/tutorial04.txt @@ -278,5 +278,10 @@ For full details on generic views, see the :doc:`generic views documentation What's next? ============ -The tutorial ends here for the time being. In the meantime, you might want to -check out some pointers on :doc:`where to go from here `. +The beginner tutorial ends here for the time being. In the meantime, you might +want to check out some pointers on :doc:`where to go from here +`. + +If you are familiar with Python packaging and interested in learning how to +turn polls into a "reusable app", check out :doc:`Advanced tutorial: How to +write reusable apps`.