Django 훑어보기¶
Django는 빠르게 변화하는 뉴스룸 환경에서 개발되었기 때문에 일반적인 웹 개발 작업을 빠르고 쉽게 수행할 수 있도록 설계되었습니다. 다음은 Django로 데이터베이스 기반 웹 앱을 작성하는 방법에 대한 알기쉬운 개요입니다.
이 문서의 목표는 Django가 어떻게 동작하는지 이해하는데 충분한 기술적 사항들을 알려주는데 있습니다. 하지만 튜토리얼이나 레퍼런스의 역할을 의도하지는 않습니다 – 물론 우리는 그 두가지를 다 가지고있죠! 프로젝트를 시작할 준비가 되었으면 튜토리얼로 시작하거나 바로 좀더 자세한 문서로 뛰어들수 있습니다.
모델 설계¶
설사 Django를 데이터베이스 없이 쓸 수 있을 지라도 데이터베이스 레이아웃을 파이썬 코드로 표현할 수 있는 object-relational mapper가 같이 딸려 옵니다.
data-model 구문은 당신의 모델을 표현할 풍부한 방법을 제공해줍니다 – 이는 지금까지 수년간 데이터베이스 스키마 문제들을 해결하는데에 많은 도움을 주어왔습니다. 아래의 간단한 예제를 보시죠.
from django.db import models
class Reporter(models.Model):
full_name = models.CharField(max_length=70)
def __str__(self):
return self.full_name
class Article(models.Model):
pub_date = models.DateField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
def __str__(self):
return self.headline
설치하기¶
다음으로, 데이터베이스를 자동으로 생성해주는 Django command-line 유틸리티를 실행하여 줍니다:
$ python manage.py makemigrations
$ python manage.py migrate
...\> py manage.py makemigrations
...\> py manage.py migrate
makemigrations
명령은 생성 가능한 모델을 찾아 테이블이 존재하지 않을 경우 마이그레이션을 생성합니다. migrate
명령은 마이그레이션을 실행하고 사용자의 데이터베이스에 테이블을 생성합니다. 이는 더욱 풍부한 스키마 제어를 선택적으로 제공합니다.
자유로운 API 즐기기¶
이것으로 자료에 접근하기 위한 자유롭고 풍부한 Python API를 얻을 수 있습니다. API는 즉석에서 만들어지며, 코드 생성이 필요하지 않습니다.
# Import the models we created from our "news" app
>>> from news.models import Article, Reporter
# No reporters are in the system yet.
>>> Reporter.objects.all()
<QuerySet []>
# Create a new Reporter.
>>> r = Reporter(full_name="John Smith")
# Save the object into the database. You have to call save() explicitly.
>>> r.save()
# Now it has an ID.
>>> r.id
1
# Now the new reporter is in the database.
>>> Reporter.objects.all()
<QuerySet [<Reporter: John Smith>]>
# Fields are represented as attributes on the Python object.
>>> r.full_name
'John Smith'
# Django provides a rich database lookup API.
>>> Reporter.objects.get(id=1)
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__startswith="John")
<Reporter: John Smith>
>>> Reporter.objects.get(full_name__contains="mith")
<Reporter: John Smith>
>>> Reporter.objects.get(id=2)
Traceback (most recent call last):
...
DoesNotExist: Reporter matching query does not exist.
# Create an article.
>>> from datetime import date
>>> a = Article(
... pub_date=date.today(), headline="Django is cool", content="Yeah.", reporter=r
... )
>>> a.save()
# Now the article is in the database.
>>> Article.objects.all()
<QuerySet [<Article: Django is cool>]>
# Article objects get API access to related Reporter objects.
>>> r = a.reporter
>>> r.full_name
'John Smith'
# And vice versa: Reporter objects get API access to Article objects.
>>> r.article_set.all()
<QuerySet [<Article: Django is cool>]>
# The API follows relationships as far as you need, performing efficient
# JOINs for you behind the scenes.
# This finds all articles by a reporter whose name starts with "John".
>>> Article.objects.filter(reporter__full_name__startswith="John")
<QuerySet [<Article: Django is cool>]>
# Change an object by altering its attributes and calling save().
>>> r.full_name = "Billy Goat"
>>> r.save()
# Delete an object with delete().
>>> r.delete()
동적인 관리자 인터페이스: 단순한 스캐폴딩이 아닙니다. 완성된 집입니다.¶
일단 모델이 정의되면 Django는 전문적이고 바로 사용할 수 있는 :doc:`administrative interface </ref/contrib/admin/index>`를 자동으로 만들 수 있습니다. 관리자 인터페이스는 인증된 사용자가 객체를 추가, 변경 및 삭제할 수 있는 웹 사이트입니다. 필요한 것은 관리자 페이지에 당신의 모델을 등록하는 것 뿐입니다.
from django.db import models
class Article(models.Model):
pub_date = models.DateField()
headline = models.CharField(max_length=200)
content = models.TextField()
reporter = models.ForeignKey(Reporter, on_delete=models.CASCADE)
from django.contrib import admin
from . import models
admin.site.register(models.Article)
사이트 수정은 직원, 고객 또는 당신에 의해 수행되며, 컨텐츠 관리만을 위해 백엔드 인터페이스를 생성할 필요는 없습니다.
Django 앱을 생성하는 하나의 전형적인 작업 흐름은 일단 모델을 만들고 관리자 사이트를 올려서 가능한 빨리 작동할 수 있게 만드는 것입니다, 그래서 당신의 운영자(혹은 고객)이 데이터 입력을 시작할 수 있게 합니다. 그러면 밖으로 데이터를 표현하는 방법을 개발합니다.
URL 설계¶
깔끔하고 우아한 URL 계획은 고품질의 웹 어플리케이션에 매우 중요한 부분입니다. Django는 아름다운 URL 설계를 장려하며 URL에 .php
나 .asp
같은 불필요한 내용들을 넣지 않습니다.
앱을 위한 URL을 설계하기 위해서 URLconf 1 파이썬 모듈을 생성해야 합니다. 이것은 당신의 앱의 목차이며, URL패턴과 Python 콜백 함수의 매핑을 포함합니다. URLconf는 Python 코드와 URL을 분리하는 역할도 합니다.
아래의 코드는 위의 Reporter
/Article
예제에 대해서 URLconf를 어떻게 쓰는지 보여줍니다:
from django.urls import path
from . import views
urlpatterns = [
path("articles/<int:year>/", views.year_archive),
path("articles/<int:year>/<int:month>/", views.month_archive),
path("articles/<int:year>/<int:month>/<int:pk>/", views.article_detail),
]
위 코드는 URL 경로들을 파이썬 콜백 함수들(“views”)로 연결해 줍니다. 경로를 나타내는 문자열들은 매개 변수 태그들을 사용하여 URL 로부터 값을 “캡처”합니다. 사용자가 페이지를 요청하면, Django 는 각 경로를 순서대로 실행하고, 요청된 URL 과 일치하는 첫번째 것에서 정지하게 됩니다. (만약 아무것도 매치하는 것이 없다면, Django 는 특수한 사례인 404 view 를 호출합니다.) 이 경로들은 로드할 때 정규표현식으로 컴파일 되어 있기 때문에 엄청나게 빠릅니다.
URL 패턴 중 하나가 일치하면 Django는 주어진 뷰를 호출합니다. 뷰는 파이썬 함수로, 각각의 뷰에는 요청 메타데이터가 포함된 요청 개체와 패턴에 잡힌 값이 전달 됩니다.
예를 들어, 사용자가 URL “/articles/2005/05/39323/”로 요청을 보냅니다, 그러면 Django는 다음처럼 함수를 호출하게 됩니다. news.views.article_detail(request, year=2005, month=5, pk=39323)
.
뷰 작성하기¶
각각의 뷰는 다음 두 가지 중 하나를 수행할 책임이 있습니다. 요청된 페이지의 내용을 담고 있는 HttpResponse
객체를 반환하거나, Http404
같은 예외를 발생시키는 것 입니다. 나머지는 여러분에게 달려있습니다.
일반적으로 뷰는 파라미터들에 따라 데이터를 가져오며 템플릿을 로드하고 템플릿을 가져온 데이타로 렌더링합니다. 아래는 위에서 만든 year_archive
에 대한 예제 뷰입니다.
from django.shortcuts import render
from .models import Article
def year_archive(request, year):
a_list = Article.objects.filter(pub_date__year=year)
context = {"year": year, "article_list": a_list}
return render(request, "news/year_archive.html", context)
이 예제는 Django의 템플릿 시스템을 사용합니다. Django 템플릿 시스템은 몇몇 강력한 기능들을 가지고 있지만 프로그래머가 아닌 사람도 사용하기에 어렵지 않도록 간결함을 유지하도록 노력하였습니다.
여러분만의 템플릿 작성¶
위의 코드는 news/year_archive.html
템플릿을 로드합니다.
장고는 여러분이 템플릿들중 중복을 최소화할 수 있게 하는 템플릿 검색 경로를 가지고 있습니다. 여러분의 장소 셋팅에 DIRS
템플릿을 확인하기 위한 디렉토리의 목록을 명시합니다. 만약 첫번째 디렉토리에 템플릿이 존재하지 않으면, 두번째 디렉토리, 그 외 디렉토리를 점검합니다.
news/year_archive.html
템플릿을 발견했다고 합시다. 아마도 이런 모양일 것입니다:
{% extends "base.html" %}
{% block title %}Articles for {{ year }}{% endblock %}
{% block content %}
<h1>Articles for {{ year }}</h1>
{% for article in article_list %}
<p>{{ article.headline }}</p>
<p>By {{ article.reporter.full_name }}</p>
<p>Published {{ article.pub_date|date:"F j, Y" }}</p>
{% endfor %}
{% endblock %}
변수는 이중 중괄호로 둘러싸입니다. {{ article.headline }}
의 뜻은 “article의 headline 속성의 값을 출력하겠다.” 입니다. 하지만 마침표가 속성의 조회에만 사용되는것은 아닙니다. 점은 사전의 키 조회에도 사용될수 있으며 인덱스 조회와 함수 호출에도 사용될 수 있습니다.
참고로 {{ article.pub_date|date:"F j, Y" }}
는 유닉스 스타일의 “파이프”(“|” 문자)를 사용한것입니다. 이 파이프는 템플릿 필터를 호출하며 이를 통해 변수의 값을 필터링 할 수 있습니다. 이 코드에서 date 필터는 파이썬의 datetime 개체를 지정한 포맷으로 변환 시킵니다.(PHP의 date 함수처럼 말이죠, 네 PHP 의 좋은 아이디어 중에 하나입니다.)
여러분은 좋아하는 여러 필터들을 함께 연결할 수 있습니다. 여러분은 커스텀 템플릿 필터를 작성할 수 있습니다. 여러분은 은밀하게 실행되는 커스텀 파이썬 코드인 커스텀 템플릿 태그를 작성할 수도 있습니다.
이제 마지막으로 Django의 “템플릿 상속” 개념을 사용해 보죠. 이를 통해 {% extends "base.html" %}
코드가 무슨 일을 하는지 알 수 있습니다. 이 코드의 의미는 ”한 뭉치의 block들이 정의된 ‘base’라는 템플릿을 먼저 로드하고 뒤따르는 block들로 이 block들을 채운다는것”입니다. 간단히 말해 템플릿 안의 중복을 극적으로 낮추게 합니다. 각각의 템플릿은 자신이 표현하려는 내용들만 정의할 수 있게 되기 때문입니다.
“base.html” 템플릿은 정적 파일의 사용을 포함하여, 다음과 같이 보일 것입니다.
{% load static %}
<html>
<head>
<title>{% block title %}{% endblock %}</title>
</head>
<body>
<img src="{% static 'images/sitelogo.png' %}" alt="Logo">
{% block content %}{% endblock %}
</body>
</html>
간단하게 사이트의 look-and-feel(사이트의 로고)을 정의하고 하위 템플릿이 채울 수 있는 “구멍”들을 제공합니다. 이 방식은 base template 라는 단일 파일을 변경하여 사이트를 재설계할 수 있습니다.
또한 하위 템플릿을 재사용하면서 서로 다른 base 템플릿을으로 여러 버전의 사이트를 생성할 수 있습니다. Django의 제작자들은 이 기술을 사용하여 단순히 새로운 base 템플릿을 만듦으로써 완전히 다른 모바일 버전의 사이트를 만들었습니다.
여러분이 선호하는 템플릿 시스템이 있다면 꼭 Django의 템플릿 시스템을 사용할 필요는 없습니다. Django의 템플릿 시스템은 Django의 모델계층과 매우 잘 통합되어 있지만 꼭 이를 사용하도록 강제하는 것은 아닙니다. 이러한 이유들로 Django의 데이터베이스 API 역시 반드시 써야 할 필요는 없습니다. 여러분은 다른 데이터베이스 추상화 계층을 사용할수 있으며 XML 파일이나 디스크에서 다른 파일을 사용하거나 여러분이 원하는 다른 여러가지 방식으로 사용할수도 있습니다. 각각의 Django 구성요소들 – 모델, 뷰, 템플릿 – 은 서로 결합도가 낮게 되어있습니다.
이건 단지 껍데기일 뿐¶
이건 Django의 기능에 대한 간략한 개요에 불과합니다. 다음과 같이 좀 더 유용한 기능들도 많습니다.
- memached나 기타 백엔드와 통합된 캐시 프레임워크.
- Python 클래스를 약간만 작성해도 RSS 및 Atom 피드를 만들어주는 syndication framework
- 이보다 더 매력적인 자동생성 관리자 기능 – 이 개요는 극히 일부만 다루었습니다.
다음 단계는 Django`_를 다운로드하고 :doc:`the tutorial </intro/tutorial01> 를 읽고 `the community`_에 가입하는 것입니다. 여러분의 관심에 감사드립니다.