| ===================================== |
| Writing your first Django app, part 1 |
| ===================================== |
| |
| Let's learn by example. |
| |
| Throughout this tutorial, we'll walk you through the creation of a basic |
| poll application. |
| |
| It'll consist of two parts: |
| |
| * A public site that lets people view polls and vote in them. |
| * An admin site that lets you add, change and delete poll. |
| |
| We'll assume you have `Django installed`_ already. You can tell Django is |
| installed by running the Python interactive interpreter and typing |
| ``import django``. If that command runs successfully, with no errors, Django is |
| installed. |
| |
| .. _`Django installed`: ../install/ |
| |
| .. admonition:: Where to get help: |
| |
| If you're having trouble going through this tutorial, please post a message |
| to `django-users`_ or drop by `#django`_ on ``irc.freenode.net`` and we'll |
| try to help. |
| |
| .. _django-users: http://groups.google.com/group/django-users |
| .. _#django: irc://irc.freenode.net/django |
| |
| Creating a project |
| ================== |
| |
| If this is your first time using Django, you'll have to take care of some |
| initial setup. Namely, you'll need to auto-generate some code that establishes |
| a Django *project* -- a collection of settings for an instance of Django, |
| including database configuration, Django-specific options and |
| application-specific settings. |
| |
| From the command line, ``cd`` into a directory where you'd like to store your |
| code, then run the command ``django-admin.py startproject mysite``. This |
| will create a ``mysite`` directory in your current directory. |
| |
| .. note:: |
| |
| You'll need to avoid naming projects after built-in Python or Django |
| components. In particular, this means you should avoid using names like |
| ``django`` (which will conflict with Django itself) or ``site`` (which |
| conflicts with a built-in Python package). |
| |
| (``django-admin.py`` should be on your system path if you installed Django via |
| ``python setup.py``. If it's not on your path, you can find it in |
| ``site-packages/django/bin``, where ``site-packages`` is a directory within |
| your Python installation. Consider symlinking to ``django-admin.py`` from some |
| place on your path, such as ``/usr/local/bin``.) |
| |
| .. admonition:: Where should this code live? |
| |
| If your background is in PHP, you're probably used to putting code under the |
| Web server's document root (in a place such as ``/var/www``). With Django, |
| you don't do that. It's not a good idea to put any of this Python code within |
| your Web server's document root, because it risks the possibility that |
| people may be able to view your code over the Web. That's not good for |
| security. |
| |
| Put your code in some directory **outside** of the document root, such as |
| ``/home/mycode``. |
| |
| Let's look at what ``startproject`` created:: |
| |
| mysite/ |
| __init__.py |
| manage.py |
| settings.py |
| urls.py |
| |
| These files are: |
| |
| * ``__init__.py``: An empty file that tells Python that this directory |
| should be considered a Python package. (Read `more about packages`_ in the |
| official Python docs if you're a Python beginner.) |
| * ``manage.py``: A command-line utility that lets you interact with this |
| Django project in various ways. |
| * ``settings.py``: Settings/configuration for this Django project. |
| * ``urls.py``: The URL declarations for this Django project; a "table of |
| contents" of your Django-powered site. |
| |
| .. _more about packages: http://docs.python.org/tut/node8.html#packages |
| |
| The development server |
| ---------------------- |
| |
| Let's verify this worked. Change into the ``mysite`` directory, if you |
| haven't already, and run the command ``python manage.py runserver``. You'll see |
| the following output on the command line:: |
| |
| Validating models... |
| 0 errors found. |
| |
| Django version 0.95, using settings 'mysite.settings' |
| Development server is running at http://127.0.0.1:8000/ |
| Quit the server with CONTROL-C (Unix) or CTRL-BREAK (Windows). |
| |
| You've started the Django development server, a lightweight Web server written |
| purely in Python. We've included this with Django so you can develop things |
| rapidly, without having to deal with configuring a production server -- such as |
| Apache -- until you're ready for production. |
| |
| Now's a good time to note: DON'T use this server in anything resembling a |
| production environment. It's intended only for use while developing. (We're in |
| the business of making Web frameworks, not Web servers.) |
| |
| Now that the server's running, visit http://127.0.0.1:8000/ with your Web |
| browser. You'll see a "Welcome to Django" page, in pleasant, light-blue pastel. |
| It worked! |
| |
| .. admonition:: Changing the port |
| |
| By default, the ``runserver`` command starts the development server on port |
| 8000. If you want to change the server's port, pass it as a command-line |
| argument. For instance, this command starts the server on port 8080:: |
| |
| python manage.py runserver 8080 |
| |
| Full docs for the development server are at `django-admin documentation`_. |
| |
| .. _django-admin documentation: ../django_admin/ |
| |
| Database setup |
| -------------- |
| |
| Now, edit ``settings.py``. It's a normal Python module with module-level |
| variables representing Django settings. Change these settings to match your |
| database's connection parameters: |
| |
| * ``DATABASE_ENGINE`` -- Either 'postgresql', 'mysql' or 'sqlite3'. |
| More coming soon. |
| * ``DATABASE_NAME`` -- The name of your database, or the full (absolute) |
| path to the database file if you're using SQLite. |
| * ``DATABASE_USER`` -- Your database username (not used for SQLite). |
| * ``DATABASE_PASSWORD`` -- Your database password (not used for SQLite). |
| * ``DATABASE_HOST`` -- The host your database is on. Leave this as an |
| empty string if your database server is on the same physical machine |
| (not used for SQLite). |
| |
| .. admonition:: Note |
| |
| If you're using PostgreSQL or MySQL, make sure you've created a database by |
| this point. Do that with "``CREATE DATABASE database_name;``" within your |
| database's interactive prompt. |
| |
| While you're editing ``settings.py``, take note of the ``INSTALLED_APPS`` |
| setting towards the bottom of the file. That variable holds the names of all |
| Django applications that are activated in this Django instance. Apps can be |
| used in multiple projects, and you can package and distribute them for use |
| by others in their projects. |
| |
| By default, ``INSTALLED_APPS`` contains the following apps, all of which come |
| with Django: |
| |
| * ``django.contrib.auth`` -- An authentication system. |
| * ``django.contrib.contenttypes`` -- A framework for content types. |
| * ``django.contrib.sessions`` -- A session framework. |
| * ``django.contrib.sites`` -- A framework for managing multiple sites |
| with one Django installation. |
| |
| These applications are included by default as a convenience for the common |
| case. |
| |
| Each of these applications makes use of at least one database table, though, |
| so we need to create the tables in the database before we can use them. To do |
| that, run the following command:: |
| |
| python manage.py syncdb |
| |
| The ``syncdb`` command looks at the ``INSTALLED_APPS`` setting and creates any |
| necessary database tables according to the database settings in your |
| ``settings.py`` file. You'll see a message for each database table it creates, |
| and you'll get a prompt asking you if you'd like to create a superuser account |
| for the authentication system. Go ahead and do that. |
| |
| If you're interested, run the command-line client for your database and type |
| ``\dt`` (PostgreSQL), ``SHOW TABLES;`` (MySQL), or ``.schema`` (SQLite) to |
| display the tables Django created. |
| |
| .. admonition:: For the minimalists |
| |
| Like we said above, the default applications are included for the common |
| case, but not everybody needs them. If you don't need any or all of them, |
| feel free to comment-out or delete the appropriate line(s) from |
| ``INSTALLED_APPS`` before running ``syncdb``. The ``syncdb`` command will |
| only create tables for apps in ``INSTALLED_APPS``. |
| |
| Creating models |
| =============== |
| |
| Now that your environment -- a "project" -- is set up, you're set to start |
| doing work. |
| |
| Each application you write in Django consists of a Python package, somewhere |
| on your `Python path`_, that follows a certain convention. Django comes with a |
| utility that automatically generates the basic directory structure of an app, |
| so you can focus on writing code rather than creating directories. |
| |
| .. admonition:: Projects vs. apps |
| |
| What's the difference between a project and an app? An app is a Web |
| application that does something -- e.g., a weblog system, a database of |
| public records or a simple poll app. A project is a collection of |
| configuration and apps for a particular Web site. A project can contain |
| multiple apps. An app can be in multiple projects. |
| |
| In this tutorial, we'll create our poll app in the ``mysite`` directory, |
| for simplicity. As a consequence, the app will be coupled to the project -- |
| 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 ``mysite`` directory and type |
| this command:: |
| |
| python manage.py startapp polls |
| |
| That'll create a directory ``polls``, which is laid out like this:: |
| |
| polls/ |
| __init__.py |
| models.py |
| views.py |
| |
| This directory structure will house the poll application. |
| |
| The first step in writing a database Web app in Django is to define your models |
| -- essentially, your database layout, with additional metadata. |
| |
| .. admonition:: Philosophy |
| |
| A model is the single, definitive source of data about your |
| data. It contains the essential fields and behaviors of the data you're |
| storing. Django follows the `DRY Principle`_. The goal is to define your |
| data model in one place and automatically derive things from it. |
| |
| In our simple poll app, we'll create two models: polls and choices. A poll has |
| a question and a publication date. A choice has two fields: the text of the |
| choice and a vote tally. Each choice is associated with a poll. |
| |
| These concepts are represented by simple Python classes. Edit the |
| ``polls/models.py`` file so it looks like this:: |
| |
| from django.db import models |
| |
| class Poll(models.Model): |
| question = models.CharField(maxlength=200) |
| pub_date = models.DateTimeField('date published') |
| |
| class Choice(models.Model): |
| poll = models.ForeignKey(Poll) |
| choice = models.CharField(maxlength=200) |
| votes = models.IntegerField() |
| |
| The code is straightforward. Each model is represented by a class that |
| subclasses ``django.db.models.Model``. Each model has a number of class |
| variables, each of which represents a database field in the model. |
| |
| Each field is represented by an instance of a ``models.*Field`` class -- e.g., |
| ``models.CharField`` for character fields and ``models.DateTimeField`` for |
| datetimes. This tells Django what type of data each field holds. |
| |
| The name of each ``models.*Field`` instance (e.g. ``question`` or ``pub_date`` ) |
| is the field's name, in machine-friendly format. You'll use this value in your |
| Python code, and your database will use it as the column name. |
| |
| You can use an optional first positional argument to a ``Field`` to designate a |
| human-readable name. That's used in a couple of introspective parts of Django, |
| and it doubles as documentation. If this field isn't provided, Django will use |
| the machine-readable name. In this example, we've only defined a human-readable |
| name for ``Poll.pub_date``. For all other fields in this model, the field's |
| machine-readable name will suffice as its human-readable name. |
| |
| Some ``Field`` classes have required elements. ``CharField``, for example, |
| requires that you give it a ``maxlength``. That's used not only in the database |
| schema, but in validation, as we'll soon see. |
| |
| Finally, note a relationship is defined, using ``models.ForeignKey``. That tells |
| Django each Choice is related to a single Poll. Django supports all the common |
| database relationships: many-to-ones, many-to-manys and one-to-ones. |
| |
| .. _`Python path`: http://docs.python.org/tut/node8.html#SECTION008110000000000000000 |
| .. _DRY Principle: http://c2.com/cgi/wiki?DontRepeatYourself |
| |
| Activating models |
| ================= |
| |
| That small bit of model code gives Django a lot of information. With it, Django |
| is able to: |
| |
| * Create a database schema (``CREATE TABLE`` statements) for this app. |
| * Create a Python database-access API for accessing Poll and Choice objects. |
| |
| But first we need to tell our project that the ``polls`` app is installed. |
| |
| .. admonition:: Philosophy |
| |
| Django apps are "pluggable": You can use an app in multiple projects, and |
| you can distribute apps, because they don't have to be tied to a given |
| Django installation. |
| |
| Edit the ``settings.py`` file again, and change the ``INSTALLED_APPS`` setting |
| to include the string ``'mysite.polls'``. So it'll look like this:: |
| |
| INSTALLED_APPS = ( |
| 'django.contrib.auth', |
| 'django.contrib.contenttypes', |
| 'django.contrib.sessions', |
| 'django.contrib.sites', |
| 'mysite.polls' |
| ) |
| |
| Now Django knows ``mysite`` includes the ``polls`` app. Let's run another command:: |
| |
| python manage.py sql polls |
| |
| You should see the following (the CREATE TABLE SQL statements for the polls app):: |
| |
| BEGIN; |
| CREATE TABLE "polls_poll" ( |
| "id" serial NOT NULL PRIMARY KEY, |
| "question" varchar(200) NOT NULL, |
| "pub_date" timestamp with time zone NOT NULL |
| ); |
| CREATE TABLE "polls_choice" ( |
| "id" serial NOT NULL PRIMARY KEY, |
| "poll_id" integer NOT NULL REFERENCES "polls_poll" ("id"), |
| "choice" varchar(200) NOT NULL, |
| "votes" integer NOT NULL |
| ); |
| COMMIT; |
| |
| Note the following: |
| |
| * Table names are automatically generated by combining the name of the app |
| (``polls``) and the lowercase name of the model -- ``poll`` and |
| ``choice``. (You can override this behavior.) |
| |
| * Primary keys (IDs) are added automatically. (You can override this, too.) |
| |
| * By convention, Django appends ``"_id"`` to the foreign key field name. |
| Yes, you can override this, as well. |
| |
| * The foreign key relationship is made explicit by a ``REFERENCES`` statement. |
| |
| * It's tailored to the database you're using, so database-specific field |
| types such as ``auto_increment`` (MySQL), ``serial`` (PostgreSQL), or |
| ``integer primary key`` (SQLite) are handled for you automatically. Same |
| goes for quoting of field names -- e.g., using double quotes or single |
| quotes. The author of this tutorial runs PostgreSQL, so the example |
| output is in PostgreSQL syntax. |
| |
| * The `sql` command doesn't actually run the SQL in your database - it just |
| prints it to the screen so that you can see what SQL Django thinks is required. |
| If you wanted to, you could copy and paste this SQL into your database prompt. |
| However, as we will see shortly, Django provides an easier way of committing |
| the SQL to the database. |
| |
| If you're interested, also run the following commands: |
| * ``python manage.py validate polls`` -- Checks for any errors in the |
| construction of your models. |
| |
| * ``python manage.py sqlinitialdata polls`` -- Outputs any initial data |
| required for Django's admin framework and your models. |
| |
| * ``python manage.py sqlclear polls`` -- Outputs the necessary ``DROP |
| TABLE`` statements for this app, according to which tables already exist |
| in your database (if any). |
| |
| * ``python manage.py sqlindexes polls`` -- Outputs the ``CREATE INDEX`` |
| statements for this app. |
| |
| * ``python manage.py sqlall polls`` -- A combination of all the SQL from |
| the 'sql', 'sqlinitialdata', and 'sqlindexes' commands. |
| |
| Looking at the output of those commands can help you understand what's actually |
| happening under the hood. |
| |
| Now, run ``syncdb`` again to create those model tables in your database:: |
| |
| python manage.py syncdb |
| |
| The ``syncdb`` command runs the sql from 'sqlall' on your database for all apps |
| in ``INSTALLED_APPS`` that don't already exist in your database. This creates |
| all the tables, initial data and indexes for any apps you have added to your |
| project since the last time you ran syncdb. ``syncdb`` can be called as often |
| as you like, and it will only ever create the tables that don't exist. |
| |
| Read the `django-admin.py documentation`_ for full information on what the |
| ``manage.py`` utility can do. |
| |
| .. _django-admin.py documentation: ../django_admin/ |
| |
| Playing with the API |
| ==================== |
| |
| Now, let's hop into the interactive Python shell and play around with the free |
| API Django gives you. To invoke the Python shell, use this command:: |
| |
| python manage.py shell |
| |
| 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 |
| things: |
| |
| * Putting ``mysite`` on ``sys.path``. For flexibility, several pieces of |
| Django refer to projects in Python dotted-path notation (e.g. |
| ``'mysite.polls.models'``). In order for this to work, the |
| ``mysite`` package has to be on ``sys.path``. |
| |
| We've already seen one example of this: the ``INSTALLED_APPS`` setting is |
| a list of packages in dotted-path notation. |
| |
| * Setting the ``DJANGO_SETTINGS_MODULE`` environment variable, which gives |
| Django the path to your ``settings.py`` file. |
| |
| .. admonition:: Bypassing manage.py |
| |
| 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 set the ``DJANGO_SETTINGS_MODULE`` |
| environment variable to ``mysite.settings``. |
| |
| For more information on all of this, see the `django-admin.py documentation`_. |
| |
| Once you're in the shell, explore the database API:: |
| |
| # Import the model classes we just wrote. |
| >>> from mysite.polls.models import Poll, Choice |
| |
| # No polls are in the system yet. |
| >>> Poll.objects.all() |
| [] |
| |
| # Create a new Poll. |
| >>> from datetime import datetime |
| >>> p = Poll(question="What's up?", pub_date=datetime.now()) |
| |
| # Save the object into the database. You have to call save() explicitly. |
| >>> p.save() |
| |
| # Now it has an ID. Note that this might say "1L" instead of "1", depending |
| # on which database you're using. That's no biggie; it just means your |
| # database backend prefers to return integers as Python long integer |
| # objects. |
| >>> p.id |
| 1 |
| |
| # Access database columns via Python attributes. |
| >>> p.question |
| "What's up?" |
| >>> p.pub_date |
| datetime.datetime(2005, 7, 15, 12, 00, 53) |
| |
| # Change values by changing the attributes, then calling save(). |
| >>> p.pub_date = datetime(2005, 4, 1, 0, 0) |
| >>> p.save() |
| |
| # objects.all() displays all the polls in the database. |
| >>> Poll.objects.all() |
| [<Poll: Poll object>] |
| |
| |
| Wait a minute. ``<Poll: Poll object>`` is, utterly, an unhelpful |
| representation of this object. Let's fix that by editing the polls model (in |
| the ``polls/models.py`` file) and adding a ``__str__()`` method to both |
| ``Poll`` and ``Choice``:: |
| |
| class Poll(models.Model): |
| # ... |
| def __str__(self): |
| return self.question |
| |
| class Choice(models.Model): |
| # ... |
| def __str__(self): |
| return self.choice |
| |
| It's important to add ``__str__()`` methods to your models, not only for your |
| own sanity when dealing with the interactive prompt, but also because objects' |
| representations are used throughout Django's automatically-generated admin. |
| |
| Note these are normal Python methods. Let's add a custom method, just for |
| demonstration:: |
| |
| import datetime |
| # ... |
| class Poll(models.Model): |
| # ... |
| def was_published_today(self): |
| return self.pub_date.date() == datetime.date.today() |
| |
| Note the addition of ``import datetime`` to reference Python's standard |
| ``datetime`` module. |
| |
| Let's jump back into the Python interactive shell by running |
| ``python manage.py shell`` again:: |
| |
| >>> from mysite.polls.models import Poll, Choice |
| |
| # Make sure our __str__() addition worked. |
| >>> Poll.objects.all() |
| [<Poll: What's up?>] |
| |
| # Django provides a rich database lookup API that's entirely driven by |
| # keyword arguments. |
| >>> Poll.objects.filter(id=1) |
| [<Poll: What's up?>] |
| >>> Poll.objects.filter(question__startswith='What') |
| [<Poll: What's up?>] |
| |
| # Get the poll whose year is 2005. Of course, if you're going through this |
| # tutorial in another year, change as appropriate. |
| >>> Poll.objects.get(pub_date__year=2005) |
| <Poll: What's up?> |
| |
| >>> Poll.objects.get(id=2) |
| Traceback (most recent call last): |
| ... |
| DoesNotExist: Poll matching query does not exist. |
| |
| # Lookup by a primary key is the most common case, so Django provides a |
| # shortcut for primary-key exact lookups. |
| # The following is identical to Poll.objects.get(id=1). |
| >>> Poll.objects.get(pk=1) |
| <Poll: What's up?> |
| |
| # Make sure our custom method worked. |
| >>> p = Poll.objects.get(pk=1) |
| >>> p.was_published_today() |
| False |
| |
| # Give the Poll a couple of Choices. The create call constructs a new |
| # choice object, does the INSERT statement, adds the choice to the set |
| # of available choices and returns the new Choice object. |
| >>> p = Poll.objects.get(pk=1) |
| >>> p.choice_set.create(choice='Not much', votes=0) |
| <Choice: Not much> |
| >>> p.choice_set.create(choice='The sky', votes=0) |
| <Choice: The sky> |
| >>> c = p.choice_set.create(choice='Just hacking again', votes=0) |
| |
| # Choice objects have API access to their related Poll objects. |
| >>> c.poll |
| <Poll: What's up?> |
| |
| # And vice versa: Poll objects get access to Choice objects. |
| >>> p.choice_set.all() |
| [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
| >>> p.choice_set.count() |
| 3 |
| |
| # The API automatically follows relationships as far as you need. |
| # Use double underscores to separate relationships. |
| # This works as many levels deep as you want. There's no limit. |
| # Find all Choices for any poll whose pub_date is in 2005. |
| >>> Choice.objects.filter(poll__pub_date__year=2005) |
| [<Choice: Not much>, <Choice: The sky>, <Choice: Just hacking again>] |
| |
| # Let's delete one of the choices. Use delete() for that. |
| >>> c = p.choice_set.filter(choice__startswith='Just hacking') |
| >>> c.delete() |
| |
| For full details on the database API, see our `Database API reference`_. |
| |
| When you're comfortable with the API, read `part 2 of this tutorial`_ to get |
| Django's automatic admin working. |
| |
| .. _Database API reference: ../db_api/ |
| .. _part 2 of this tutorial: ../tutorial2/ |