본문 바로가기
프로그래밍 놀이터/Script(Python)

[Django] 파이썬 웹 프로그래밍 - Django 웹 프레임워크 #2

by 돼지왕 왕돼지 2016. 12. 12.
반응형

 [Django] 파이썬 웹 프로그래밍 - Django 웹 프레임워크 #1


&, .html, /polls/{question.id}/vote, 0.0.0.0, 127.0.0.1, 1:n, 1table.ntable_set, 8000, :5, admin, admin pae, admin 사이트, admin.py, admin.site.register, admin.site.register(), All, Apache, app package, appDir, application, application files, appname, asia/seoul, autoincrement, base_dir, bg 실행, charfield, choice.votes, column, CONTEXT, createsuperuser, cross site request forgery, crud, CSRF, csrf 공격, DateTimeField, DB, db 변경, db 삭제, db 추가, db.sqlite3, default, detail, detail(), detail.html, dictionary, Dir, django-admin.py, django-admin.py startproject, django.contrib.auth, django.db, djanog, doesnotexist, error_message, FK, Foreign Key, ForeignKey, form, Get, get_list_or_404, get_object_or_404, Groups, host, http 404 exception, httprequest, HttpResponse, httpresponseredirect, Include, index, index(), index.html, installed_apps, integerfield, keyerror exception, kwargs, Label, logs, makemigrations, manage.py, Migrate, migration, migrations, Model, model 코딩, model.doesnotexist exception, Models, models.foreignkey, models.model, models.py, mysql, mystie, Name, namespace, non null, None, object, objects, Operation, oracle, order_by, parameters, password, patternname, PK, pluralize, polls.urls, Post, prefix, Primary Key, project configuration files, project package, python, python manage.py migrate, python manage.py startapp, python3, question_id, Regex, render, request, request.post, results(), results.html, Reverse, root_urlconf, runserver, S, Save, setting.py, settings.py, sqlimigrate, SQLITE3, sql문, startproject, static, table, tablename_id, template, template 코딩, templates, tests.py, time_zone, unit test, url, url string, url view 1:1, url 패턴, url 패턴 정의, URLconf, urlconf 코딩, urls.py, User, USER NAME, user 생성, UTC, View, view 코딩, views.py, Vote, vote(), web programming, wsgi, wsgi.py, xxx_set, [Django] 파이썬 웹 프로그래밍 - Django 웹 프레임워크 #2, __init__.py, __str__(), __unicode()__, {% csrf_token %}, {% url %}, {% url 'polls:vote' question.id %}, 객체, 계층적 웹 개발, 공격, 규격, 기능 그룹, 기본, 기본 뼈대, 단수, 단수 복수, 단축 함수, 데이터베이스 변경사항 반영, 데이터베이스 지정, 동일한 동작, 디렉토리, 로그의 형식, 로그인, 로그인된, 리다이렉션, 매핑 함수, 명령어 처리, 보안 취약, 복수, 뷰 함수에 대한 접두 문자, 뼈대, 사용자, 사용자 그룹, 생산성, 설정 파일, 스트링, 신규 생성, 악의적인 사이트, 앱, 앱 디렉토리, 앱 생성, 앱 파일, 어플리케이션, 역순정렬, 연동, 외부, 웹 서버, 웹 프레임워크, 작업, 장고, 재사용, 정의 변경, 제출된 폼 데이터, 조건, 중복, 중복 방지, 최상위 urlconf, 추가 인자, 추출 항목, 쿠키, 클래스형 뷰, 테이블 반영, 템플릿, 템플릿 언어, 템플릿 태그, 템플릿 파일, 파이썬 웹 프로그래밍, 파이썬 웹 프로그램, 파이썬 패키지, 패키지, 패키지 인식, 폼 템플릿, 표현, 프로젝트, 프로젝트 뼈대 만들기, 프로젝트 생성, 프로젝트 설정 파일, 프로젝트 파일, 하드코딩, 하위 서브 프로그램, 함수, 함수형 뷰

< 3.4. 프로젝트 뼈대 만들기 >


-

