Python Web frameworks, Part 1: Develop for the Web with Django and Python

来源:百度文库 编辑:神马文学网 时间:2024/04/29 06:32:15
    Country/region [select]     Terms of use


All of dW -----------------   AIX and UNIX   eServer   Information Mgmt   Lotus   Rational   Tivoli   WebSphere   Workplace -----------------   Autonomic computing   Grid computing   Java technology   Linux   Open source   Power Architecture   SOA & Web services   Web architecture   Wireless   XML -----------------   dW forums ----------------- alphaWorks ----------------- All of IBM    
Home     Products     Services & solutions     Support & downloads     My account
 
developerWorks
In this article:
Installing Django
Django admin tool
Django projects and applications
Creating a model
Query sets
Administrator tool
Designing your URL scheme
Implementing the views
Creating the templates
Generic views
Conclusion
Resources
About the author
Rate this page

Related links
Linux technical library
Open source technical library
Web architecture technical library


developerWorks  >  Linux | Open source | Web architecture  >
Python Web frameworks, Part 1: Develop for the Web with Django and Python
The Python Django Web framework, from install to finished Web site

Document options

Print this page

E-mail this page
New site feature

dW radio -- Listen to our podcasts
Rate this page

Help us improve this content
Level: Intermediate
Ian Maurer (ian@itmaurer.com), Senior Consultant, Brulant, Inc.
06 Jun 2006
In this first article of a two-part series, we show off Django, an open-source model-view-controller (MVC)-style Web application framework powered by the Python programming language. With Django, you can create high-quality, easy-to-maintain, database-driven Web applications in minutes.
The Django project is a custom-built framework that originated with an online newspaper Website and was released as open source in July 2005. The core components of the Django framework are:
Object-relational mapping for creating models Polished administrator interface designed for end users Elegant URL design Designer-friendly template language Caching system
This is the first article in a two-part series on Python Web frameworks. The secord article will introduce you to the TurboGears framework.
To use and understand the code in this article, you need to have Python installed and know how to use it at a beginner level. Check to see if you have Python, and what version, by typing python -V. Django requires, at a minimum, version 2.3.5, which is available at the Python Web site (see theResources section later in this article for a link). You should also be at least passingly familiar with the MVC architecture.
This article uses the development version of Django, to take advantage of the recent improvements to the Django framework. I recommend that you use this version until the 0.95 release. Check the Django Web site for the latest release (again, seeResources for a link).
Download and install Django as follows:
~/downloads# svn co http://code.djangoproject.com/svn/django/trunk/ django_src ~/downloads# cd django_src ~/downloads# python setup.py install


Back to top
After installing Django, you should have the admin tool, django-admin.py, available on your path. Listing 2 shows some of the commands available to the admin tool:
~/dev$ django-admin.py usage: django-admin.py action [options] actions: adminindex [modelmodule ...] Prints the admin-index template snippet for the given model module name(s). ... snip ... startapp [appname] Creates a Django app directory structure for the given app name in the current directory. startproject [projectname] Creates a Django project directory structure for the given project name in the current directory. validate Validates all installed models. options: -h, --help show this help message and exit --settings=SETTINGS Python path to settings module, e.g. "myproject.settings.main". If this isn‘t provided, the DJANGO_SETTINGS_MODULE environment variable will be used. --pythonpath=PYTHONPATH Lets you manually add a directory the Python path, e.g. "/home/djangoprojects/myproject".


Back to top
To begin a Django project, use the django-admin startproject command, like so:
~/dev$ django-admin.py startproject djproject
The above command creates a directory called djproject that contains the basic configuration files needed to run a Django project:
__init__.py manage.py settings.py urls.py
For this project, you will build a job-board application called "jobs." To create an application, use the manage.py script, which is a project-specific django-admin.py script where the settings.py file is automatically supplied:
~/dev$ cd djproject ~/dev/djproject$ python manage.py startapp jobs
This creates a barebone application with one Python module for your models and another for your views. The jobs directory will contain the following files:
__init__.py models.py views.py
The location of the application inside the project is purely a convention created for new Django developers, not a requirement. Once you start mixing and matching applications across several projects, you can put applications in their own module namespace and tie them together using settings and master URL files. For now, follow the steps as shown.
To make Django aware of a new application, you‘ll need to add an entry to the INSTALLED_APPS field in the settings.py file. For this job board application, the string djproject.jobs must be added:
INSTALLED_APPS = ( ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.sites‘, ‘djproject.jobs‘, )


