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

[Django] 파이썬 웹 프로그래밍 - Django 의 핵심 기능 #1

by 돼지왕왕돼지 2016. 12. 13.

 [Django] 파이썬 웹 프로그래밍 - Django 의 핵심 기능 #1


ADD, admin, admin 사이트 꾸미기, admin 사이트 템플릿 수정, admin 페이지, admin.ModelAdmin, admin.py, admin.site.register, admin.stackedinline, admin.tabularinline, All, and, arg1, arg2, argn, as, autoescape off, bar, base.html, base_dir, base_site.html, Block, block tag, block.super, choiceinline, CLASS, classes, Collapse, COMMENT, contrib, cross site request forgery, cross site scripting, CSRF, csrf_token, csv, DB, default, Delete, delete(), dictionary type, Django, django 1.8, django_settings_module, elif, Else, end comment, endautoescape, endblock, endfor, endif, endwith, Es, Escape, exclude, exclude(), extends, Extra, FALSE, fields, fields 순서, fieldsets, Filter, filter(), foo.bar, foo['bar'], foo[bar], for in, for tag, forloop, forloop.counter, forloop.counter(), forloop.first, forloop.last, forloop.parentloop, forloop.revcounter, forloop.revcounter(), Get, get(), HTML, html 태그, ies, IF, in, Include, inline, inlines, Join, length, Library, linebreaks, list_display, list_filter, look and feel, look up 순서, lookup, Lower, lower case, manage.py, Model, modeladmin, models.py, mysite/settings.py, namespace, Not, not in, objects, objects.all, Options, or, os.path.join(base_dir, pacakge, pluralize, polls, Post, pulralize:, python, queryset, questionadmin, register, rendering, safe, Save, save(), Scope, setitng.py, settings.py, site-packages, StackedInline, step, Stepping, string_if_invalid, striptags, table, TabularInline, template filter, template system, template tag, template variable, templates, template_dirs, template_string_if_invalid, truncatewords, ui 양식 변경, Update, update(), url, urls.py, variable name, variable_name, view-name, web programming, With, xml, XSS, y, [Django] 파이썬 웹 프로그래밍 - Django 의 핵심 기능, __str__, block, for, tag, _, 개수 제한, 객체, 검색, 공격, 공격 명령, 공격방법, 관리자, 데이터 입력 및 수정, 데이터베이스, 도트, 랜더링, 레모드, 레코드, 레코드 리스트, 레코드 제목, 렌더링, 룩앤필, 리스트, 메모리, 모듈, 모든 객체 삭제, 미정의 변수, 배열 슬라이싱, 변수, 복잡, 복잡한 조건, 부모 템플릿, 빈 문자열, 뼈대, 사용자 정의 태그, 사용자 정의 필터, 사이트 간 요청 위조 공격, 사이트간 스크립팅 공격, 사전, 사전타입, 상속, 생성, 속성, 수정, 쉘, 악성 스크립트, 악의적 스크립트 문장, 오바라이딩, 외래키 관계 화면, 외부 url, 웹 사이트, 웹 앱, 유효성 검증, 이 값 변경, 이스케이프, 이스케이프 방지, 인증, 인터넷 속도, 일관성, 일반 사용자, 임포트, 자동 이스케이프, 자동 이스케이프 기능, 장고, 장점, 재사용, 저장, 접미사, 조건, 주석, 주석 내용, 주의사항, 줄바꿈, 중첩 사용, 짝수, 짝수번째, 체인, 취약점, 치환, 컬럼 항목, 코스트, 콜렉션, 태그, 테이블, 텍스트, 텍스트 파일, 템플릿, 템플릿 상속, 템플릿 시스템, 템플릿 코드 해석, 템플릿 태그, 템플릿 파일, 템플릿 필터, 템픞릿 변수, 토큰, 파라미터, 파이썬 쉘, 파이썬 웹 프로그래밍, 파이프 문자, 패턴 이름, 폼 데이터, 필드 순서 변경하기, 필드 접기, 필터, 필터 사이드바, 필터 인자, 하드 코딩, 한 개 요소, 핵심 기능


-

책을 읽으며 Remind 하는 내용, 핵심 내용, 모르던 내용을 정리한 것입니다. 예문 및 자세한 설명은 책을 구매하여 보세요~



< 4.1. Admin 사이트 꾸미기 >


* 4.1.1. 데이터 입력 및 수정




* 4.1.2. 필드 순서 변경하기


-

테이블 데이터 변경이 아닌 테이블을 보여주는 UI 양식 변경은 admin.py 파일을 변경하면 된다.

아래와 같이 순서에 대해 정의하는 admin.ModelAdmin 을 상속하는 녀석을 만들고, register 할 때 이 class 를 함께 전달하면 된다.


class QuestionAdmin(admin.ModelAdmin):

     fields = [‘pub_date’, ‘qestion_text’]


admin.site.register(Question, QuestionAdmin)

admin.site.register(Choice)




* 4.1.3. 각 필드를 분리해서 보여주기


-

아래와 같이 admin.py 를 수정하면 각 필드를 분리해서 보여줄 수 있다.


class QuestionAdmin(admin.ModelAdmin):

     fieldsets = [

          (‘Question Statement’, {‘fields’:[‘question_test’]}), # 'Question Statement' 는 Fieldset 의 label

          (‘Date Information’, {‘fields’:[‘pub_date’]}),

     ]




* 4.1.4. 필드 접기


-

admin.py 의 fieldsets 정의에서, ‘fields’ 와 함께 ‘classes’:[‘collapse’] 속성을 함께 주면 접어서 보여준다.


ex) (‘Question Statement’, {‘fields’:[‘question_test’], 'classes':['collapse']}),




