backend/django

4장 장고핵심기능: admin, shell, template system, form, CBV, LOG

seul chan 2017. 3. 9. 23:28


1. admin

-필드 분리: fieldsets = []


-필드 접기: fieldset = ('Date Information', {'fields':['pub_date'], 'classes':['collapse']})


-ForeignKey: Question 화면에서 Choice 보기 

=> Inline 클래스 추가

class ChoiceInline(admin.StackedInline):

# 줄로 나타내고싶으면 TabularInline

model=Choice

extra = 2 #기존 데이타 이외의 엑스트라 공백 칸 수

=> QuestionAdmin 클래스에 inlines 변수 추가

...

inlines = [ChoiceInline]

...


-list에 보여주는 컬럼 지정

list_display = (), # 튜플 형식 (뒤에 , 찍어야함)


-list_filter: 필터하기

list_filter = ()

=> 필터 형식에 따라 장고가 자동으로 생성


-search_fields

search_fields = [] or ()


-템플릿 수정

장고의 기본 admin 템플릿 파일을 프로젝트로 복사 후 수정 => settings.py 파일에 등록

...django/contrib/admin/templates/admin 하위의 base_site.html 이다.

=> templates/admin  (프로젝트의)에 복사

=> settings.py에 TEMPLATES의 DIRS에 [os.path.join(BASE_DIR, 'templates')] 추가


*장고 path 찾기

python -c "

import sys

sys.path = sys.path[1:]

import django

print(django.__path__)"

'/home/seul/.pyenv/versions/djangostudy/lib/python3.6/site-packages/django'


*문제: 프로젝트 하위 디렉토리의 base_site.html을 변경하였는데 아무런 변화가 없ㅇ므

=> 그냥 해결됨

장고가 html을 찾는 순서는

-폴더 안의 templates를 보고, 없다면

-installed_apps에 있는 디렉토리를 순서대로 따라가며 찾는다

=> 이 loader를 활성화 시키려면 APP_DIRS: True로 지정


2. 장고 파이썬 쉘로 데이터 조작하기

-복잡한 데이터 처리 가능

$python manage.py shell # 장고 파이썬 쉘 접속

CRUD로 설명

1) Create => 내부적으로 SQL의 INSERT문 실행

객체를 생성한 후 save() 전까지는 메모리에서만 변경, 반드시 save() 해야함

2) Retrive =>

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

QuerySet: 데이터베이스 테이블에서 꺼내온 객체 콜렉션, 필터를 사용하여 조건에 맞는 레코드 추출

objects 객체를 사용하여 QuerySet을 얻음 => objects: 테이블 정보를 담고 있는 객체

>> Question.objects.all() # Question 테이블.레코드.모두

조건을 사용하려면 filter(), exclude()

한개만 검색하는 경우에는 get

slicing 문법을 활용해서 [:5]같이 할수있음 => 리스트를 반환 (OFFSET, LIMIT - SQL 용어로는)

3) Update => 데이터 수정

그냥 필드 속성값 수정 후 save(), 여러개를 수정할 때는 update() 메소드

q.question_tedt = "making change" #이렇게 

4) Delete => 데이터 삭제

Question.objects.filter(pub_date__year=2000).delete()

Question.objects.all().delete() 로 모두 삭제 가능하다.


3. 템플릿 시스템

-템플릿에서의 for, if: 템플릿 시스템에서만 사용되는 고유의 문법,

템플릿 코드 => 렌더링 => 템플릿 파일로 해석(HTML, CSV 등 텍스트 파일)

*템플릿 변수

{{ variable }}

-. (dot)은 파이썬 언어와 다름. 

ex) foo.bar 

=> foo가 dict 타입인지 확인. 맞다면 foo['bar']

=> foo의 속성. 있다면 foo.bar

=> foo가 리스트인지 확인. 맞다면 foo[bar]

*템플릿 필터

템플릿 변수에 필터를 적용하여 변수의 출력 결과 변경

-파이프 문자 (|) 사용

{{ name|lower }} # 모두 소문자로 바꿔주는 필터

-필터를 체인으로 연결 가능. 

{{ text|escape|linebreaks }} # text 중에 특수문자를 escape, 그 결과 스트링에 HTML <p> 태그를 붙여줌