프로젝트란 개발 대상이 되는 전체 프로그램을 의미하며,

프로젝트를 몇 개의 기능 그룹으로 나누었을 때, 프로젝트의 하위 서브 프로그램을 앱이라 말한다.

즉 서브 프로그램인 앱을 개발하고, 이들을 모아 프로젝트 개발을 완성하게 되는 것이다.


이런 개념으로 프로젝트 디렉토리와 앱 디렉토리를 구분하고,

코딩하는 파일도 프로젝트 파일인지 앱 파일인지 구분해서 적절한 위치에 저장해야 한다.



-

중요한 점은 하나의 앱이 여러 개의 프로젝트에 포함될 수 있기 때문에,

앱을 한 번만 개발하고 이를 다른 프로젝트에 재사용하여 개발의 생산성을 높일 수 있다.

앱 단위로 이들을 모아 프로젝트로 만들고,

프로젝트를 모아서 더 큰 프로젝트를 만드는 방식으로,

계층적인 웹 프로그램 개발이 가능하다는 장점이 있다.



-

프로젝트와 앱 모두 파이썬 패키지 디렉토리에 해당하는데, 파이썬에서는 __init__.py 파일이 존재하는 디렉토리를 패키지라고 한다.



-

기본 뼈대는 아래와 같다.


&, .html, /polls/{question.id}/vote, 0.0.0.0, 127.0.0.1, 1:n, 1table.ntable_set, 8000, :5, admin, admin pae, admin 사이트, admin.py, admin.site.register, admin.site.register(), All, Apache, app package, appDir, application, application files, appname, asia/seoul, autoincrement, base_dir, bg 실행, charfield, choice.votes, column, CONTEXT, createsuperuser, cross site request forgery, crud, CSRF, csrf 공격, DateTimeField, DB, db 변경, db 삭제, db 추가, db.sqlite3, default, detail, detail(), detail.html, dictionary, Dir, django-admin.py, django-admin.py startproject, django.contrib.auth, django.db, djanog, doesnotexist, error_message, FK, Foreign Key, ForeignKey, form, Get, get_list_or_404, get_object_or_404, Groups, host, http 404 exception, httprequest, HttpResponse, httpresponseredirect, Include, index, index(), index.html, installed_apps, integerfield, keyerror exception, kwargs, Label, logs, makemigrations, manage.py, Migrate, migration, migrations, Model, model 코딩, model.doesnotexist exception, Models, models.foreignkey, models.model, models.py, mysql, mystie, Name, namespace, non null, None, object, objects, Operation, oracle, order_by, parameters, password, patternname, PK, pluralize, polls.urls, Post, prefix, Primary Key, project configuration files, project package, python, python manage.py migrate, python manage.py startapp, python3, question_id, Regex, render, request, request.post, results(), results.html, Reverse, root_urlconf, runserver, S, Save, setting.py, settings.py, sqlimigrate, SQLITE3, sql문, startproject, static, table, tablename_id, template, template 코딩, templates, tests.py, time_zone, unit test, url, url string, url view 1:1, url 패턴, url 패턴 정의, URLconf, urlconf 코딩, urls.py, User, USER NAME, user 생성, UTC, View, view 코딩, views.py, Vote, vote(), web programming, wsgi, wsgi.py, xxx_set, [Django] 파이썬 웹 프로그래밍 - Django 웹 프레임워크 #2, __init__.py, __str__(), __unicode()__, {% csrf_token %}, {% url %}, {% url 'polls:vote' question.id %}, 객체, 계층적 웹 개발, 공격, 규격, 기능 그룹, 기본, 기본 뼈대, 단수, 단수 복수, 단축 함수, 데이터베이스 변경사항 반영, 데이터베이스 지정, 동일한 동작, 디렉토리, 로그의 형식, 로그인, 로그인된, 리다이렉션, 매핑 함수, 명령어 처리, 보안 취약, 복수, 뷰 함수에 대한 접두 문자, 뼈대, 사용자, 사용자 그룹, 생산성, 설정 파일, 스트링, 신규 생성, 악의적인 사이트, 앱, 앱 디렉토리, 앱 생성, 앱 파일, 어플리케이션, 역순정렬, 연동, 외부, 웹 서버, 웹 프레임워크, 작업, 장고, 재사용, 정의 변경, 제출된 폼 데이터, 조건, 중복, 중복 방지, 최상위 urlconf, 추가 인자, 추출 항목, 쿠키, 클래스형 뷰, 테이블 반영, 템플릿, 템플릿 언어, 템플릿 태그, 템플릿 파일, 파이썬 웹 프로그래밍, 파이썬 웹 프로그램, 파이썬 패키지, 패키지, 패키지 인식, 폼 템플릿, 표현, 프로젝트, 프로젝트 뼈대 만들기, 프로젝트 생성, 프로젝트 설정 파일, 프로젝트 파일, 하드코딩, 하위 서브 프로그램, 함수, 함수형 뷰