Back to top
Django comes with its own object-relational mapper (ORM) library that supports dynamic database access through a Python object interface. The Python interface is very usable and powerful, but you are also free to drop down and use SQL directly, if needed.
The ORM currently provides support for PostgreSQL, MySQL, SQLite, and Microsoft® SQL databases.
This example uses SQLite as the database backend. SQLite is a lightweight database that requires no configuration and resides on disk as a simple file. To use SQLite, simply install the pysqlite library using setuptools (seeResources for more information on setuptools and the easy_install tool in particular, which you need to install separately):
easy_install pysqlite
Before working on the model, configure the database in the settings file. SQLite requires only that the database engine and name be specified.
DATABASE_ENGINE = ‘sqlite3‘ DATABASE_NAME = ‘/path/to/dev/djproject/database.db‘ DATABASE_USER = ‘‘ DATABASE_PASSWORD = ‘‘ DATABASE_HOST = ‘‘ DATABASE_PORT = ‘‘
This job board application will have two types of objects, Locations and Jobs. A Location contains city, state (optional), and country fields. A Job has a location, title, description, and publish date.
from django.db import models class Location(models.Model): city = models.CharField(maxlength=50) state = models.CharField(maxlength=50, null=True, blank=True) country = models.CharField(maxlength=50) def __str__(self): if self.state: return "%s, %s, %s" % (self.city, self.state, self.country) else: return "%s, %s" % (self.city, self.country) class Job(models.Model): pub_date = models.DateField() job_title = models.CharField(maxlength=50) job_description = models.TextField() location = models.ForeignKey(Location) def __str__(self): return "%s (%s)" % (self.job_title, self.location)
The __str__ method is a special class method in Python that returns the string representation of an object. Django uses this method extensively when displaying objects in the Admin tool.
To see the database schema for the model, run manage.py‘s sql command. The schema won‘t be enacted yet.
~/dev/djproject$ python manage.py sql jobs BEGIN; CREATE TABLE "jobs_job" ( "id" integer NOT NULL PRIMARY KEY, "pub_date" date NOT NULL, "job_title" varchar(50) NOT NULL, "job_description" text NOT NULL, "location_id" integer NOT NULL ); CREATE TABLE "jobs_location" ( "id" integer NOT NULL PRIMARY KEY, "city" varchar(50) NOT NULL, "state" varchar(50) NULL, "country" varchar(50) NOT NULL ); COMMIT;
To initialize and install the model, run the synchronize database command, syncdb:
~/dev/djproject$ python manage.py syncdb
Note that the syncdb command asks you to create a superuser account. This is because the django.contrib.auth application, which provides basic user authentication functionality, is supplied by default in your INSTALLED_APPS settings. The superuser name and password will be used for logging into the admin tool described in the next section. Remember that this is the Django superuser, not your system‘s.


Back to top
Django models access the database through the default Manager class called objects. For example, to print a list of all Jobs, you would use the all method of the objects manager:
>>> from jobs.models import Job >>> for job in Job.objects.all(): ... print job
The Manager class also has filtering methods called filter and exclude. Filtering gets all the objects that meet a condition, while excluding gives all the objects that do not. The queries below should give the same results ("gte" means "greater than or equal," and "lt" means "less than").
>>> from jobs.models import Job >>> from datetime import datetime >>> q1 = Job.objects.filter(pub_date__gte=datetime(2006, 1, 1)) >>> q2 = Job.objects.exclude(pub_date__lt=datetime(2006, 1, 1))
The filter and exclude methods return QuerySet objects that can be chained together and can even perform joins. The q4 query below will find jobs posted since January 1st, 2006, in Cleveland, Ohio:
>>> from jobs.models import Job >>> from datetime import datetime >>> q3 = Job.objects.filter(pub_date__gte=datetime(2006, 1, 1)) >>> q4 = q3.filter(location__city__exact="Cleveland", ... location__state__exact="Ohio")
It‘s very nice that QuerySets are lazy. This means that they do not execute against the database until they are evaluated, and thus run much faster than immediate queries.
This laziness is handy with Python‘s slicing functionality. Rather than request all the records and then slice the records needed, the code below uses an OFFSET of 5 and a LIMIT of 10 in the actual SQL query, greatly improving performance.
>>> from jobs.models import Job >>> for job in Job.objects.all()[5:15] ... print job
Note: Use the count method to find out how many records are in a QuerySet. The Python len method does a full evaluation and then counts the rows returned as records, while the count method does an actual SQL COUNT, which is much faster. Your database administrator will thank you.
>>> from jobs.models import Job >>> print "Count = ", Job.objects.count() # GOOD! >>> print "Count = ", len(Job.objects.all()) # BAD!
For more information, see theResources section for a link to the Django "Database API reference."