-인자를 가질 수도 있음

{{ bio|truncatewords:30 }} # bio 변수값 중 앞의 30개 단어만 보여주고 줄바꿈 문자를 없애줌

{{ list|join:" // " }} # 인자에 빈칸이 있는 경우 따옴표로 묶기 (?)

{{ value|default:"nothing" }} # 변수값이 False일 경우 'nothing'으로 표시

{{ value|length }}

{{ value|striptags }} # 변수값에서 HTML 태그를 없애줌 (?)

{{ value|pluralize }} # 복수 쩝미사 필터

{{ value|pluralize:"es" }}

{{ value|pluralize:"y, ies" }}

{{ value|add:L"2" }} # 더하기, 타입에 따라 결과가 달라질 수 있음

{{ first|add:second }} # 타입의 인자를 integer라고 간주하고 덧셈 => 실패하면 문법에 따라 더하기 (리스트, string 등...)

(https//docs.djangoproject.com/en/1.10/ref/templates/builtins/) 참고


*템플릿 태그

-{% tag %}의 형식

*{% for %}

-forloop.counter: 현재까지 루프 실행한 루프 카운트(1부터)

-forloop.counter0: 0부터 카운트

-forloop.revcounter: 끝에서 현재가 몇인지 카운트 (1부터)

-forloop.revcounter0: 0부터

-forloop.first: 루프에서 첫번째 실행시 True

-forloop.last: 루프에서 마지막 실행시 True

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

*{% if %}: 변수 평가 후 True면 아래 문장 표시

-if 태그에 필터와 연산자 사용 가능, str 반환하므로 산술 연산이 안되고 length만 가능

{% if athlete_list|length > 1 %}

and, or, not, and not, ==, !=, in 등의 연산자 사용 가능

*{% csrf_token %}:

POST 방식의 oform 사용하는 코드에서 공격 방어위해 사용

<form action="." method="POST">{% csrf_token %}

와 같이 폼엘리먼트 첫줄 다음에 넣어주면 됨

# CSRF 공격(Cross-Site Request Forgery): 사이트간 요청 위조 공격

*{% url %}: 소스에 URL 하드코딩을 방지하기 위해서 

=> 원하는 URLconf 모듈만을 참조 가능

{% url 'namespace:view-name" arg1 arg2 %}와 같은 방식으로 사용

-namespace: urls.py의 include 함수에서 정의한 namespace

-argN: 뷰함수에서 사용하는 인자, 빈칸으로 여러개 구분


*{% with %} : 특정 값을 변수에 저장

{% with total=business.employees count %}

{{ total }} people works at business

{% endwith %}

=> total은 with 구문 내에서만 유효, 부하를 줄여주는 효과

*{% load %}: 사용자 정의 태그 및 필터 로딩

=> 개발자가 필요에 따라 스스로 정의하여 사용 가능

{% load somelibrary package.otherlibrary %} 와 같이 사용

=> somelibrary.py 파일 및 package/otherlibrary.py에 정의된 태그, 필터 로딩


**템플릿 주석

-한줄 주석문: {#  #} 형식

-여러줄: {% comment "optional note %}

{% endcomment %}


**HTML 이스케이프

디폴트로 HTML에 사용되는 예약 문자들을 의미르 제거한 문자로 변경해주는 기능

< : &lt; (less than)

>: &gt; (greater than)

': &#39;

" : &quot;

& : &amp; (ampersand)

이외의 자동 이스케이프 비활성화시키는 방법

-safe 필터 사용: {{date|safe }}

-{% autoescape off %}

{% endautoescape %}


**템플릿 상속: 코드 재사용, 룩앤필 일관성있게. 어렵지만 강력한 기능

{% block title %} {% endblock %} 방식으로 사용

자식 템플릿에서 {% extends 'base.html' %}을 쓰고 block문을 이어서 사용

다음 단게를 따라서 해라

1). 사이트 전체의 룩앤필을 담은 base.html

2). 하위의 섹션별 스타일을 담은 base_news.html 등을 만듬, 1단계 base.html을 상속

3). 개별 페이지의 템플릿을 만들어서 2단계 템플릿을 상속




4. 폼 처리하기: 장고의 폼 기능

**HTML에서의 폼: input 엘리먼트 외에도 actoin 속성(폼 데이터를 어디로 보낼지)고ㅑㅏ method 속성(어떤 HTTP 메소드로 보낼지)을 정해줘야함 => GET, POST뿐

=> 장고는 이중에서 POST 방식만 사용


**장고의 폼 기능 (??)

*장고는 폼처리를 위한 3가지 기능 제공

-폼 생성에 필요한 데이터를 폼 클래스로 구조화

-폼 클래스의 데이터를 렌더링하여 HTML 폼 만들기

-사용자로부터 제출된 폼과 데이터를 수신, 처리


폼도 결국은 템플릿의 일부 => 템플릿 코드에 포함되서 렌더링 절차, 3가지 과정

=> 렌더링할 객체를 뷰로 가져오기(데이터베이스에서 객체 추출)

=>그 자체를 템플릿 시스템에게 넘겨주기

=>템플릿 문법을 처리하여 HTML 마크업 언어로 변환

: 폼 객체에는 데이터가 없을 수도 있음(사용자가 데이터를 채우는게 보통)

데이터가 없는 폼: unbound form => 비어있거나 default값

데이터가 있는 폼: bound form => 제출된 데이터를 갖고 유효성 검사를 하는데 사용


*폼클래스로 폼 생성하기 => 폼도 클래스로 정의하여 간편하게 만들수있다~

모든 폼클래스는 django.forms.Form의 자식클래스로 생성

class NameForm(forms.Form):

your_name = forms.CharField(label='Your name', max_length=20)

각각의 폼 필드는 위젯 클래스를 갖고, 이는 <input type='text'>와 같은 HTML 폼 위젯으로 대응.

=> 각각의 폼 필드는 디폴트로 위젯 클래스 가짐

=> CharField: TextInput이 디폴트 위젯, 이를 textarea로 변경하려면 폼 필드 정의할 때 명시하면됨

your_name = forms.CharField(label = 'Your name', max_length=20, widget=forms.Textarea)


장고의 폼 클래스 => 모드너 필드에 유효성 검사 루틴 실행시키는 is_valid() 메소드를 가짐

=> 모든 필드가 유효하다면 True를 반환하고 cleaned_data 속성에 넣음

=> 위 코드에 대한 결과는

<label for="your_naem">Your name: </label>

<input id='your_name' type='text' name='your_name" maxlength='20'>

으로 나옴

-결과에 <form>태그나 submit은 없기 떄문에 개발자가 직접 템플릿에 넣어줘야함

=> 다음과 같이 html에서 템플릿 사용하기

<form action='/your-name/' method='post'>

{% csrf_token %}

{{ form }}

<input type='submit' value='Submit' />

</form>

=> form 변수는 뷰에서 컨텍스트 변수에 포함되어 템플릿 시스템으로 넘어감


*뷰에서 폼 클래스 처리

-앞에서 작성한 NameForm 폼 클래스와 템플릿을 사용하여 폼을 보여주고 폼 데이터를 수신하여 처리하는 뷰 작성

-폼을 처리하는 뷰는 2개 필요

=> 폼을 보여주는 뷰 + 제출된 폼을 처리하는 뷰, 장고에서는 통합하여 처리하는것을 권장(?)

==> 하나의 뷰에서 2가지 기능을 처리하기 위해서 처음 보여주는 폼과 입력 후 제출된 폼을 구분항려 처리

===> HTTP 메소드로 구분: GET 방식으로 요청받은 경우 처음 폼을 보여주고, POST 방식은 제출된 폼으로 간주


*폼 클래스를 템플릿으로 변환

-{{ form }} => label, input으로 렌더링됨

-{{ form.as_table }} =>  <tr>태그로 감싸서 테이블 셀로 렌더링

-{{ form.as_p }} => <p>태그로 감싸서 렌더링

-{{form as_ul }} => <li> 태그로 감싸도록 렌더링


5. 클래스형 뷰 (CBV)

1) 클래스형 뷰의 시작점

