2016년 1월 23일 토요일

Django 요약

예제로 배우는 python 프로그래밍 (Django 기초: http://pythonstudy.xyz/Python/Django)

Django 소개
-----------
Django는 웹어플프레임웍(web app framework)의 하나이다. 파이썬으로 개발되었고 오픈소스이다.

가상 환경 구축
----------------
Django 설치
-----------
>pip install django
>pip install django=1.8 #특정버전 지정

Django 프로젝트 생성과 실행
---------------
>django-admin startproject myweb #새 프로젝 만듬
>python manage.py runserver #서버 실행
서버실행 시 127.0.0.1:8000 또는 8080에 접속.

Django App
----------
프로젝 하에 위치하며, 하나의 프로젝은 여러개 App을 포함할 수 있다. 잘 모듈화된 App은 여러 프로젝에서 재 사용 가능.
>manage.py startapp home # home이라는 새 App생성

views.py는 html 웹을 호출하는 역할을 한다.
간단하게 화면에 글자를 출력해 보자.

from django.shortcuts import render
from django.http import HttpResponse

# Create your views here.
def index(request):
    return HttpResponse("Hello, World!")

01.settings.py: INSTALLED_APPS 리스트에 App 추가
02.urls.py: urlpatterns 리스트에 사용할 URL 패턴 추가. 또 ^는 시작, $는 끝이므로 빈 문자열, 즉, 루트를 가리킴.


Django 뷰
---------
보통 GUI는 MVC framework인데 여기서는 MTV이다. (Model,View, Controller) == (Model, Templates, View)
장고 뷰는 HTTP Request를 받아, HTTP Response를 리턴.
Request에는 (문서) Model 데이터가 들어 있으며, Response에서는 Template html을 생성하거나 호출.


Django 템플릿
-------------
View에서 이쪽으로 전달된 데이터를 받아, 동적인 웹페이지를 만든다.
App폴더 아래에 templates 폴더 만들고 그아래 html을 위치.
여러개의 App이 한 프로젝 아래에 있는 경우에는

"App폴더/templates/App명/템플릿파일"

로 한다. 복수의 App들이 동일 이름 템플릿을 가진 경우에 대비: 템플릿을 찾을 때, 자신 App아래 템플릿을 먼저 찾는 것이 아니라, 전체 App들 템플릿 폴더들을 처음부터 순서대로 찾는다.

from django.shortcuts import render

def index(request):
    msg = 'My Message'
    return render(request, 'index.html', {'message': msg})

render함수는 index.html을 호출하며, 세번째 파라메터는 dict형태로 넘겨줌.

(템플릿 언어)
.변수: {{ }}로 둘러싸이면 변수 값이 이 위치에 치환.
.템플릿 태그: {%...%}. if, for와 같은 python명령이 내부에 온다.
{% if count > 0 %}
    Data Count = {{ count }}
{% else %}
    No Data
{% endif %}

{% for item in dataList %}
  <li>{{ item.name }}</li>
{% endfor %}

{% csrf_token %} # 해킹 공격에 대응

.템플릿 필터: 변수값을 특정 포맷으로 변형.
날짜 포맷 지정
{{ createDate|date:"Y-m-d" }}

소문자로 변경
{{ lastName|lower }}

.템플릿에서 주석
싱글 라인: {#...#}
여러 라인: {% comment %} ... {% endcomment %}



Django 모델
-----------
필드 타입: CharField, TextField, FileField, ...
ImageField(FileField의 파생클래스로 이미지 파일인지 체크)

  필드 옵션      설명
.null (Field.null): Empty 값을 DB에 NULL로 저장. DB에 Null 허용.
                    예: models.IntegerField(null=True)
.blank (Field.blank): blank=False(Required 필드). blank=True(Optional 필드).
                   예: models.DateTimeField(blank=True)
.primary_key(Field.primary_key): 해당 필드가 Primary Key.
            예: models.CharField(max_length=10, primary_key=True)
.unique (Field.unique): 해당 필드가 테이블에서 Unique함 표시. 해당 컬럼에 대해 Unique Index를 생성.
             예: models.IntegerField(unique=True)
.default (Field.default): 필드 디폴트값을 지정.
            예: models.CharField(max_length=2, default="WA")
.db_column (Field.db_column): 컬럼명은 디폴트로 필드명을 사용하는데, 만약 다르게 쓸 경우 지정한다.



DB 설정과 Migration
-------------------
Model클래스 생성 후, 해당 모델 테이블(틀)을 DB에 생성 가능.
> manage.py makemigrations # migration을 준비하는 과정. 스키마 생성 또는 수정. App내에 migrations서브폴더 생성.
> manage.py migrate # migration을 DB에 적용하는 과정
migrate후에 생기는 파일 명: App명_ModelClass명

DB 관리 쉘
> manage.py dbshell #테이블, 컬럼정보, 테이블 내용 확인 가능
sqlite> .tables #테이블 리스트 출력
sqlite> PRAGMA table_info(리스트중하나) # 테이블 컬럼정보
sqlite> select * from 리스트중하나 # (이미 입력 저장된) 테이블 데이터



Django 모델 API
---------------
일단 모델 클래스가 정의되면 장고는 데이터추가, 갱신에 관련된 다양한 API를 제공

(INSERT)
from feedback.models import *  # feedback(App명)/models.py
from datetime import datetime

# Feedback 객체 생성
fb = Feedback(name = 'Kim', email = 'kim@test.com', comment='Hi', createDate=datetime.now())

# 새 객체 INSERT
fb.save()

(SELECT)
장고는 모델 클래스에 objects라는 관리 객체를 자동 추가해 줌. 이를 통해 여러 제어 가능.
"모델클래스명.objects"로 사용함.
all(): 테이블 데이터 전부 가져옴
for f in Feedback.objects.all():
    s += str(f.id) + ' : ' + f.name + '\n'

get(): 하나의 row만 가져옴. pk(primary key)를 사용.
row = Feedback.objects.get(pk=1)
print(row.name)

filter(): 특정조건에 맞는 row가져옴
rows = Feedback.objects.filter(name='Kim')

exclude(): 특정 조건을 제외한 나머지 row가져옴
rows = Feedback.objects.exclude(name='Kim')

count(): 데이터 갯수
n = Feedback.objects.count()

order_by(): 키를 따라 정렬. -는 내림차순.
rows = Feedback.objects.order_by('id', '-createData') #id를 기준으로 올림차순, createData를 기준으로 내림차순 정렬

distinct(): 중복 시 하나만 표시.
rows = Feedback.objects.distinct('name')

first(): 처음 row만 리턴.
rows = Feedback.objects.order_by('name').first() #정렬 후 첫 요소 리턴

last(): 마지막 row 리턴
rows = Feedback.objects.order_by('name').last()

체인연결 가능
row = Feedback.objects.filter(name='Kim').order_by('-id').first()


(UPDATE)
수정할 객체 얻고 변경 필드 수정. 다시 저장.
fb = Feedback.objects.get(pk=1)
fb.name = 'Park'
fb.save()

(DELETE)
대상 row얻은 후 delete호출
fb = Feedback.objects.get(pk=2)
fb.delete()



URL 매핑
--------
어떤 프로젝 아래에 App이 여러개일 때, proj 아래 urls.py 파일에 각 App의 urls.py를 매핑하면 편리.

myWeb/urls.py
urlpatterns = [
   ...
   url(r'^feedback/', include('feedback.urls')), #'feedback/': App별 기준 url위치.
   url(r'^home/', include('home.urls')),
]

# home/urls.py
from django.conf.urls import url
from home import views

urlpatterns = [
    url(r'^contact', views.contact), #url: /home/contact, 함수:home.views.contact
    url(r'^about', views.about),
]

# feedback/urls.py
from django.conf.urls import url
from feedback import views

urlpatterns = [
    url(r'^list', views.list), #url: /feedback/list, 함수:feedback.views.list
    url(r'^add', views.add),
    url(r'^update', views.update),
]


RegEx사용. r'정규표현식'형식이고, 앞에 r(raw) prepix붙임. ^로 시작.

(..): Capture 표현. 일부 문자열 추출.

url(r'^blogs/([0-9]{4})/([0-9]{2})/$$', views.blogs_month)  #4개/2개 추출
만약 입력 URL이 "/blogs/2015/12" 이면, 이 URL은 views.blogs_month(request, '2015', '12') 과 같이 함수를 호출

Named Group:  (?P<그룹이름>pattern). 캡춰한 것에 이름붙여 전달.
url(r'^blogs/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.blogs_month)
입력 URL이 "/blogs/2015/12" 이면, 이 URL은 views.blogs_month(request, year='2015', month='12') 과 같이 함수를 호출


템플릿 확장
-----------
아래 두 파일 경우, 일단 base.html이라는 파일을 생성하고, 이 내부에서 block위치를 찾는다. 그리고, 그 위치에 index.html에 있는
<h1>{{message}}</h1>
을 치환한다.


(base.html)
<!DOCTYPE html>
<html lang="en">
<head>
     ...
</head>
<body>
     ....
     {% block content %}   # 삭제 후 index.html에 있는
     {% endblock content %} # <h1>{{message}}</h1> 부분 대입

</body>
</html>


(index.html)
{% extends "base.html" %} #첫 라인에 base.html 추가

{% block content %}
    <h1>{{message}}</h1>
{% endblock content %}



Django 폼(form)
---------------
모델 클래스로부터 폼을 자동으로 생성하는 기능.

from django.forms import ModelForm
from .models import Feedback

class FeedbackForm(ModelForm):
    class Meta:
        model = Feedback
        fields = ['id', 'name','email','comment'] #모델 필드중 일부만 폼에서 사용.



이렇게 정의 후, 뷰에서 이 폼을 사용한다.

from django.shortcuts import render, redirect
from .models import *
from .forms import FeedbackForm

def create(request):
    if request.method=='POST': # 뭐가 전달되는지 모르지만 어떤 객체가 전달된 경우를 표현
        form = FeedbackForm(request.POST) #사용자가 입력한 것을 인자로 넘겨줘서 폼 생성.
        if form.is_valid():
            form.save()
        return redirect('/feedback/list') #urls.py의 urlpatterns을 통해 view함수 호출.
    else:
        form = FeedbackForm()

    return render(request, 'feedback.html', {'form': form}) #세번째 인자는 dict()

위 코드는
. 데이터를 입력받을 폼을 보여주는 부분
. 사용자가 데이터 입력하여 저장 버턴 클릭 시, 이를 DB에 저장하는 부분.
. view에서 html로 form을 전달하였다. 그래서, 아래 html에서 이를 랜드링.

{% extends "base.html" %}
{% block content %}
    <p>
        <a href="{% url 'list' %}">Goto Feedback List</a>
    </p>

    <div>
        <form method="POST"> # 뷰에서 form을 넘겨주었었다.
            {% csrf_token %}
            {{ form.as_p }} #p태그(paragraph), 즉 새 문단으로 form 연다.
            <button type="submit">저장</button>
        </form>
   </div>
{% endblock content %}



Static 파일
-----------
장고홈(settings.py 내 BASE_DIR) 아래에 static 폴더를 만들어 js, css, image 등 웹에서 사용하는 파일 저장:
STATIC_URL = '/static/' #웹에서 주소로 살펴볼 때
STATICFILES_DIRS=[os.path.join(BASE_DIR, 'static'),]

.html에서 static 파일 사용 시는 템플릿 상단에
{% load staticfiles%}
를 명시하고, 실제 static file을 가리키기 위해서는 link태그로 지정.
{% static 'bootstrap/css/bootstrap.min.css' %}

.배포(deploy) 시에는 각 App의 static 폴더 아래 파일을 그대로 복사하므로 이름 충돌을 피하기 위해 다음 처럼 한다:
 -App명/static/App명 #각 App하의 static 폴더명 지정 시.
 -settings.py에 다음 지정.
  STATIC_ROOT = '/var/www/myweb_static' #배포용 web 경로하의 static 폴더.

  STATICFILES_FINDERS = (
     'django.contrib.staticfiles.finders.FileSystemFinder',
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
  )


.collectstatic
배포 시 흩어져 있는 static 파일 들을 모아 특정 폴더로 옮기는데, 이 때,
'manage.py collectstatic' 실행.


샘플 Feedback App
-----------
Site Deployment (Nginx)
-----------
Site Deployment (Apache)
-----------
Django 디버깅


[참고]
1. Django 기초.











댓글 없음:

댓글 쓰기