프로젝트가 완성된 후에는 templates, static, logs 등의 디렉토리가 더 필요하다.



-

root mysite 디렉토리 : 프로젝트 관련 디렉토리 및 파일을 모아주는 최상위 디렉토리. 보통 settings.py 파일의 BASE_DIR 항목으로 지정된다. ( 이 녀석은 특별한 의미를 가지지 않기 때문에 rename 해도 괜찮다. )

db.sqlite3 : SQLite3 DB 파일. db 디렉토리를 만들고 그 하위에 두기도 한다.

manage.py : 장고의 명령어를 처리하는 파일

mysite 디렉토리 : 프로젝트명으로 만들어진 디렉토리. 프로젝트 관련 파일들이 있다.

     __init__.py : 패키지 인식

     settings.py : 프로젝트 설정 파일

     urls.py : 프로젝트 레벨의 URL 패턴을 정의하는 최상위 URLconf. 보통 하위 앱 디렉토리마다 urls.py 가 있다.

     wsgi.py : Apache 와 같은 상용 웹 서버와 WSGI 규격으로 연동하기 위한 파일

polls 디렉토리 : 앱명으로 만들어진 디렉토리. 해당 앱 관련 파일이 들어 있다.

     __init__.py

     admin.py : Admin 사이트에 모델 클래스를 등록해주는 파일

     migration 디렉토리: DB 변경사항을 관리하기 위한 디렉토리, DB 에 추가, 삭제, 변경 등이 발생하면 변경 내역을 기록한 파일들이 위치한다.

     models.py : DB 모델 클래스를 정의

     tests.py : unit test 용 파일

     views.py : 뷰 함수를 정의하는 파일. 함수형 뷰 및 클래스형 뷰 모두 이 파일에 정의




-

뼈대를 만들기 위해서 다음의 순서로 명령을 실행한다.


$ django-admin.py startproject mysite

$ python manage.py startapp polls // polls 라는 앱을 생성

$ python manage.py migrate // db 변경사항 반영

$ python manage.py runserver // 현재까지 작업을 개발용 웹 서버로 확인


     


* 3.4.1. 프로젝트 생성




* 3.4.2. 앱 생성




* 3.4.3. 데이터베이스 변경사항 반영


-

DB 를 만들지도 않았는데 python manage.py migrate 를 호출해주는 이유는..

장고는 모든 웹 프로젝트 개발 시 반드시 사용자와 사용자의 그룹 테이블이 필요하다고 가정하고 설계되었다.

따라서 우리가 테이블을 만들지 않았더라도, 사용자 및 사용자 그룹 테이블을 만들어주기 위해 이 명령을 실행해야 한다.

명령을 실행하면 migrate 명령에 대한 로그가 보이고, 실행 결과로 SQLite3 DB 파일인 db.sqlite3 파일이 생성된다.




* 3.4.4. 지금까지 작업 확인하기


-

runserver 에 주소와 포트를 지정하지 않으면 기본으로 127.0.0.1 주소 및 8000 포트를 사용한다.

port 만 지정할 수도 있다.

0.0.0.0 은 현재 명령을 실행중인 서버의 IP 주소가 무엇으로 설정되어 있더라도 그와는 무관하게 웹 접속 요청을 받겠다는 의미. 즉, 외부에서 서버의 IP 주소를 브라우저의 주소창에 입력하여 접속하는 것을 가능하게 해준다.

