[01]Django를 이용한 웹프로그래밍
1. Django Framework
- Django는 파이썬으로 만들어진 무료 오픈소스 웹 어플리케이션 프레임워크
- 쉽고 빠르게 웹사이트를 개발할 수 있도록 돕는 구성요소로 이루어진
웹 프레임워크.
- 공통모듈에 해당하는 회원가입, 로그인, 로그아웃과 같이 사용자 인증을 다루는 방법이나
웹사이트의 관리자 패널, 폼, 파일 업로드와 같은 것등 새로운 웹 사이트를 개발할 때
바로 사용할 수 있는 구성요소들을 갖춘 프레임워크
- 새로운 웹사이트를 개발할 때 뒤따르는 간접비용의 부담을 덜어준다.
- 새로운 request의 url은 urlresolver에서 처리할 model를 거쳐 보여줄 view를 검색하여
브라우저에 response된다.
2. Django 설치
1) 가상환경: Django Framework의 버전이 달라지면 생성된 애플리케이션에 또한 영향을
미치므로 가상환경을 이용하여 Python/Django를 설치할것을 권장함.
- 프로젝트 기초 전부를 Python/Django와 분리시켜준다. 웹사이트가 변경되어도
개발 중인 것에 영향을 미치지 않다는 것입니다. (생략가능)
2) Python 설치
- 다운:https://www.python.org/downloads/
- 2.7.X or 3.5.X 버전 선택
- C:\Python27
- 시스템 환경변수설정
- path=C:\Python27;~
- cmd에서 python --version 으로 설치확인
3) Django 설치
- 다운:https://www.djangoproject.com/download/
- 1.9 or 1.10 버전선택
- 압축풀기: tar.gz 파일 압축풀고 설치
C:\Django-1.9.9
- 설치:cmd에서 설치폴더로 이동후 python setup.py install
- C:\Django-1.9.9\django\bin\django-admin.py 파일을
파이썬 설치폴더 C:\Python27로 이동
- C:\Django-1.9.9폴더 삭제해도 됨
- cmd에서 django-admin.py --version 설치확인
4) Django 프로젝트 생성후 Helloword 브라우저로 출력
- New Project -> PyDev -> PyDev Django project
- 프로젝트명:web_python
- Django server 실행 -> 브라우저에서 확인
- Helloworld 출력하기 위한 새로운 application 생성
- web_python 우클릭-> Django -> Create application(manage.py startapp)
- web_python -> web_python(패키지)-> setting.py
- Time-Zone내용변경 및 Static_Root 경로 설정(css 경로설정을 위해)
"""
Django settings for web_python project.
Generated by 'django-admin startproject' using Django 1.9.9.
For more information on this file, see
https://docs.djangoproject.com/en/1.9/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.9/ref/settings/
"""
import os
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '*=6ck#5l((0++(5k$!mfsl_lye90)er*^pb0ovac!!gb+d%=4r'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'web_python.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
WSGI_APPLICATION = 'web_python.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'static')
- web_python -> web_python(패키지)-> urls.py
- 아래 url의 Helloworld는 application 명과 같아야 함.
url(r'^Helloworld/', include('Helloworld.urls')),
"""web_python URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.9/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url ,include
from django.contrib import admin
urlpatterns = [
url(r'^Helloworld/', include('Helloworld.urls')),
url(r'^admin/', admin.site.urls),
]
- Helloworld(패키지)-> urls.py 생성
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
]
- Helloworld(패키지)-> views.py 아래내용으로 변경
from django.http import HttpResponse
# Create your views here.
def index(request):
return HttpResponse("Hello, world. Let's Django!!")
- Django 서버실행후 브라우저에서 http://127.0.0.1:8000/Helloworld 확인
3. web_python 프로젝트에 blog 애플리케이션 만들기
- blog에 글목록/글상세
- sqlite3을 이용해서 ORM 사용(sql문이 전혀사용안함) - 오브젝트 릴레이티드 매핑
1) Django -> Create application (manage.py startapp)-> blog
- web_python/settings.py 33Line~41Line 쯤 blog 추가
:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
]
:
2) Django Model 정의 : blog/models.py에 아래 코드 저장
- 장고 안의 모델은 객체의 특별한 종류이다.
- 이 모델을 저장하면 그 내용이 데이터베이스에 저장되는 것이 특별한 점이다.
- 블로그 글을 위한 장고 모델을 만든다.
from django.db import models
from django.utils import timezone
class Post(models.Model):
author = models.ForeignKey('auth.User')
title = models.CharField(max_length=200) - 좀 작은 내용
text = models.TextField() - 얘는 좀 큰 내용
created_date = models.DateTimeField(
default=timezone.now)
published_date = models.DateTimeField(
blank=True, null=True)
def publish(self):
self.published_date = timezone.now()
self.save()
def __str__(self):
return self.title
- models.Model은 Post가 장고 모델임을 의미함
- 이 코드 때문에 Post가 데이터베이스에 저장 된다.
- title, text, created_date, published_date, author속성을 정의함. - 컬럼에 연관되는 필드 같은 것
- 각 필드마다 데이터 타입은 텍스트, 숫자, 날짜, 유저 등이 있다.
- models.CharField - 글자 수가 제한된 텍스트를 정의할 때 사용한다.
글 제목같이 대부분의 짧은 문자열 정보를 저장할 때 사용한다.
- models.TextField - 글자 수에 제한이 없는 긴 텍스트를 위한 속성이다.
블로그 콘텐츠등
- models.DateTimeField - 이것은 날짜와 시간을 나타냄
- models.ForeignKey - 다른 모델에 대한 참조를 의미한다.
3)데이터베이스에 모델을 위한 테이블 만들기
- 데이터베이스에 우리의 새 모델, Post 모델을 추가한다.
- 장고는 데이터베이스에 바로 반영할 수 있도록 마이그레이션 파일
(migration file)을 준비하고 있다.
- eclipse : web_python->Django->Make migrations .....
- 실제 데이터베이스에 모델 추가를 반영한다.
- eclipse : web_python->Django->Migrate .....
4) Django 관리자로 글추가/수정/삭제
- 조금전 모델링한 글들을 장고 관리자에서 추가,수정,삭제할 수 있다.
- blog/admin.py 파일을 열어서 내용을 다음과 같이 바꿈
from django.contrib import admin
from .models import Post
admin.site.register(Post)
- 앞에서 정의했던 Post 모델을 가져오고(import) 있다.
- 관리자 페이지에서 만든 모델을 보려면 admin.site.register(Post)
로 모델을 등록해야한다.
- python manage.py runserver 실행후
- 브라우저에서 http://127.0.0.1:8000/admin/ 입력후 로그인창 확인
- 로그인을 위해서 모든 권한을 가지는 슈퍼유저(superuser)를 생성해야함.
- 커맨드라인에서 python manage.py createsuperuser을 입력후,
사용자 이름 (소문자, 공백 없이), 이메일 주소 및 암호를 입력한다.
username : blog
email : blog@blog.com
password : blog1234
- python manage.py runserver 실행후 다시 브라우저에서
http://127.0.0.1:8000/admin/ 입력후 로그인후 몇개의 글등록를 함.
5) Django의 URL과 정규표현식
- 어플리케이션은 URL을 입력한 사용자에게 어떤 내용을 보여줘야한다.
- 장고는 URLconf (URL configuration)를 사용하며, URLconf는
장고에서 URL과 일치하는 뷰를 찾기 위한 패턴들의 집합이다.
- web_python/urls.py파일을 열면 아래와 같다.
from django.conf.urls import url ,include
from django.contrib import admin
urlpatterns = [
url(r'^Helloworld/', include('Helloworld.urls')),
url(r'^admin/', admin.site.urls),
]
- admin/ 또는 Helloworld/로 시작하는 모든 URL을 장고가 view와
대조해 찾아낸다는 뜻.
- 이때 사용한것이 정규표현식이다.
^ 문자열이 시작할 ?
$ 문자열이 끝날 때
\d 숫자
+ 바로 앞에 나오는 항목이 계속 나올 때
() 패턴의 부분을 저장할 때
- web_python/urls.py에 다음 url를 추가함.
url(r'', include('blog.urls')),
의미는 http://127.0.0.1:8000 요청될때 blog.urls를 참조함.
from django.conf.urls import url ,include
from django.contrib import admin
urlpatterns = [
url(r'^Helloworld/', include('Helloworld.urls')),
url(r'^admin/', admin.site.urls),
url(r'', include('blog.urls')),
]
- blog/urls.py 파일 생성 하여 다음 작성
- 'http://127.0.0.1:8000/' 요청하면 views.post_list를 보여줌
- views가 없어서 오류남.
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
]
6) Django의 뷰 만들기
- blog/views.py에 다음 작성.
- post_list메서드는 요청(request)을 넘겨받아 render 메서드를 호출.
render 메서드는 넘겨진 요청(request)과 blog/post_list.html
페이지를 받아 그 내용이 브라우저에 보여지게 된다.
from django.shortcuts import render
# Create your views here.
def post_list(request):
return render(request, 'blog/post_list.html', {})
- 브라우저에 보여줄 파일은 templates폴더안 애플리케이션이름과 동일한
blog폴더안에 생성함.
- blog/template/blog/post_list.html 작성
- python manage.py runserver 실행후 http://127.0.0.1:8000 확인
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>
<h1><a href="">Django Girls Blog</a></h1>
</div>
<div>
<p>published: 14.06.2014, 12:14</p>
<h2><a href="">My first post</a></h2>
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
</div>
<div>
<p>published: 14.06.2014, 12:14</p>
<h2><a href="">My second post</a></h2>
<p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut f.</p>
</div>
</body>
</html>
7) Django ORM과 QuerySets
- Django 데이터베이스 처리는 sql문이 없이 ORM방식으로 처리함.
- QuerySets은 전달받은 모델의 객체 목록이다.
쿼리셋은 데이터베이스로부터 데이터를 읽고, 필터를 걸거나 정렬한다.
- Django shell에서 확인
cmd -> python manage.py shell
eclipse -> web_python -> Django -> Shell with django environment
#포스팅된 글 모두 읽어오기
from blog.models import Post
Post.objects.all()
[<Post: test>, <Post: test>]
#등록된 계정 모두 읽어오기
User.objects.all()
[<User: blog>, <User: clare>]
#me 변수에 계정하나를 등록
me = User.objects.get(username='blog')
#새로운 글을 포스팅함
Post.objects.create(author=me, title='Sample title', text='Test')
<Post: Sample title>
#다시 모두 보여주기
Post.objects.all()
[<Post: test>, <Post: test>, <Post: Sample title>]
#필터링하기
- 예를 들어, 우리는 blog라는 User가 작성한 모든 글을 검색을 할때
이런 경우 Post.objects.all()에서 all 대신, filter를 사용한다.
author=me를 사용한다.
Post.objects.filter(author=me)
[<Post: test>, <Post: Sample title>]
#모든 글들 중, 제목(title)에 'title'이라는 글자를 포함한 것만
Post.objects.filter( title__contains='title' )
[<Post: Sample title>]
#오늘날짜 이전에 작성된 글모여주기
from django.utils import timezone
Post.objects.filter(published_date__lte=timezone.now())
[<Post: test>, <Post: test>,<Post: Sample title>]
#바로전 작성된 글이 안보이면(생략가능)
post = Post.objects.get(title="Sample title")
post.publish()
Post.objects.filter(published_date__lte=timezone.now())
[<Post: test>, <Post: test>, <Post: Sample title>]
#정렬 (글생성될때 빠른 날짜순)
Post.objects.order_by('created_date')
[<Post: test>, <Post: test>, <Post: Sample title>]
#정렬(-는 역순)
Post.objects.order_by('-created_date')
[<Post: Sample title>, <Post: test>, <Post: test>]
#필터및 정렬
Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
[<Post: test>, <Post: test>, <Post: Sample title>]
8) 데이터베이스 내용 views페이지에 보여주기
- blog/views.py 에 작성
- posts 쿼리셋을 처리해서 views에 보낸다.
from django.shortcuts import render
from django.utils import timezone
from .models import Post
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
- blog/templates/blog/post_list.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>
<h1><a href="/">Python Django Blog</a></h1>
</div>
{% for post in posts %}
<div>
<p>published: {{ post.published_date }}</p>
<h1><a href="">{{ post.title }}</a></h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
</body>
</html>
- blog/static/css/blog.css 생성
- Django는 app폴더 안에 있는 "static" 폴더를 자동으로 찾아 안에 있는
내용을 인식함.
.page-header {
background-color: #ff9400;
margin-top: 0;
padding: 20px 20px 20px 40px;
}
.page-header h1, .page-header h1 a, .page-header h1 a:visited, .page-header h1 a:active {
color: #ffffff;
font-size: 36pt;
text-decoration: none;
}
.content {
margin-left: 40px;
}
h1, h2, h3, h4 {
font-family: 'Lobster', cursive;
}
.date {
float: right;
color: #828282;
}
.save {
float: right;
}
.post-form textarea, .post-form input {
width: 100%;
}
.top-menu, .top-menu:hover, .top-menu:visited {
color: #ffffff;
float: right;
font-size: 26pt;
margin-right: 20px;
}
.post {
margin-bottom: 70px;
}
.post h1 a, .post h1 a:visited {
color: #000000;
}
- blog/templates/blog/post_list.html css 및 bootstrap
적용으로 변경
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Python Django Blog/title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="{% static 'css/blog.css' %}">
</head>
<body>
<div class="page-header">
<h1><a href="/">Python Django Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% for post in posts %}
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h1><a href="">{{ post.title }}</a></h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
</div>
</div>
</div>
<body>
- 기본 템플릿 페이지 만들기
- blog/teamplates/blog/base.html 생성
{% load staticfiles %}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Python Django Blog</title>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="{% static 'css/blog.css' %}">
</head>
<body>
<div class="page-header">
<h1><a href="/">Python Django Blog</a></h1>
</div>
<div class="content container">
<div class="row">
<div class="col-md-8">
{% block content %}
{% endblock %}
</div>
</div>
</div>
<body>
- blog/post_list.html 기본템플릿을 적용하여 변경
{% extends 'blog/base.html' %}
{% block content %}
{% for post in posts %}
<div class="post">
<div class="date">
{{ post.published_date }}
</div>
<h1><a href="">{{ post.title }}</a></h1>
<p>{{ post.text|linebreaksbr }}</p>
</div>
{% endfor %}
{% endblock content %}
<body>
- post_list.html 페이지 링크걸기
- 상세페이지로 연결하는 링크 만들기
<h1><a href="{% url 'post_detail' pk=post.pk %}">{{ post.title }}</a></h1>
- {% %} 표기는 장고 템플릿 태그를 말함.
- 요청 URL에 blog.views.post_detail는 post_detail view 이다.
- views는 views.py 파일의 이름에서 나온 것이며,
post_detail는 view 의 이름이다.
- blog/urls/py에 views.post_detail를 추가
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.post_list, name='post_list'),
url(r'^post/(?P<pk>[0-9]+)/$', views.post_detail, name='post_detail'),
]
^post/(?P<pk>[0-9]+)/$ 의미
^은 "시작"이란 뜻 첫 부분 다음부터 나오는 post/는 URL이 post를
포함해야한다는 뜻이다.
(?P<pk>[0-9]+) 이 정규 표현식의 의미는 파라메터를 pk변수에 담아
뷰로 전송하겠다는 뜻이다.
[0-9]은 문자를 제외하고, 숫자 0부터 9까지 하나의 숫자란 뜻이며,
+는 하나 또는 그 이상의 숫자가 와야한다는 것을 의미한다.
/은 다음에 / 가 한번 더 와야 한다는 의미이다.
$은 그 뒤로 더이상 문자가 오면 안된다.
- http://127.0.0.1:8000/post/5/입력하면, 장고는 post_detail인
view 를 찾으며 pk변수에 5를담아 view 로 정보를 보낸다
- blog/views.py 추가
from django.shortcuts import render
from django.utils import timezone
from .models import Post
from django.shortcuts import render, get_object_or_404
def post_list(request):
posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date')
return render(request, 'blog/post_list.html', {'posts': posts})
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
return render(request, 'blog/post_detail.html', {'post': post})
- blog/templates/blog/post_detail.html 생성후 작성
- 서버실행후 브라우저에서 확인