* 4.1.5. 외래키 관계 화면




* 4.1.6. Question및 Choice 를 한 화면에서 변경하기


-

1:N 관계에 있을 때  admin.py 에 아래와 같이 추가해주면, N 에 해당하는 녀석들을 1 의 수정화면에서 함께 보고 수정할 수 있다.


class ChoiceInline(admin.StackedInline):

     model = Choice

     extra = 2 # 새로 추가할 수 있는 N table row 의 기본 row 갯수.


class QuestionAdmin(admin.ModelAdmin):

     fieldsets = {

          (None, {‘fields’:[‘question_text’]}),

          (‘Date Information’, {‘fields’:[‘pub_date’], ‘classes’:[‘collapse’]}0,

     ]

     inlines = [ChoiceInline]





* 4.1.7. 테이블 형식으로 보여주기


-

admin.py 에서 admin.StckedInline 대신 admin.TabularInline 을 상속하도록 하면 table 형태로 볼 수 있다.




* 4.1.8. 레코드 리스트 항목 지정하기


-

Admin 사이트의 레코드 리스트에서 레코드의 제목은 models.py 에 정의한 __str__() 의 리턴값을 사용한다.

아래의 list_display 를 지정하지 않으면 __str__() 에 지정한 녀석만 제목으로 노출된다.



-

admin.py 에 레코드 리스트에 보여주는 컬럼 항목을 지정할 수 있다.

이는 ModelAdmin 을 상속한 녀석에 list_display 항목을 지정함으로써 구현한다.


list_display = (‘question_text’, ‘pub_date’)




* 4.1.9. list_filter 필터


-

admin.py 의 ModelAdmin 을 상속한 녀석에 list_filter 항목을 한 줄 추가하면, 필터 사이드바를 붙일 수 있다.


list_filter = [‘pub_date’]




* 4.1.10. search_fields


-

admin.py 의 ModelAdmin 을 상속한 녀석에 search_fields 항목을 추가하면 검색창을 넣을 수 있다.


search_fields = [‘question_text’]




* 4.1.11. polls/admin.py 변경 내역 정리




* 4.1.12. Admin 사이트 템플릿 수정


-

Admin 페이지의 템플릿 자체를 수정하고 싶다면, 장고의 기본 Admin 템플릿 파일을 우리 프로젝트로 복사해 온 다음 수정하면 된다.

이 때 복사위치는 프로젝트 내 templates/admin 디렉토리이다. ( 없으면 새로 만든다. )

Admin 페이지의 위치는 …./site-packages/django/contrib/admin/templates/admin/base_site.html


템플릿 복사 후에는 settings.py 에 아래 문구를 추가해준다.

TEMPLATE_DIRS = [os.path.join(BASE_DIR, ‘templates’)]






< 4.2. 장고 파이썬 쉘로 데이터 조작하기 >


-

admin 페이지를 통하지 않고, 파이썬 쉘을 이용하여 데이터를 관리할 수도 있다.

쉘 데이터 처리는 인터넷 속도가 느려져 Admin 사이트에 접속이 어려울 때 사용할 수 있고, 복잡한 조건으로 검색하거나 수정하는 등의 처리도 가능하다는 장점이 있다.



-

장고 파이썬 쉘 시작은 아래 명령어로 한다.

일반 파이썬 쉘과 다른 점은 manage.py 모듈에서 정의한 DJANGO_SETTINGS_MODULE 속성을 이용하여 미리 mysite/settings.py 모듈을 임포트한다는 것.


$ python manage.py shell




* 4.2.1. Create - 데이터 생성/입력


-

테이블에 레코드를 생성하기 위해서는 필드값을 지정하여 객체를 생성한 후 save() 메소드를 호출하면 된다.

save() 명령 실행 전은 메모리에만 반영된 것이다.


ex)