마지막에 & 를 붙이면 자동으로 bg 에서 실행한다.



-

host/admin 으로 접근하면 admin page 로 이동한다.


user 생성은 아래와 같이 한다.


$ python manage.py createsuperuser

// user name, password 설정이 진행된다.



-

admin 화면에서 기본적으로 User 와 Groups 테이블이 보이는 것은 이미 settings.py 파일에 django.contrib.auth 앱이 등록되어 있기 때문이다.






< 3.5. 앱 개발하기 - 설계 >






< 3.6. 앱 개발하기 - Model 코딩 >


* 3.6.1. 데이터베이스 지정


-

장고는 디폴트로 SQLite3 을 사용한다.

만약 MySQL 이나 Oracle 등 다른 db 로 변경하고 싶다면 settings.py 를 수정해주면 된다.



-

settings.py 설정 파일은 프로젝트의 전반적인 사항들을 설정해주는 곳으로,

루트 디렉토리를 포함한 각종 디렉토리의 위치,

로그의 형식,

프로젝트에 포함된 앱 등이 지정되어 있어 그 내용에 익숙해지는 것이 좋다.



-

프로젝트에 포함되는 앱들은 모두 설정 파일에 지정되어야 한다.


INSTALLED_APPS 에 새로운 앱을 추가해주어야 한다.



-

TIME_ZONE 항목의 Default 는 UTC 인데 이를 바꿀 수 있다.


TIME_ZONE = ‘Asia/Seoul'






* 3.6.2. 테이블 정의


-

from django.db import models


class Question(models.Model): # question_id 라는 PK 가 자동으로 생긴다.

     question_text = modesl.CharField(max_length=200) # varchar(200)

     pub_date = models.DateTimeFiled(‘date published’) # datetime


class Choice(models.Model):  # choice_id 라는 PK 가 자동으로 생긴다.

     question = models.ForeignKey(Question) #question_id 로 접근

     choice_text = models.CharField(max_length=200) 

     votes = models.IntegerField(default=0)



-

PK(Primary Key)는 클래스에 지정해주지 않아도, 장고는 항상 PK 에 대한 속성을 Not Null 및 Autoincrement 로, 변수 이름은 TableName_id 로 자동으로 만들어준다.



-

DateTimeField() 에 정의하는 문구는 column 에 대한 label 문구이다.

Admin 사이트에서 보인다.



-

FK(Foreign Key)는 항상 다른 테이블의 PK 에 연결되므로, 클래스 이름만 지정하면 된다.



-

__unicode()__ 함수는 객체를 스트링으로 표현할 때 사용하는 함수이다.

__unicode__() 함수를 정의하지 않으면 테이블명이 제대로 표시되지 않는다.

Python3 에서는 __str__() 함수로 변경되었다.




* 3.6.3. Admin 사이트에 테이블 반영


-

새로 생성한 테이블을 보이게 하려면 admin.py 에 해당 table 을 추가하면 된다.

admin.site.register() 함수를 사용하여 등록해주면 된다.


테이블을 추가할 때는 models.py 와 admin.py 두개를 함께 수정한다는걸 기억해야 한다.


ex)

from django.contrib import admin

from polls.models import Question, Choice


admin.site.register(Question)

admin.site.register(Choice)




* 3.6.4. 데이터베이스 변경사항 반영


-

테이블의 신규 생성, 테이블의 정의 변경 등 db 변경이 필요한 사항이 있으면, 이를 db 에 실제 반영해주는 작업을 해야 한다.

이는 아래와 같이 한다.


$ python manage.py makemigrations # 앱dir/migrations 폴더가 생기고 그곳에 migration 코드가 생성된다.

$ python manage.py migrate


$ python manage.py sqlimigrate polls 0001 # migrate 명령으로 데이터베이스를 반영할 때 장고가 사용하는 SQL 문을 볼 수 있다.




* 3.6.5. 지금까지 작업 확인하기