Back to top
One of the biggest selling points of Django is its well-polished admin interface. This tool was created with end users in mind. It gives your projects a great data entry tool.
The admin tool is an application that comes with Django. It must be installed, like the jobs application, before you can use it. The first step is to add the application‘s module (django.contrib.admin) to the INSTALLED_APPS setting:
INSTALLED_APPS = ( ‘django.contrib.auth‘, ‘django.contrib.contenttypes‘, ‘django.contrib.sessions‘, ‘django.contrib.sites‘, ‘djproject.jobs‘, ‘django.contrib.admin‘, )
To make the admin tool available from the /admin URL, simply uncomment the line provided in your project‘s urls.py file. The next section goes into URL configuration in greater detail.
from django.conf.urls.defaults import * urlpatterns = patterns(‘‘, (r‘^admin/‘, include(‘django.contrib.admin.urls.admin‘)), )
The admin application has its own database model and needs to be installed. Use the syncdb command again to accomplish this:
python manage.py syncdb
To view the admin tool, you can use the test server that comes with Django.
~/dev/djproject$ python manage.py runserver Validating models... 0 errors found. Django version 0.95 (post-magic-removal), using settings ‘djproject.settings‘ Development server is running at http://127.0.0.1:8000/ Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows).
You can now navigate to the admin tool at http://localhost:8000/admin and log in using the superuser account you created before. You will notice that none of your models are available for use.
To make a class accessible through the admin tool, create an Admin subclass to it. You can then customize how each class can be administered by adding class attributes to this subclass. Listing 19 shows how to add the Location class to the admin tool.
class Location(meta.Model): ... class Admin: list_display = ("city", "state", "country")
You can now create, update, and delete the Location records through the admin interface.

You can list and sort Records by city, state, and country as specified by the list_display class attribute.

The admin tool has numerous options for managing each type of model class. Listing 20 shows several examples applied to the Job class:
class Job(meta.Model): ... class Admin: list_display = ("job_title", "location", "pub_date") ordering = ["-pub_date"] search_fields = ("job_title", "job_description") list_filter = ("location",)
According to the above settings, a job‘s title, location, and published data will be used when listing job records. The jobs will be ordered by when they were published, starting with the most recent (a minus sign indicates descending order). Users can find jobs by title and description, and administrators can filter records based on location.