q = Question(question_text="What's new?", pub_date=timezone.now())

q.choice_set.create(choice_text=‘Sleeping’, votes=0)

q.save()



-

1:N 관계에서 N 에 대해 create 명령을 통해 row 를 추가할 수 있다.




* 4.2.2. Read - 데이터 조회


-

데이터 조회를 위해서 QuerySet 객체를 사용한다.

QuerySet 은 데이터베이스 테이블로부터 꺼내 온 객체들의 콜렉션이다.

QuerySet 은 필터를 가질 수 있으며, 필터를 사용하여 검색 결과에서 주어진 파라미터로 조건에 맞는 레코드만 다시 추출한다.


QuerySet 을 얻으려면 objects 객체를 사용한다.


Question.objects.all() # 모든 레코드



-

특정 레코드를 검색할 때는 filter() exclude() 메소드를 사용한다.


filter() : 주어진 조건에 맞는 객체들을 담고 있는 QuerySet 콜렉션을 반환

exclude() : 주어진 조건에 맞지 않는 객체들을 담고 있는 QuerySet 콜렉션을 반환함.


ex)

Question.objects

.filter( question_text__startswith=‘What’ )

.exclude( pub_date__gte=datetime.date.today() )

.filter( pub_date__gte=datetime( 2005, 1, 30 ) ) # __gte 는 greater than equal 의 약자



-

한 개의 요소만 검색하는 경우에는 get() 을 호출하면 된다.


ex) one_entry = Question.objects.get(pk=1)



-

QuerySet 요소의 개수 제한을 위해 배열 슬라이싱 문법을 사용할 수 있다.


ex)

Question.objects.all()[:5]

Question.objects.all()[:10:2] # 마지막 colon 은 stepping 이다. 즉 10번째 아이템까지 중 짝수번째 녀석들 collect 한 효과이다.






* 4.2.3. Update - 데이터 수정


-

필드 속성 값을 수정한 후 save() 를 호출하면 된다.

여러 객체를 한번에 수정할 때는 update() 메소드를 사용한다.


ex) 

Question.objects

.filter(pub_date__year=2007) # __year 는 연도만 발췌, property 에 접근하는 . 문법 느낌

.update(question_text=‘Everything is the same’) 




* 4.2.4. Delete - 데이터 삭제


-

객체 삭제는 delete() 메소드를 사용한다.



-

모든 객체 삭제는 꼭 all() 로 받아와서 해야만 가능하다.


Question.objects.all().delete() # 가능

Question.objects.delete() # 불가능, 의도치 않은 삭제를 방지하기 위해 장고에서 막음




* 4.2.5. polls 앱 데이터 실습






< 4.3. 템플릿 시스템 >


-

템플릿 코드를 해석하여 템플릿 파일로 해석하는 과정을 장고에서는 렌더링이라고 한다.

결과물인 템플릿 파일은 HTML, XML, CSV 등의 단순한 텍스트 파일이다.




* 4.3.1. 템플릿 변수


-

변수는 {{ variable_name }} 의 형태로 사용한다.



