[ 배운 내용 ]
Chapter 1. Django 시작하기
Chapter 2. Django 프로젝트
Chapter 3. Django Model
Chapter 4. Django Template
Chapter 5. 장고 모델 활용
Chapter 6. 장고 ORM
- Manager() & QuerySet
- Manager() 메서드 : 조회(상세조회), 추가, 수정, 삭제
Chapter 7. 장고 Form
- CSRF Middleware
- HttpRequest
- Form 객체
- URL Reverse
- ModelForm 객체
Chapter 6. 장고 ORM
이전까지는 장고에서 ORM 방식으로 .all()이나 .get() 메서드로 단순 조회하는 법만 배웠다. 이번에는 SQL 상에서 WHERE이 적용됐을 때와 같은 조건을 포함한 조회, 추가, 수정, 삭제에 대해 배워보았다.
Manager() 클래스
장고에서는 Post.objects.all()과 같이 모델 클래스의 objects를 사용해서 ORM 방식을 사용한다.
장고의 Model 클래스 내부에는 objects라는 변수가 정의되어 있는데, 이는 Manager 라는 클래스의 인스턴스이다. ( objects = models.Manager() ) 즉, .all .get 등의 메소드는 모두 Manager 객체의 메소드인 것이다.
장고의 Manager() 클래스는 다양한 ORM 메소드를 제공하면서 ORM 처리를 담당한다.
아래의 장고 공식 문서에서 Manager()의 ORM 메소드들을 확인 할 수 있다.
https://docs.djangoproject.com/en/2.1/ref/models/querysets/
Django
The web framework for perfectionists with deadlines.
docs.djangoproject.com
Manager & QuerySet
Manager()에서 제공되는 메소드들은 쿼리셋(QuerySet)을 리턴하는 메서드와 그렇지 않은 메서드로 나눌 수 있다.
쿼리셋(QuerySet)이란 SELECT한 결과 즉, 서브쿼리라고 생각하면 된다. QuerySet() 객체는 Manager()가 갖고 있는 메서드들을 그대로 갖는다. 따라서 쿼리셋을 리턴하는 메서드는 SQL에서 서브쿼리를 사용하는 것과 같이 2차 쿼리가 가능해진다. ex) all(), filter(), ...
쿼리셋을 리턴하지 않는 메서드들은 모델인스턴스(get()), 숫자(count()), True/False(exists()) 등을 리턴하며 바로 쿼리의 결과로 사용이 가능하다.
예시로 아래 코드를 보면 .all() 메서드로 받아온 post_list의 타입을 보면 QuerySet이라는 것을 볼 수 있다.
반면에 .get()메서드로 받아온 post는 타입이 그냥 Post 클래스의 인스턴스로 나오는 것을 볼 수 있다.
따라서 아래처럼 쿼리셋인 post_list에 대한 2차 쿼리를 통해 값을 얻을 수 있다.
Manager()의 조회 메서드
- all() : 모든 인스턴스 조회
모델명.objects.all()
- order_by() : 정렬
모델명.objects.order_by('필드명')
QuerySet객체명.order_by('필드명')
order_by() 메서드의 경우 order_by를 해준다고 해서 테이블 자체에 정렬이 적용되는 것은 아니다.
모델 클래스(테이블) 단위로 적용을 해주고 싶다면, Model객체 안에 Meta라는 내부 클래스를 만들고 그 안에 작업을 정의해 줄 수 있다.
ex)
Post 모델 객체의 내부에 Meta라는 내부 클래스를 만들어주었고, 그 안에 ordering = ['id'] 로 id필드에 대한 정렬을 하도록 설정해주었다. ( ['-id'] 는 거꾸로 정렬 )
- first(), last() : 첫번째, 마지막 인스턴스 조회
모델명.objects.first()
QuerySet객체명.first()
모델명.objects.last()
QuerySet객체명.last()
- count() : 개수 세기
모델명.objects.count()
QuerySet객체명.count()
- exists() : 있는지/없는지 ==> True/False 리턴
QuerySet객체명.exists()
[ WHERE절 조건조회 ]
filter()와 exclude()가 있는데, 주고 filter()를 많이 쓰기 때문에 filter() 함수 기준으로 설명하겠다.
- filter() : 조건에 맞는 데이터만
모델명.objects.filter(조건)
QuerySet객체명.filter(조건)
- exclude() : 조건에 맞지 않는 데이터만
모델명.objects.exclude(조건)
QuerySet객체명.exclude(조건)
SQL 문의 경우
WHERE name LIKE '%김%'
WHERE age >= 20
과 같은 식으로 조건을 준다.
하지만 Manager()의 메서드들은 파이썬 함수이기 때문에 파이썬의 인자 형식으로 조건을 표현해주어야 한다.
파이썬 인자 형식에는
- 위치 인자 ex) sum(10,20)
- 키워드 인자 ex) sum(x=10, y=20)
가 있는데, 조건을 표현할 때는 키워드 인자 형식을 사용한다.
조건은 아래와 같은 형식으로 기술한다.
# filter()함수 키워드 인자 조건 형식
필드명__lookup명 = 값
lookup명의 종류는 다양한데, 대표적인 몇개를 정리하면 다음과 같다.
- exact : =, IS NULL 등과 같음
- contains : LIKE '%~~%' 등과 같음 (문자열 포함)
- icontains : contains와 동일한데 대소문자 구분 X
- in : IN
- gt, gte, lt, lte : >, >=, <, <=
- startswith, endswith : LIKE의 시작/끝 문자열 확인 조건과 같음
- range : BETWEEN (날짜 형식도 가능)
- year, month, day : 날짜 체크
예시
# exact ==> id=3
id__exact=3
# exact ==> region='Asia'
region__exact='Asia'
# in ==> SELECT ... WHERE id IN (1, 2, 3);
id__in=[1, 2, 3]
# gte ==> SELECT ... WHERE id >= 4;
id__gte=4
# range ==> SELECT ... WHERE id BETWEEN 1 AND 5;
id__range=(1,5) # 튜플 형식으로
[ 조건이 여러개인 경우 ]
- AND : filter()인자에 ,로 조건 여러개 주기
Post.objects.filter(region='Asia', body__contains='발리')
- OR : filter() 인자로 조건을 넣어주고, |로 구분 + 각 조건은 Q()메서드의 인자로 넣어준다.
from django.db.models import Q
Post.objects.filter( Q(region='Asia') | Q(body__contains='발리') )
.get()메소드 같은 경우는 리턴값(결과값)이 1개여야 정상 처리된다. 결과값이 0개일 경우에는 Does Not Exist오류, n개일 경우에는 MultipleObject오류가 나타난다. 따라서 결과가 1개만 나올 수 있는 primary key 조건에 사용한다.
Manager()의 추가 메서드
- Model의 save() 사용
post = Post(title='제목1', body='내용1')
post.save()
- Manager()의 create() 사용
Post.objects.create(title='제목1', body='내용1')
create()메서드는 INSERT한 인스턴스를 리턴해준다.
Manager()의 수정 메서드
- Model의 save() 사용
post = Post.objects.get(title='제목1')
post.title = '제목2'
post.region = '지역2'
post.save()
- QuerySet의 update() 사용
qs = Post.objects.filter(title='제목1')
qs.update(title='제목2', region='지역2'))
filter결과가 여러개의 레코드일 경우 인스턴스들의 리스트 형식으로 된 QuerySet이 반환된다.
이럴 경우 update를 해주면 쿼리셋의 모든 모델 인스턴스들이 일괄적으로 수정된다.
update()는 수정된 레코드 수를 리턴해준다.
Manager()의 삭제 메서드
- Model의 delete() 사용
post = Post.objects.get(title='제목1')
post.delete()
- QuerySet의 delete() 사용
qs = Post.objects.filter(title='제목1')
qs.delete()
Chapter 7. 장고 Form
일반적으로 장고에서는 화면에서 HTML form태그를 통해 입력을 받고, 입력 결과를 사용해서 DB에 작업을 할 때, 동일한 URL을 사용하면서 요청 방식에 따라 GET / POST 2가지로 나눠서 작업이 이루어진다.
먼저 클라이언트 쪽에서 form태그가 있는 화면을 불러오기 위한 GET 요청을 보낸다. 서버에서 요청을 받으면 템플릿 페이지를 응답하면서 csrf 토큰을 발급해준다.
이 후, 클라이언트가 form태그에 값을 입력한 뒤, 입력한 값을 서버로 보내기 위해 POST 요청을 보낸다. 서버 쪽에서 요청을 받으면 csrf 토큰을 검사해서 요청을 보낸 곳을 확인하고 나서 입력받은 데이터를 처리한다. (fail 시에 403 error로 응답)
이렇게 토큰을 확인하기 때문에 제 3자가 대신 요청을 보내는 CSRF공격을 방지할 수 있다.
장고에서는 기본적으로 다양한 미들웨어가 적용되어 있다. 그 중 csrf 미들웨어의 존재로 인해서 위와 같은 처리가 이루어지는 것이다.
장고 프로젝트의 settings.py의 MIDDLEWARE를 보면 CsrfViewMiddleware가 기본적으로 적용되어 있는 것을 확인해볼 수 있다.
따라서 제대로 응답을 받기 위해서는 HTML 템플릿에서 {% csrf_token %}을 넣어주어야 서버로부터 발급받은 csrf 토큰을 갖고 있다가 POST 요청 시에 같이 보내주면서 서버로부터 제대로 응답을 받을 수 있다.
몇시간동안 글 쓰던거 날라가서 멘탈 나갔으므로 이후 내용은 대충 정리하겠음
자세한 내용은 강의록 보기
HttpRequest
클라이언트와 서버 간에 요청과 응답은 HttpRequest와 HttpResponse를 주고받으며 이루어짐
HttpRequest의 여러 속성으로 다양한 값을 뽑아서 활용 가능
- method : 요청 방식 정보 (GET / POST)
- GET : GET 방식으로 전달된 내용 (딕셔너리 형식)
- POST : POST 방식으로 전달된 내용 (딕셔너리 형식)
- FILES : 업로드된 파일 정보 (딕셔너리 형식)
장고 Form
장고 Form으로 form 위젯 생성을 간단하게 할 수 있음
[ GET 방식 입력 페이지 응답 ]
- 장고 Form 클래스를 선언하고, 필드 속성으로 입력 폼 처리
[ POST 방식 서비스 처리 응답 ]
- HttpRequest.POST 값을 장고 Form 객체에 바인딩
- 장고 Form의 is_valid() 메서드를 호출해서 유효성 검사
- 유효하지 않으면 오류메세지 + 입력페이지 응답(돌아가기)
- 유효하면 입력값들을 cleaned_data 변수에 저장함. cleaned_data를 기반으로 서비스 처리 진행됨
장고 Form의 필드를 HTML form태그로 변환할 때는 장고 Form에서 제공하는 다음의 메소드 사용
- as_p() : HTML Form 태그를 <p> 태그로 분리
- as_ul() : HTML Form 태그를 <li>태그로 분리
- as_table() : HTML Form 태그를 <tr>태그로 분리
앱의 forms.py 파일에 Form 클래스 선언해준다.
예시
URL Reverse
URL의 변화에 따른 유연한 대처를 위해 URL Reverse 함수를 사용하는 것이 좋다.
- reverse()
- resolve_url()
- redirect() : 다른 페이지로 응답하는 경우 사용 (내부적으로는 resolve_url을 사용)
위 함수들은 이동할 경로를 문자열로 리턴시켜준다.
urls.py에서 각 경로에 name으로 경로 이름을 지정해주고, 다른 앱과 같은 경로 이름의 중복을 방지하기 위해 app_name으로 앱에 대한 경로 이름도 지정해준다.
- reverse() 예시
- reverse() & resolve_url() 비교
- 다 비슷한데, 경로에 인자가 들어가는 경우가 다름
- url 태그 : {% url %}
==> 템플릿 페이지에서 URL Reverse를 사용하기 위해 url 태그를 넣어준다.
==> 내부적으로 reverse 함수 호출
- get_absolute_url()
resolve_url()에 경로이름(URL)이 아닌 모델 인스턴스를 넣을 경우에는, 경로이름을 리턴하도록 해당 모델 클래스에 내부적으로 정의된 메소드를 자동으로 호출한다. 이렇게 되도록 하려면 모델 클래스 내부에 get_absolute_url() 메서드를 선언해야 한다.
get_absolute_url()는 reverse()를 통해 경로이름을 리턴해주도록 한다.
ModelForm
Form 클래스를 직접 생성할 필요 없이 모델을 기반으로 장고에서 알아서 만들어준다.
ModelForm을 사용해서 Form 클래스보다 더 간단한 코드로 Create, Update, Delete 작업 가능
예시
- 뷰 함수 - Create
- 뷰 함수 - Update
- 뷰 함수 - Delete
따라서 장고 활용 시에 HTML form 입력 화면을 만드는 방법은 총 3가지가 있다.
- HTML 코드로 직접 form 태그 구현
- forms.py에 forms.Form 클래스 상속받은 클래스 생성
- forms.py에 forms.ModelForm 클래스 상속받은 클래스 생성
어느 방식을 사용해도 상관 없지만 2,3번 같이 장고의 form 클래스를 사용해서 간단하게 파이썬 코드로 구현할 수 있다는 것을 알아두자
'KT AIVLE School' 카테고리의 다른 글
(18주차 - 22.11.14) Web App 개발2 - 장고(Django) Template, Model간 관계 설정 (0) | 2022.11.14 |
---|---|
(17주차 - 22.11.11) Web App 개발1 - 장고(Django) 프로젝트 생성, Model, View (0) | 2022.11.11 |
(17주차 - 22.11.09~22.11.10) SQL - MySQL (0) | 2022.11.09 |
(17주차 - 22.11.07~22.11.08) 웹 프로그래밍 - 자바스크립트 (JavaScript), Vue.js (0) | 2022.11.07 |
(16주차 - 22.11.03~22.11.04) 가상화 클라우드2 - 쿠버네티스(k8s) (0) | 2022.11.03 |