< 3.7. 앱 개발하기 - View 및 Template 코딩 >


-

장고에서 URL 과 뷰는 항상 1:1 관계로 매핑이 된다.

URL/View Mapping 은 URLconf 라고 하며 urls.py 파일에 작성한다.



-

url -> view -> template

/polls/ -> index() -> index.html

/polls/5 -> detail() -> detail.html

/polls/5/vote/ -> vote() -> detail.html 에 있는 폼을 POST 방식으로 처리한다.

/polls/5/results/ -> results() -> results.html


from django.conf.urls import patterns, url

from polls import views


urlpatterns = patterns( '',

url(r'^polls/$', views.index, name='index'),

url(r'^polls/(?P<question_id>\d+)/$', views.detail, name='detail'),

url(r'^polls/(?P<question_id>\d+)/vote/$', views.vote, name='vote'),

url(r'^polls/(?P<question_id>\d+)/results/$', views.results, name='results'),

url(r'^admin/', include(admin.site.urls)),

)




* 3.7.1. URLconf 코딩


-

url( regex, view, kwargs=None, name=None, prefix=‘')


view : regex 인자에 매칭되면 호출하는 함수. 뷰 함수에는 HttpRequest와 regex 에서 추출한 항목을 인자로 넘겨준다.

kwargs : regex 인자에서 추출한 파라미터 외에 추가적인 인자를 파이썬 사전 타입의 키워드 인자로 넘겨준다.

name : URL 별로 이름을 붙여준다. 여기서 정해준 이름이 템플릿 파일에서 사용된다.

prefix : 뷰 함수에 대한 접두문자열이다.



-

url(r’^polls/(?P<question_id>\d+)/$’, views.detail, name=‘detail’)


위는 polls/5 와 같은 URL 이 들어오면 matching 되며,

?P<question_id> 라고 명시해준 것은 그 다음에 오는 것을 question_id=(\d+의 값) 형태로 전달한다.

즉, views.detail(request, question_id=‘5’) 형태로 호출이 된다.



-

settings.py 의 ROOT_URLCONF 항목에 정의된 urls.py 파일을 가장 먼저 분석하기 시작한다.



-

URLconf 를 코딩할 때 urls.py 에 직접 코딩할 수도 있고,

appName/urls.py 와 같이 분리한 후 include 시키는 방법도 있다.


url(‘r^polls/‘, include(‘polls.urls’, namespace=“polls”)), # namespace 는 중복을 막기 위함으로 polls:detail 과 같은 형태가 된다.


그리고 이 방식이 추천되는 방식이다.




* 3.7.2. 뷰 함수 index() 및 템플릿 작성


-

template 을 작성하는 위치는.. 

appDir/templates/appDir 에 .html 형태로 작성한다.

templates 아래 appDir 을 다시 생성하는 이유는..

앱의 갯수가 늘어나고 템플릿 파일이 많아질 경우 앱은 다르지만 템플릿 파일 이름이 같은 경우가 발생하기 때문에 사용하는 관습.



-

template 은 템플릿 언어인 {% if %}, {% for %} 태그 등을 사용한다.



-

views.py 에는 매핑 함수를 구현해준다.


ex)

def index(request):

     latest_question_list = Question.objects.all().order_by(‘-pub_date’)[:5] # - 는 역순정렬

     context = {‘latest_question_list’:latest_question_list}

     return render(request, ‘polls/index.html’, context) # render 를 하면 HttpResponse 가 생긴다.






* 3.7.3. 뷰 함수 detail() 및 폼 템플릿 작성


-

<!-- detail.html -->

<h1>{{ question.question_text }}</h1>


{% if error_message %} <p><strong> {{ error_message }} </strong></p> {% endif %}


<form action="{% url 'polls:vote' question.id %}" method="post">

{% csrf_token %}

{% for choice in question.choice_set.all %}

<input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" />

<label for="choice{{ forloop.counter }}">{{ choice.choice_text }}</label><br />

{% endfor %}

<input type="submit" value="Vote" />

</form>



-

template 에서 사용하는 코드에 에러가 있다면 error_message 라는 변수에 값이 담긴다.