-

변수의 속성에 접근하는 도트(.) 표현식도 가능한데, 파이썬의 . 과는 조금 다르다.

템플릿 문법에서 . 을 만나면 장고는 다음 순서로 lookup 을 시도한다.

예를 들어 foo.bar 라는 템플릿 변수가 있다면..

     1. foo 가 사전타입인지 검사. 그렇다면 foo[‘bar’] 로 해석

     2. foo 의 속성을 검사해서 bar 라는 속성이 있으면 foo.bar 로 해석

     3. 그것도 아니면 foo 가 리스트인지 확인해서 foo[bar] 로 해석



-

템플릿 시스템은 정의되어 있지 않은 변수를 사용할 경우 빈 문자열(‘’) 로 채워주며, 이 값을 변경하려면 settings.py 에 다음 속성을 지정해주면 된다.

기본값은 빈 문자열이다.


# Since Django 1.8

TEMPLATES = [

     {

          ...

          ‘OPTIONS’ : {

               ‘string_if_invalid’ : ‘Invalid variable!!’,

          }

     },

]


# Before Django 1.8

TEMPLATE_STRING_IF_INVALID = ‘Invalid variable!!'




* 4.3.2. 템플릿 필터


-

필터는 파이프( | ) 문자를 사용한다.

파이프 앞에 있는 variable 을 파이프 뒤에 있는 조건으로 치환하는 문법이다.

필터는 체인으로 사용할 수도 있다.


ex)

{{ name | lower }} # name 을 lower case 로 만든다.

{{ text | escape | linebreaks }} # text 를 escape 하고, 마지막에 <p> 를 붙여준다.

{{ bio | truncatewords:30 }} # 앞의 30개 단어만 보여주고 줄 바꿈 문자는 모두 없애준다.

{{ list | join:” // “ }} # list item 들을 // 를 구분자로 join 해준다.

{{ value | default:”nothing” }} # value 값이 False 이거나 없는 경우 nothing 으로 보여준다.

{{ value | length }} # len() 함수를 호출한 것과 같은 효과를 보여준다. 즉 string, list 등 모두 사용 가능하다.

{{ value | striptags }} # html 태그를 모두 없애준다. ( 100% 보장은 아니라 함 )

{{ value | pluralize }} # value 가 복수라면 그에 상응하는 복수형태의 접미사를 넣어준다.

{{ value | pluralize:”es” }} 또는 {{ value | pluralize:"y, ies” }} # 접미사로 es 또는 y 로 끝날 대 ies 를 붙여준다.

{{ value | add:”2” }} # 값을 더하거나, string 에 concat 하거나 하는 등의 동작을 한 값을 return 한다. add 를 할 수 없는 타입일 경우 빈 문자열을 반환한다.




* 4.3.3. 템플릿 태그


-

템플릿 태그는 {% tag %} 형식을 가진다.

어떤 태그는 시작 태그가 있다면 끝 태그도 반드시 있어야 한다.




** {% for %} 태그


-

ex)

{% for athlete in athlete_list %}

     <li>{{ athlete.name }}</li>

{% endfor %}




-

아래와 같은 변수를 사용할 수 있다.


forloop.counter : 현재까지 루프를 실행한 루프 카운트, 1부터 시작

forloop.counter() : counter 와 동일하나 0부터 시작

forloop.revcounter : 루프 끝에서 몇번째인지 카운트, 1부터 시작

forloop.revcounter() : revcounter 와 동일하나 0부터 시작

forloop.first : 루프의 첫번째 실행이면 True

forloop.last : 루프의 마지막 실행이면 True

forloop.parentloop : 중첩 루프에서 현재의 루프 바로 상위의 루프를 의미




** {% if %}


-

ex)

{% if athlete_list %}

     Number of athletes: {{ athlete_list | length }}

{% elif athlete_in_locker_room_list %}

     Athletes should be out of the locker room soon!

{% else %}

     No athletes

{% endif %}



-

if 문에는 필터와 연산자를 사용할 수 있는데, 대부분의 필터가 스트링을 반환하므로 산술 연산이 안 되지만 length 필터는 예외이다.


ex) {% if athlete_list | length > 1 %}



-

if 태그 안에는 아래 연산자들을 사용할 수 있다.


and, or, not, ==, !=, <, >, <=, >=, in, not in




** {% csrf_token %} 태그


-

POST 방식의 <form>을 사용하는 템플릿 코드에서는 CSRF(Cross Site Request Forgery) 공격을 방지하기 위해서 {% csrf_token %} 태그를 사용해야 한다.

폼 데이터에는 악의적인 스크립트 문장이 들어 있을 수 있기 때문이다.


ex) <form action=“.” method=“post”> {% csrf_token %}