Back to top
The Django URL dispatch system uses regular-expression configuration modules that map URL string patterns to Python methods called views. This system allows URLs to be completely decoupled from the underlying code, allowing for maximum control and flexibility.
A urls.py module is created and defined as the default starting point for URL configuration (via the ROOT_URLCONF value in the settings.py module). The only requirement for a URL configuration file is that it must contain an object that defines the patterns called urlpatterns.
The job board application will start with an index and detail view that are accessed through these URL mappings:
/jobs index view: Displays the latest 10 jobs /jobs/1 detail view: Displays jobs with an ID of 1
Both views (index and detail) will be implemented in a module called views.py in the jobs application. Implementing this configuration in the project‘s urls.py file would look like this:
from django.conf.urls.defaults import * urlpatterns = patterns(‘‘, (r‘^admin/‘, include(‘django.contrib.admin.urls.admin‘)), (r‘^jobs/$‘, ‘djproject.jobs.views.index‘), (r‘^jobs/(?P\d+)/$‘, ‘djproject.jobs.views.detail‘), )
Note the piece. It‘s important later.
Best practice is to pull out application-specific URL patterns and place them in the application itself. This decouples the application from the project and allows for greater reuse. An application-level URL config file for jobs would look like this:
from django.conf.urls.defaults import * urlpatterns = patterns(‘‘, (r‘^$‘, ‘djproject.jobs.views.index‘), (r‘^(?P\d+)/$‘, ‘djproject.jobs.views.detail‘), )
Since the view methods now all come from the same module, the first argument can be used to specify djproject.jobs.views as the module‘s root name, and Django will use it to look for the methods index and detail:
from django.conf.urls.defaults import * urlpatterns = patterns(‘djproject.jobs.views‘, (r‘^$‘, ‘index‘), (r‘^(?P\d+)/$‘, ‘detail‘), )
Tying the above jobs URLs back into the project as a whole is done using the include function. The application level URLs are tied back below the /jobs section:
from django.conf.urls.defaults import * urlpatterns = patterns(‘‘, (r‘^admin/‘, include(‘django.contrib.admin.urls.admin‘)), (r‘^jobs/‘, include(‘djproject.jobs.urls‘)), )
If you try to access the index page (http://localhost:8000/jobs) at this point using your test server, you will get an error, since the view being called (djproject.jobs.views.index) does not exist yet.


Back to top
A view is a simple Python method that accepts a request object and is responsible for:
Any business logic (directly or indirectly) A context dictionary with data for the template Rendering the template with a context The response object that passes the rendered results back to the framework
In Django, the Python method called when a URL is requested is called a view, and the page loaded and rendered by the view is called a template. Because of this, the Django team refers to Django as an MVT (model-view-template) framework. TurboGears, on the other hand, calls its methods controllers and their rendered templates views so that they can fit squarely into the MVC acronym. The difference is largely semantic, as they accomplish the same things.
The simplest possible view returns an HttpResponse object initialized with a string. Create the following method and make a /jobs HTTP request to ensure your urls.py and views.py files are set up correctly.
from django.http import HttpResponse def index(request): return HttpResponse("Job Index View")
The following code gets the latest 10 jobs, renders them through a template, and returns a response. It will not work without the template file from thenext section.
from django.template import Context, loader from django.http import HttpResponse from jobs.models import Job def index(request): object_list = Job.objects.order_by(‘-pub_date‘)[:10] t = loader.get_template(‘jobs/job_list.html‘) c = Context({ ‘object_list‘: object_list, }) return HttpResponse(t.render(c))
In the above code, the template is named by the jobs/job_list.html string. The template is rendered with a context of the job list named object_list. The rendered template string is then passed into an HTTPResponse constructor, which is sent back to the request client via the framework.
The steps of loading a template, creating a context, and returning a new response object are replaced below with the convenience method named render_to_response. Also new is the detail view method that uses a convenience method called get_object_or_404 to retrieve a Job object using the arguments supplied. If the object is not found, a 404 exception is thrown. These two methods remove a lot of boilerplate code in most Web applications.
from django.shortcuts import get_object_or_404, render_to_response from jobs.models import Job def index(request): object_list = Job.objects.order_by(‘-pub_date‘)[:10] return render_to_response(‘jobs/job_list.html‘, {‘object_list‘: object_list}) def detail(request, object_id): job = get_object_or_404(Job, pk=object_id) return render_to_response(‘jobs/job_detail.html‘, {‘object‘: job})
Note that detail takes object_id as an argument. This is the number mentioned earlier after the /jobs/ URL path in the jobs urls.py file. It is passed further to the get_object_or_404 method as the primary key (pk).
The above views will still fail because the templates that they load and render (jobs/job_list.html and jobs/job_detail.html) do not exist yet.


Back to top
Django provides a simple templating language designed for fast rendering and ease of use. Django templates are created with plain text embedded with {{ variables }} and {% tags %}. Variables are evaluated and replaced with the value they represent. Tags are used for basic control logic. Templates can be used to generate any text-based format including HTML, XML, CSV, and plain text.
The first step is to define where the templates are located. For simplicity‘s sake, create a templates directory under djproject and add its path to the TEMPLATE_DIRS settings.py entry:
TEMPLATE_DIRS = ( ‘/path/to/devdir/djproject/templates/‘, )
Django templates support a concept called template inheritance, which allows site designers to create a uniform look and feel without repeating content in every template. You can use inheritance by defining a skeleton, or base, document with block tags. These block tags are filled by page templates with content. This example shows an HTML skeleton with blocks called title, extrahead, and content:
Company Site: {% block title %}Page{% endblock %} {% block extrahead %}{% endblock %} {% block content %}{% endblock %}
To keep the application decoupled from the project, use an intermediary base file as the base for all the Job application page files. For this example, put the application CSS in the base file for simplicity. In a real application, with a properly configured Web server, extract this CSS and put it in a static file served by the Web server.
{% extends "base.html" %} {% block extrahead %} {% endblock %}
By default, the Django test server does not serve static files because that is the Web server‘s job. If, during development, you would like Django to serve images, style sheets, etc., then see the link inResources on how to turn that feature on.
Now, create two page templates to be loaded and rendered by the views. The jobs/job_list.html template simply iterates through the object_list it gets through the context by the index view, and displays a link to each record‘s detail page.
{% extends "jobs/base.html" %} {% block title %}Job List{% endblock %} {% block content %}

Job List

{% endblock %}
The jobs/job_detail.html page shows one record, called job:
{% extends "jobs/base.html" %} {% block title %}Job Detail{% endblock %} {% block content %}

Job Detail

{{ job.job_title }} - {{ job.location }}
Posted: {{ job.pub_date|date:"d-M-Y" }}
{{ job.job_description }}
{% endblock %}
The Django template language has been designed with limited functional capabilities. This limitation keeps templates simple for non-programmers and keeps programmers from putting business logic where it doesn‘t belong, the presentation layer. See the link to the template language documentation inResources.


Back to top
Django comes with four sets of generic views that let developers create applications that follow typical patterns:
List/detail pages (like the above example) Date-based breakdown of records (useful for news or blog sites) Creation, update, and deletion (CRUD) of objects Simple direct template rendering or simple HTTP redirect
Instead of creating boilerplate view methods, all of the business logic is in the urls.py file and is handled by the generic view methods supplied by Django.
from django.conf.urls.defaults import * from jobs.models import Job info_dict = { ‘queryset‘: Job.objects.all(), } urlpatterns = patterns(‘django.views.generic.list_detail‘, (r‘^$‘, ‘object_list‘, info_dict), (r‘^(?P\d+)/$‘, ‘object_detail‘, info_dict), )
Three major changes to this urls.py file are:
An info_dict map object passes along a query set for the Jobs to be accessed. It uses django.views.generic.list_detail instead of djproject.jobs.views. The actual views called are object_list and object_detail.
This project follows some requirements to make the transition to generic views work automatically:
The generic detail view expects an argument named object_id. The templates follow the naming pattern: app_label/model_name_list.html (jobs/job_list.html) app_label/model_name_detail.html (jobs/job_detail.html) The list template handles a list named object_list. The detail template handles an object named object.
More options can be passed through the info_dict, including a paginate_by value that specifies the number of objects per page.


Back to top
The next article in this series will examine TurboGears, another Python Web framework, and compare it with Django.


Back to top
Learn
Read anoverview of the MVC architecture on Wikipedia.
"Fast-track your Web apps with Ruby on Rails" (developerWorks, June 2005) shows how Ruby on Rails creates Web-based applications.
Python.org is the home of the Python programming language, where you can find links for downloading the Python interpreter and standard libraries.
ThePython tutorial will get you started with Python.
DjangoProject.com is the home page for the Django framework. The documentation includes: TheHow to install Django, which shows how to set up Django on a development machine TheDatabase API reference, a guide to using the Django ORM library TheDjango template language, a simple guide for template authorsHow to serve static files, an illustration of how to set up Django to serve static files during development (do not do this in production)How to use Django with mod_python, a guide to combining Django with Apache using the mod_python moduleGeneric views, which shows how to implement common Web application patterns even more quickly with Django‘s generic views
Building and Distributing Packages with setuptools shows how to install setuptools, along with easy_install (part of the Python Eggs package).
Django performance tips shows how to handle lots of traffic with Django.
In thedeveloperWorks Linux zone, find more resources for Linux developers.
Stay current withdeveloperWorks technical events and Webcasts.
Get products and technologies
Order the SEK for Linux, a two-DVD set containing the latest IBM trial software for Linux from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
WithIBM trial software, available for download directly from developerWorks, build your next development project on Linux.
Discuss
Check outdeveloperWorks blogs and get involved in thedeveloperWorks community.


Back to top



Ian Maurer is a senior consultant for Brulant, Inc., where he specializes in developing integrated e-commerce solutions using open source and IBM WebSphere technologies for various industries including consumer goods and retail. Ian resides in northeastern Ohio and is a member of the Cleveland Area Python Interest Group.


Back to top

Please take a moment to complete this form to help us better serve you.

Did the information help you to achieve your goal?

Yes No Don‘t know


Please provide us with comments to help improve this page:



How useful is the information?

1 2 3 4 5
Not
usefulExtremely
useful





Back to top

DB2, Lotus, PowerPC, Rational, Tivoli, and WebSphere are trademarks of IBM Corporation in the United States, other countries, or both. Linux is a trademark of Linus Torvalds in the United States, other countries, or both. Microsoft is a trademark of Microsoft Corporation in the United States, other countries, or both. Other company, product, or service names may be trademarks or service marks of others.
About IBM     Privacy     Contact
_xyz