-

{% url %} 에 polls:vote 와 같이 명시해주면, polls 를 namespace 로 갖는 name 이 vote 인 URLconf 에 지정된 view 가 호출된다.

{% url ‘polls:vote’ question.id %} 와 같이 하면 결국 매핑된 형태는 /polls/{question.id}/vote 가 된다.



-

form 을 처리하는 경우, 보안 측면에서 CSRF( Cross Site Request Forgery ) 공격을 주의해야 한다.

장고는 이를 방지하기 위한 기능을 제공하는데, {% csrf_token %} 탬플릿 태그를 명시만 해주면 이를 방지해준다.


CSRF 는 사용자가 보안이 취약한 사이트에 로그인해 있는 상태에서, 악의적인 사이트를 접속하는 경우(혹은 그곳에서 어떤 작업을 할 경우) 로그인된 취약한 사이트에 어떤 작업( CRUD ) 을 하는 공격 방법.

대표적인 예가 로그인 상태를 쿠키에 보관하는 경우, 악의적인 사이트에서 해당 쿠키를 이용하는 것이다.



-

두 개의 테이블 관계가 1:N 관계이고, FK 로 연결되어 있다면..

1 테이블에 연결된 N 테이블의 항목들이라는 의미로, xxx_set 속성을 사용할 수 있다.

1table.ntable_set 이란 property 로 접근 가능하다.


ex) question.choice_set



-

# views.py


from django.shortcuts import get_object_or_404, render

from polls.models import Question


# ... index()


def detail(request, question_id):

question = get_object_or_404(Question, pk=question_id)

return render(request, 'polls/detail.html', {'question': question})



-

get_object_or_404 는 단축함수로,

첫번째 Model 로부터 뒤에 따라붙는 조건의 object 를 찾아오고, 찾지 못하면 Http404 Exception 이 발생한다.



-

대상 객체를 리스트로 가져오는 get_list_or_404() 단축함수도 있다.




* 3.7.4. 뷰 함수 vote() 및 리다이렉션 작성


-

# views.py

#... index()

# ... detail()


def vote(request, question_id):

p = get_object_or_404(Question, pk=question_id)

try:

selected_choice = p.choice_set.get(pk=request.POST['choice'])

except (KeyError, Choice.DoesNotExist):

return render(request, 'polls/detail.html', { 'question' : p, 'error_message' : "You didn't select a choice.", })

else:

selected_choice.votes += 1

selected_choice.save()

return HttpResponseRedirect(reverse('polls:results', args=(p, question_id,)))



-

request.POST 는 제출된 폼의 데이터를 담고 있는 객체이다.

dictionary 형태이다.


ex) request.POST[‘choice’] # 키가 없으면 KeyError Exception 이 발생한다.



-

get 함수는 해당하는 조건이 없으면 Model.DoesNotExist Exception 이 발생한다.



-

model 에 operation 한것을 db 저장하려면 save() 함수를 호출해준다.



-

POST 방식의 폼 데이터 처리의 경우, 그 결과를 보여줄 수 있는 페이지로 이동시키기 위해 HttpResponseRedirect 객체를 리턴하는 것일 일반적이다.



-

reverse() 함수는 URL 패턴으로부터 URL 스트링을 구할 수 있는 것이다.

(URLconf 는 URL 스트링으로부터 URL 패턴을 구한다.)


reverse(patternName, parameters)


reverse 는 URLconf 에 미리 정의된 URL 패턴에서 URL 스트링을 추출하는 방식이라 유연성이 좋다.

그러므로 하드코딩을 피하고 reverse 를 쓰는 것이 추천된다.




* 3.7.5. 뷰 함수 results() 및 템플릿 작성


-

{{ choice.votes | pluralize }} 와 같은 방식으로 사용하면, choice.votes 의 단수 복수 상태에 따라 s 를 붙이거나 안 붙이거나 한다.



-

템플릿의 url 태그는 view 의 reverse 와 동일한 역할을 한다.




* 3.7.6. 지금까지 작업 확인하기








반응형

댓글