이 태그를 사용하면 장고는 내부적으로 CSRF 토큰값의 유효성을 검증한다.

만일 CSRF 토큰값 검증에 실패하면 사용자에게 403 에러를 보여준다.



-

CSRF 토큰값이 유출될 수 있으므로, 외부 URL 로 보내는 <form> 에는 사용하지 않도록 한다.



-

CSRF 공격은 Cross-Site Request Forgery 의 약자로 사이트 간 요청 위조 공격이라고도 한다.

웹 사이트의 취약점을 공격하는 방식 중의 하나.

특정 웹 사이트에서 이미 인증을 받은 사용자의 정보를 이용하여 공격을 시도한다.

인증을 받은 사용자가 공격 코드가 삽입된 페이지를 열면 공격 대상이 되는 웹 사이트는 위조된 공격 명령이 믿을 수 있는 사용자로부터 발송된 것으로 판단하여 공격을 받게 되는 방식.






** {% url %} 태그


-

이 태그의 주 목적은 소스에 URL 을 하드 코딩하는 것을 방지하기 위함이다.



-

{% url ‘namespace:view-name’ arg1 arg2 %}

          namespace : urls.py 파일의 include() 함수에서 정의한 Namespace

          view-name : urls.py 파일의 URL 패턴에서 정의한 뷰 함수 또는 패턴 이름

          argN : 뷰 함수에서 사용하는 인자로, 없을 수도 있고, 여러 개인 경우 빈칸으로 구분




** {% with %} 태그


-

특정 값을 변수에 저장해 두는 기능이다.

해당 변수의 scope 는 endwith 까지이다.

보통 DB 조회처럼 코스트가 많이 드는 결과값을 저장해놓아 부하를 줄이기 위함이다.


ex)

{% with total=business.employees.count %} # total = 대신 마지막에 as total 을 써서 variable 이름을 지정해 줄 수도 있다.

     {{ total }} people works at business

{% endwith %}




** {% load %} 태그


-

태그와 필터는 장고에서 기본적으로 제공하는 것 외에도, 개발자가 필요에 따라 스스로 정의하여 사용할 수 있다.

이런 것을 사용자 정의 태그, 사용자 정의 필터라고 한다.

load 태그는 그 사용자 정의 태그 및 필터를 로딩한다.


ex)

{% load somelibrary package.otherlibrary %} # somelibrary.py 파일 및 package/otehrlibrary.py 파일에 정의된 사용자 정의 태그 및 필터 로딩




* 4.3.4. 템플릿 주석


-

템플릿 코드에서의 주석 방법은 2가지가 있다.


