Code


Version 2 (modified by graphittie, 5 years ago) (diff)

--

장고 도움말 페이지로 가기

Django 어플리케이션 따라하기, 파트 1

예제를 통해 Django를 배워보도록 합시다.

이 튜토리얼은 간단한 설문조사 애플리케이션을 만들면서 진행하게 됩니다.

설문조사 애플리케이션은 두 가지 부분으로 이루어 집니다:

  • 사용자들이 설문을 보고 설문에 참여하는 공개된 사이트
  • 관리자가 설문을 추가,삭제,수정할 수 있는 관리자 사이트

이미 Django가 설치되어 있다는 가정하에 진행하도록 하겠습니다. Django의 설치 여부 는 를 알기 위해 파이썬 인터프리터 쉘을 실행시킨 후 import django를 입력합니다. 입력한 명령이 에러 없이 성공적으로 수행될 경우, Django가 성공적으로 설치된 것입니다.

프로젝트 생성하기

Django를 처음 사용하시는 것이라면, 처음 설정에 주의를 기울여야 합니다. 즉, Django *프로젝트*를 위해 필요한 몇몇 파일들을 자동으로 생성해야 합니다. 여기서 프로젝트란, Django 프로젝트를 구성하는 설정( 데이터베이스 설정, Django에 특화된 옵션들과 각각의 애플리케이션의 설정 ) 으로 이루어진 파일들을 말합니다.

명령줄에서 여러분의 프로그램을 저장하고자 하는 디렉토리로 cd명령을 이용하여 이동합니다. 그리고 django-admin.py startproject mysite라는 명령을 입력합니다. 이 명령은 mysite라는 디렉토리를 현재 디렉토리 아래에 생성합니다.

(Django를 python setup.py를 통해 설치했다면 django-admin.py 는 여러분의 시스템 경로에 있을 것 입니다. 만약에 없다면 site-packages/django/bin에서 찾을 수 있을 것입니다. site-packages는 여러분이 파이썬을 설치한 경로에 있는 디렉토리를 말합니다. django-admin.py를 여러분의 path설정에 있는 어딘가, 예를 들어 /usr/local/bin 같은 곳에 심볼릭 링크를 만들어 두는 것도 좋은 방법 입니다.)

어디에 코드를 두어야 하나요?

만약 PHP를 사용하셨다면 보통 웹서버의 document root (/var/www 등의 경로)에 여러분의 코드를 두었을 것입니다. Django에서는 그렇게 할 필요가 없습니다. 이 파이썬 코드들을 당신의 웹서버의 document root에 두는 것은 제3자가 여러분의 코드를 웹에서 볼 수 있는 위험이 존재하므로 보안을 생각한다면 좋은 방법이 아닙니다.

당신의 코드를 /home/mycode 같은 document root 밖에 보관하는 것을 추천합니다.

startproject가 무엇을 생성했는지 봅시다:

mysite/
    __init__.py
    manage.py
    settings.py
    urls.py

이 파일들은 다음과 같은 역할을 합니다:

  • __init__.py: 파이썬에게 이 디렉토리를 파이썬 패키지로 해석하도록 지시하기 위한 비어있는 파일입니다. ( 파이썬 초보자라면 파이썬 공신 문서에 있는 more about packages 를 읽어보세요. )
  • manage.py: 다양한 방법으로 Django 프로젝트를 관리할 수 있게 하는 명령줄 유틸리티 입니다.
  • settings.py: 이 Django 프로젝트의 설정입니다.
  • urls.py: 이 Django 프로젝트에서 사용할 URL 설정을 담고 있습니다; 여러분이 Django로 만든 사이트의 목차이기도 합니다.

개발용 서버

제대로 동작하는지 확인해 보도록 합니다. mysite 디렉토리로 들어간 뒤, python manage.py runserver를 실행해봅시다. 명령줄에 다음과 같은 결과를 보게 될 것입니다.

    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).

여러분은 순수하게 파이썬만으로 쓰여진 간단한 Django 개발용 웹서버를 실행했습니다. Apache 같은 큰 복잡한 웹서버 설정을 하지 않고도 여러분이 Django로 빠르게 개발을 시작할 수 있도록 돕기 위해 간단한 웹서버를 Django에 포합시켰습니다.

이 사항을 항상 염두에 두세요: 이 서버를 여러분의 어플리케이션을 실제로 출시할 때는 사용하지 않도록 하시기 바랍니다. 이것은 단지 개발하는 과정에서 사용되도록 의도된 것입니다. ( 우리는 웹 프레임워크를 만들지, 웹 서버를 만들지는 않습니다. )

이제 서버가 실행되는 동안은, http://127.0.0.1:8000/ 을 여러분의 웹브라우저를 통해 방문할 수 있습니다. 하늘색으로 쓰여진 "Welcome to Django" 페이지를 보게 된다면 제대로 동작하는 것입니다.

포트 변경하기

기본적으로, runserver 명령은 8000번 포트에 개발 서버를 실행합니다. 이 포트를 바꾸고 싶다면, 명령줄 인자에 포트 번호를 넘겨주면 됩니다. 예를 들어서, 8080포트에서 실행하고 싶다면 :

python manage.py runserver 8080

개발용 서버에 대한 자세한 설명을 보려면 django-admin documentation을 참고하세요.

데이터베이스 설정

이제 settings.py를 수정하도록 합시다. 이것은 Django 세팅을 표현하기 위한 모듈 레벨의 변수들이 있는 일반적인 Python 모듈입니다. 여러분의 데이터베이스 연결 매개변수와 일치하도록 다음을 참고하여 이 세팅을 변경하세요.

  • DATABASE_ENGINE - 'postgresql', 'mysql' 또는 'sqlite3'. 앞으로 더 지원될 것입니다.
  • DATABASE_NAME - 데이터베이스 명 또는 SQLit 사용시에는 데이터베이스 파일의 (절대)경로.
  • DATABASE_USER - (SQLite를 사용하지 않을 경우) 데이터베이스 사용자명.
  • DATABASE_PASSWORD - (SQLite를 사용하지 않을 경우) 데이터베이스 비밀번호.
  • DATABASE_HOST - 데이터베이스가 돌아가는 호스트. (SQLite를 사용하지 않는 경우) 데이터베이스 서버가 물리적으로 같은 서버에서 돌아가고 있다면 빈 문자열로 남겨놓으십시오.
메모

PostgreSQL이나 MySQL을 사용하신다면, 반드시 데이터베이스의 명령 프롬프트(interactive prompt)에 CREATE DATABASE database_name;를 입력하여 데이터베이스를 생성해야 합니다.

settings.py을 편집하고 계신다면, 파일의 밑 부분에 있는 INSTALLED_APPS 세팅에 주목하십시오. 이 변수는 이 Django 인스턴스에서 활성화된 모든 Django 어플리케이션명을 담고 있습니다.

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.

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.

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.

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.

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.

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.

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.
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.