-가장 먼저 URLconf에서 함수형 뷰(views.xxx) 대신 클래스형 뷰(as_view())를 사용해야함

-장고의 URL 해석기는 리퀘스트 파라미터를 함수에 전달 => as_view() 클래스 메소드로 클래스로 진입: 진입 메소드

=> 클래스의 인스턴스생성, 인스턴스의 dispatch() 메소드 호출

==> dispatch(): 요청 검사, GET, POST등 어떤 HTTP 메소드로 요청됐는지 확인 후 해당 이름을 갖는 메소드로 요청 중계, 정의가 안되있으면 HttpResponseNotAllowed 익셉션

-그 이후 View 클래스 코딩(views.py)

from django.views.generic imprt View # View 클래스 안에 as_view, dispatch가 정의되어 있어서 정의하지 않아도 사용 가능

class MyView(view):

def get(self, request):

return HttpResponse('result')

2) 장점: 효율적인 메소드 구분 

-HTTP 메소드에 따른 처리 기능 코딩시, IF 함수 없이 메소드명으로 구분 가능

-HTTP 메소드(GET, POST 등..)를 수신한 후 어떻게 처리하는지

함수형 뷰에서 GET 메소드 처리 로직:

def my_view(request):

if request.method == 'GET': #이렇게 if 문으로 GET 메소드인지를 확인해야함