한줄 주석은 {# 주석 내용 #} 이다.

멀티라인 주석은 {% comment “Optional Note" %}, {% endcomment %} 이다. 

optional note 는 없어도 되며, 멀티라인 주석은 중첩 사용할 수 없다.




* 4.3.5. HTML 이스케이프


-

템플릿 코드를 렌더링(rendering)하여 HTML 텍스트를 만들 때, 주의해야 할 사항이 있다.

만일 템플릿 변수에 HTML 태그가 들어 있는 경우, 있는 그대로 렌더링하면 원하지 않는 결과가 나올 수 있다.


예를 들어

name = “<b>username” # 변수가 태그를 갖고 있다.

Hello, {{ name }} # 템플릿에 태그를 가진 녀석을 둔다.

# 결과는 Hello, <b>username 이 되면서 원하지 않는 결과가 나온다.


이런 취약점을 이용하여 XSS(Cross Site Scripting) 공격이 이루어질 수 있다.



-

XSS 공격은 Cross Site Scripting 의 약자로 사이트 간 스크립팅 공격이라고 한다.

웹 사이트의 취약점을 공격하는 방식 중 하나로, 웹 사이트관리자가 아닌 일반 사용자도 시도할 수 있는 공격방법이다.

주로 여러 사용자가 보게 되는 전자 게시판에 악성 스크립트가 담긴 글을 올리는 형태로 이루어진다.

이 취약점은 웹 앱이 사용자로부터 입력받은 값을 제대로 검사하지 않고 사용할 경우에 나타난다.



-

장고는 XSS 공격을 방지하기 위해 자동 이스케이프 기능을 제공한다.

장고는 디폴트로 HTML 에 사용되는 예약 문자들을 이스케이프한다.

( 예를 들어 < 는 &lt; 로, “ 는 &quot; 로 )

그러나 HTML 태그를 그대로 출력하고 싶은 경우나, 이스케이프 문자가 들어있는 이메일 메시지를 템플릿 파일에 출력하는 경우에는 자동 이스케이프를 비활성시켜야 한다.


그 방법은 아래와 같으며 템플릿 변수에만 영향을 미친다.

1. safe 필터를 사용하여 이스케이프를 방지. ( ex) {{ data | safe }}

2. {% autoescape off %}, {% endautoescape %} 사이에 auto escape 방지하고픈 구문을 넣는 것이다.



-

필터의 인자에 사용되는 string literal 에는 자동 이스케이프 기능이 적용되지 않는다.

{{ data|default:”3 < 5” }} # 자동 이스케이프 적용 안됨.




* 4.3.6. 템플릿 상속


-

상속은 템플릿 문법 중 가장 복잡하지만, 그만큼 강력하다.

템플릿 상속을 통해 템플릿 코드를 재사용할 수 있고, 사이트의 룩앤필을 일관성 있게 꾸미기도 쉽다.

부모 템플릿은 템플릿의 뼈대를 만들어주고 {% block %} 태그를 통해 하위로 상속해줄 부분을 지정해주면, 자식 템플릿은 부모 템플릿의 뼈대는 그대로 재사용하고 {% block %} 부분만 채워주면 된다.



-

사이트 전체적으로 조화로운 룩앤필을 위해 일반적으로 템플릿 상속을 3단계로 사용하는 것을 권장한다.


1. 사이트 전체의 룩앤필을 담고 있는 base.html 을 만든다.

2. 사이트 하위의 섹션별 스타일을 담고 있는 base_news.html, base_sports.html 등의 템플릿을 만든다. 2단계 템플릿들은 1단계 base.html 을 상속한다.

3. 개별 페이지에 대한 템플릿을 만든다. 3단계 템플릿들은 2단계의 적절한 템플릿을 상속받는다.



-

템플릿 상속을 정의할 때 다음 사항을 유의하여 사용해야 한다.


    {% extends %} 태그는 사용하는 태그 중에서 가장 먼저 나와야 한다.

    템플릿의 공통 사항을 가능하면 많이 뽑아서 1단계 부모 템플릿에 {% block %} 태그가 많아질수록 좋다.

    부모 템플릿에 있는 {% block %} 의 내용을 그대로 사용하고 싶다면 자식 템플릿에서 {{ block.super }} 변수를 사용하면 된다. 이 경우 부모 템플릿의 {% block %} 내용을 자식 템플릿의 내용으로 오버라이딩 하지 않는다. 부모 템플릿의 내용을 그대로 사용하면서 자식 템플릿에서 내용을 추가하는 경우에 사용할 수 있다.

    가독성을 높이기 위해 {% endblock content %}  처럼 블록명을 기입해도 된다.


ex)

<!-- base.html -->

<!DOCTYPE html>

<html lang="en">

<head>

<link rel="stylesheet" href="style.css" />

<title>{% block title %}My amazing site{% endblock %}</title>

</head>


<body>

<div id="sidebar">

<% block sidebar %>

<ul>

<li><a href="/">Home</a></li>

<li><a href="/blog/">Blog</a></li>

<% endblock %>

</div>

</body>

</html>


<!-- child.html -->

<% extends "base.html" %}


{% block title %}My amazing blog {% endblock %}


{% blok sidebar %}

No sidebar

{% endblock %}







댓글0