[Django] 파이썬 웹 프로그래밍 - Django 의 핵심 기능 #1 |
-
책을 읽으며 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 에 사용되는 예약 문자들을 이스케이프한다.
( 예를 들어 < 는 < 로, “ 는 " 로 )
그러나 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 %}
'프로그래밍 놀이터 > Script(Python)' 카테고리의 다른 글
[Django] Tutorial 목차 (0) | 2017.04.12 |
---|---|
[Django] 파이썬 웹 프로그래밍 - Django 의 핵심 기능 #2 (0) | 2016.12.15 |
[Django] 파이썬 웹 프로그래밍 - Django 웹 프레임워크 #2 (0) | 2016.12.12 |
[Django] 파이썬 웹 프로그래밍 - Django 웹 프레임워크 #1 (0) | 2016.12.09 |
[Django] 파이썬 웹 프로그래밍 - 파이썬 웹 표준 라이브러리 (0) | 2016.12.08 |
댓글