>클래스형 뷰에서 GET 메소드 처리 로직:

class MyView(View):

def get(self, request): # 코드 구조가 훨씬 깔끔, 메소드명 소문자기 때문에 get, post 등...

=> 내부의 dispatch() 메소드가 어떤 HTTP 메소드인지를 알아내고 요청을 중계 

3) 장점2: 상속 기능 가능

-이를 이해하려면 generic view를 알아야함: 뷰 개발 과정에서 공통으로 사용하는 기능을 추상화,

=> 이를 장고에서 미리 만들어 제공해주는 클래스형 뷰

# abtout.html 템플릿 보여주는 예제

# views.py

from django.views.generic import TemplateView

class AboutView(TemplateView):

template_name = 'about.html' # 오버라이딩하여 사용 가능

4) Generic view: 공통된 로직을 미리 개발해 놓고 제공하는 뷰

4가지 분류-

-Base View: 뷰 클래스 생성, 다른 generic view의 parents class 제공

=> View: 가장 기본이 되는 최상위 뷰

=> TemplateView: 템플릿이 주어지면 해당 템플릿 렌더링

=> RedirectView: URL이 주어지면 해당 URL로 리다이렉트

-Generic Display View: 객체의 리스트, 특정 객체의 디테일 보여줌

=> DetailView: 객체 하나에 대한 상세한 정보 보여줌

=> ListView: 조건에 맞는 여러 객체 보여줌

-Generic Edit View: 폼을 통해 객체를 생성, 수정, 삭제

=> FormView: 폼이 주어지면 해당 폼을 보여줌

=> CreateView: 객체를 생성하는 폼을 보여줌

=> UpdateView

=> DeleteView

-Generic Date View: 날짜 기반 객체의 년/월/일을 페이지로 구분

=> YearArchiveView

=> MonthArchiveView

=> DayArchiveView

### https://doce.djangoproject.com/1.10/ref/class-based-view/ 더 참고하기


5) 클래스형 뷰에서 폼처리: 함수형 뷰, View, FormVIew로 폼을 처리

FormView로 form 처리하는법

from django.views.generic.edit import FormView

class MyFormView(FormView):

form_class = MyForm # form.py 내의 클래스명

template_name = 'form_template.html' # 렌더링할 템플릿명

success_url = '/thanks/' # 리다이렉트 시킬 URL

def form_valid(self, form):  # 유효한 폼 데이터로 처리할 로직: super() 호출해야함

return super(MyFormView, self).form_valid(form)



6. 로그 남기기: Logger, Handler, Filter, Formatter ==> 이게 무슨말인지? 더 공부해야할듯.. ㅠㅠ 

1) Logger

-로깅 시스템의 시작점. 메세지를 담아두는 저장소

=> 로그 레벨: 메세지의 중요도에 따라서 

-DEBUG: 디버그용도

-INFO: 일반적, 보편적 정보

-WARNING: 덜 중요한 문제 발생 시 이에대한 정보

-ERROR: 주요 문제 발생 시 이에 대한 정보

-CRITICAL: 치명적인 문제점

=> 저장되는 메세지: 로그 레코드



02202-486-1224255-41533