HTTP Status Code
웹서버는 적절한 상태코드로서 응답해야합니다. 대표적 HTTP 응답 상태 코드
• 200 : 성공. 서버가 요청을 잘 처리했다. (OK)
• 302 : 임시 URL로 이동했다. (Redirect)
• 404 : 서버가 요청한 페이지를 찾을 수 없음. (Not Found)
• 500 : 서버 오류 발생 (Server Error)
# 아래 3종류가 200받는 형식
1 | from django.http import HttpResponse, JsonResponse |
# 아래 3종류가 302(임시url, redirect)
1 | from django.http import HttpResponseRedirect |
# 404발생시키기
1 | from django.http import Http404, HttpResponseNotFound |
# 500으로 응답하기
이는 서버에서 요청 처리 중에 예기치못한 오류 (코드오류, 설정오류) 가 발 생할 경우
(IndexError, KeyError, django.db.models.ObjectDoesNotExist, … 등)
지정 Record가 없는 것은 서버오류가 아닙니다 (!= 500)
html은 개행문자(엔터) 무시하므로
구문으로 일일히 해줘야하지만 변환해주는 것있다
1 | {{post.content|linebreaks}} 하면 <p> 구문으로 나눠주고 |
내가 데이터를 지워버리면 500이떠버림 (404가 떠야함 뜨게 만들어야함)(서버오류가 아니라 not found page이므로)
따라서 try:
except:
raise Http404하면됨.
하지만 맨날 이럴수없음
1 | #try: |
Model Relationship Fields (관계형 데이터베이스)
포스팅과 댓글, 포스팅과 글쓴이, 포스팅과 카테고리 등의 정보를 RDBMS (관계형 데이터베이스, Relational Database management System) 에 저장하기 위해서는, Relation에 대한 이해가 필요
__관계가 있는 Record끼지 서로 연결(Link) __
• ForeignKey - 1:N 관계를 표현
• ManyToManyField - M:N 관계를 표현
중간 테이블이 생성되며, ForeignKey 관계로 참조
• OneToOneField - 1:1 관계를 표현
데이터베이스 정규화
정규화: RDBMS 설계에서 중복을 최소화하게 데이터를 구조화하는 프로세스
충분히 정규화하지 않는다면, 중복 정보가 복수 개의 Row/Column에 혼재
Record 갱신/삭제 시에 관련 Row/Column에 대해서 처리되지 않을 경우, 논리적 모순 발생
경우에 따라 비정규화 과정이 필요.
1:N - 포스팅과 댓글
1 | from django.db import models |
# on_delete=models.CASCADE 이거는 ForeignKey쓸떄 2번쨰 파라미터에입력!
# post필드는 실제 sql 데이터보면 필드가 post_id라는 것으로 입력되어있다(ForeignKey)
글에 댓글을 달아놓은것을 볼수있게함 (admin페이지에서 관리함)
1
2
3
4
5@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
pass
M:N - Relation없이 포스팅과 태그
1 | class Post(models.Model): |
tip : 모델에 relation지정하는 필드들을 (‘Tag’)처럼 문자열로도 클래스 부르느것가능
# 중간테이블이 자동으로 생성됨 blog_post_tag_set테이블이 생김. 이어주는역할
# post쪽 tag쪽둘다 줄수있음.
1:1 - User와 Profile
Django 에서는 django.contrib.auth.models.User 모델을 기본 제공 User에 대한 부가적인 정보(전화번호, 주소 등)를 저장하기 위해, Profile 모델을 1:1 관계로 설계 가능
1 | from django.contrib.auth.models import User |
복습하면 startapp하면 settings.py에 앱 이름 추가하고 앱에 urls.py만들어서 from django.conf.urls import url 하고 아래에 urlpatterns = [] 추가하고
프로젝트에 urls.py에서 이 url연결 include만들기
ForeignKey와 Onetoone차이
- 생성되는 필드명은 같으나 유일성의 차이
1 | class Post(models.Model): |
알아야할것
1 | import Comment |
참고 : auth.User 모델과 관계를 맺을 때
1 | from django.conf import settings |
ForeignKey.on_delete 옵션
1측의 Row가 삭제될 경우, N측의 Row의 처리에 대한 동작을 지정 (즉 post하나삭제시 댓글들 데이터동작지정)
• CASCADE : 연결된 Row 를 일괄 삭제 (디폴트 동작)
• PROTECT : ProtectedError 예외를 발생시키며, post 삭제 방지
• SET_NULL : null=True 설정이 되어있을 때, 삭제되면 해당 필드를 null 설정
• SET_DEFAULT : 필드에 지정된 디폴트값으로 설정
• SET : 값이나 함수를 지정. 함수의 경우 호출결과값을 지정
•DO_NOTHING : 대개의 DB에서는 오류발생의 가능성이 있습니다. sqlite3는 엄격하지 않음
ForeignKey에서 related_name 지정의 필요성
- 1:N 관계에서 1측에서 N측으로 접근 시의 속성명 : 모델명소문자_set
1 | Comment.objects.create(post=post, author="양승원", message="댓글#3") |
related_name 이름 중복이 발생
user_instance.post_set 은 어떤 앱 (blog/shop) 의 Post인가?
related_name이 중복되지 않도록 지정을 해야만, makemigrations 명령이 동작
(아래예시는 post라는 모델클래스가 겹쳐서 migrate에러가뜬다.)
1 | # blog/models.py |
- 혹은 related_name을 쓰지 않도록 지정도 가능 : “+” (related_name=’+’)
save되지 않은 모델 인스턴스와 Relation은 불가
Relation은 pk로 관계를 맺는데, 초기 save() 전에는 pk 미할당 상태
• pk는 primary key를 뜻하며, 현재 id필드가 primary key이다
왜냐하면 relation을 하는것은 pk값기준으로 하기때문에 먼저존재해야되므로
ManyToManyField
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 사전작업 : 관련 Object 획득
post = Post.objects.first() #인스턴스
tag1 = Tag.objects.all()[0] #인스턴스
tag2 = Tag.objects.all()[1] #인스턴스
tag3 = Tag.objects.all()[2] #인스턴스
tag_qs = Tag.objects.all()[:3] #쿼리
# 관계에 추가
post.tag_set.add(tag1)
post.tag_set.add(tag1, tag2)
post.tag_set.add(tag1, tag2, tag3)
post.tag_set.add(*tag_qs)
# 관계에서 제거
post.tag_set.remove(tag1)
post.tag_set.remove(*tag_qs) #쿼리셋으로 여러개 변경 개꿀갯수 카운트하는 2가지 방법
1 | from blog.models import Post |
Django Template Inheritance
여러 템플릿 파일 별로 필연적으로 발생하는 중복을 상속을 통해 중복 제거 상속은 여러 번 이뤄질 수 있다
부모 템플릿은 전체 레이아웃을 정의하며, 자식 템플릿이 재정의할 block 을 다수 정의해야 한다
자식 템플릿은 부모 템플릿을 상속받은 후에 부모 템플릿의 block 영역에 대해 재정의만 가능하며 그 외 코드는 무시
템플릿 상속 문법 : 항시 자식템플릿 코드 내, 최상단에 쓰여져야합니다.
extends "부모템플릿경로" %} ``` 1
2
3
4
5
6
- 즉 상속을 사용하면 중복을 피해서 템플릿들 작성가능
- 부모 탬플릿 (자식 재정의할곳 block)
-<meta charset="utf-8" /> <title>AskDjango Blog</title>
<h1>AskDjango Blog</h1> {% block content %} #block 이름이 content이므로 템플릿내에서유일한이름임 {% endblock %} <hr/> © 2017. AskDjango
{% extends "blog/layout.html" %} #최상단 무조건해야함 {% block content %} {% for post in post_list %} {{post.title }} {% endfor %} {% endblock %}1
2
3
4
- 자식 탬플릿이 간단해짐 (block영역만 지정가능, 나머지 것들은 모두 무시됨)
-1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
## 2단계의 상속을 추천
프로젝트 전반적인 레이아웃 템플릿 : askdjango/templates/layout.html
장고는 하나의 프로젝트(하나의 사이트) 다수의 앱(기능들) 비슷한 레이아웃 즉,
프로젝트에서 레이아웃>>각 앱별 레이아웃 템플릿>> 각 템플릿
tip: 프로젝트 디렉토리 안에 templates폴더만들고 넣으면 정리쉬움. 경로는 setting.py에 템플릿에 경로 추가해줘야함('DIRS': [
os.path.join(BASE_DIR, 'askdjango', 'templates')
],)
tip: 부모를 건드리거나 내용 추가하면 아래것들 다 추가되서 편함
- 각 앱 별 레이아웃 템플릿 #1 : blog/templates/blog/layout.htm
- l - 각 템플릿 #1 : blog/templates/blog/post_list.html
- 각 템플릿 #2 : blog/templates/blog/post_detail.html
- 각 템플릿 #3 : blog/templates/blog/post_form.html
- 각 앱 별 레이아웃 템플릿 #2 : shop/templates/shop/layout.html
- 각 템플릿 #4 : shop/templates/shop/item_list.html
- 각 템플릿 #5 : shop/templates/shop/item_detail.html
- 각 템플릿 #6 : shop/templates/shop/item_order_form.html
Template Loader에 대한 이해가 필요 (at EP13)
<자식탬플릿에서 추가하고 싶은것은 똑같은 ```{% block 이름 %}``` 쓰면 적용됨 ```{% endblock %}
Django Template Loader 꼭알자
다수 디렉토리 목록에서 지정 상대경로를 가지는 템플릿을 찾음
•__app_directories.Loader 와 filesystem.Loader __
위 Loader를 통해, 템플릿 디렉토리가 있을 후보 디렉토리 리스트를 작성 합니다. 이는 장고 서버 초기 시작시에만 1회 작성됩니다.
주로 아래 함수를 통해 Template 파일들을 활용합니다
• render : 템플릿을 렌더링은 문자열로 HttpResponse 객체를 리턴
• render_to_string : 템플릿 렌더링한 __문자열을 리턴 __ 즉 str 리턴
1 |
|
app_directories.Loader
settings.INSTALLED_APPS에 설정된 앱 디렉토리 내 templates 경로 에서 템플릿 파일을 찾습니다. ( ‘APP_DIRS’: True,이므로 자동으로 찾음)
앱 디렉토리 별로 각 앱을 위한 템플릿 파일을 위치
- blog앱용 템플릿은 blog/templates/ 경로에 두는 것이 관리성 좋음
- shop앱용 템플릿은 shop/templates/ 경로에 두는 것이 관리서 좋음
filesystem.Loader
프로젝트 전반적으로 쓰일 템플릿 파일은 “특정앱/templates/“ 경로가 아닌 별도의 경로에 저장이 필요(프로젝트 settings.py 에 템플릿에 DIR에 리스트형식으로추카 )
1 | # 프로젝트/settings.py 에 후보지 디렉토리 경로 지정 |
실행과정
render 혹은 render_to_string 함수가 호출되면, 미리 작성된 템플릿 후 보 디렉토리들을 차례대로 순회하며 템플릿 파일을 찾습니다. render(request, ‘blog/post_list.html’) 이 호출되면
blog/templates/blog/post_list.html 파일 체크, 없으면 다음 shop/templates/blog/post_list.html 파일 체크, 없으면 다음 diary/templates/blog/post_list.html 파일 체크, 없으면 다음
프로젝트명/templates/blog/post_list.html 파일 체크, 없으면
다음 마지막까지 검사해서 없을 경우, TemplateDoesNotExist 예외 발생
순서대로 있는지 검사하므로 blog에 있다면 shop에있는 같은 이름의 템플릿은 평생못부름따라서 템플릿디렉토리안에 앱명디렉토리안에 템플릿넣어놓자
따라서 습관적으로 blog_post_list.html 을 만들기 or 템플릿디렉토리안 해당 앱이름으로 디렉토리 만들고 그안에 템플릿 쓰면됨.
1 | 예시 |
render(request, "blog/post_list.html") 로 호출시킴
장고 앱은 재사용할려고 만듬 즉 거의 모든 파일은 앱 디렉토리 안에 넣어놓자
전반적으로 쓸 템플릿은 프로젝트 레벨에 쓸 템플릿을 넣는것은 프로젝트 디렉토리에 템플릿에 넣자 그리고 꼭 settings.py 에 템플릿에 dir에 경로 추가해줘야함 (자동추가x)
render_to_string 샘플(템플릿으로 html, 이메일, JS 등등가능)
accounts/signup_welcome.txt
1 | 안녕하세요. {{ name }}님. {{ name }}님께서는 {{ when }}에 가입하셨습니다. |
만들기
URL Reverse
urls.py 변경만으로 “각 뷰에 대한 URL”이 변경되는, 유연한 URL시스템
1 | urlpatterns = [ |
을 아래와 같이 바꾼다
1 | urlpatterns = [ |
이것이 URL Reverse의 힘!!
URL Reverse 의 혜택(템플릿>url찾음)
• 개발자가 일일이 URL을 계산하지 않아도 됩니다. 만세 ~
(뷰는 안바뀌고 url주소만바뀜)
• URL이 변경되더라도, URL Reverse가 변경된 URL을 추적
• 누락될 일이 없어요.
예시
내가 list를 만들고 싶음
blog앱 Post목록을 볼려면 post_list뷰를 호출해야되니깐, URLConf 뒤 적뒤적거리며 URL계산계산 @_@;;; /blog/ 주소로 접근하면 되겠네.
1
2
3
4
5
6<!-- blog/templates/blog/layout.html -->
<a href="/blog/">블로그 글 목록</a>
<!-- blog/templates/blog/post_form.html -->
<a href="/blog/">블로그 글 목록</a>
<!-- blog/templates/blog/comment_form.html -->
<a href="/blog/">블로그 글 목록</a>문제점은 blog앱을 다른 프로젝트에 쓸려고 옮겼는데, r’^blog/‘ 에서 r’^weblog/‘로 다시 다 변경해야함
뷰 url계산은 장고! 시키자
URL이 변경될 때마다, 이 URL을 참조하고 있는 코드를 일일이 찾아서 변 경하는 것은 너무 번거롭고, 수정건을 누락시킬 여지도 많다
각각의 url패턴이란? url(~~)형식을 말함
이때 urls.py 에서 url(
~ ,, name=’post_detail’) 라고 url이름을 달아주면
1 | {% raw %} |
URL Reverse를 수행하는 4가지 함수
• reverse 함수 : 매칭 URL이 없으면 NoReverseMatch 예외 발생 (str리턴)
reverse(‘blog:post_detail’, kwargs={‘id’: 10})
reverse(“blog:post_detail”, args=[10])
• resolve_url 함수 : 매칭 URL이 없으면 “인자 문자열”을 그대로 리턴 (str리턴)
내부적으로 reverse 함수를 사용
resolve_url(‘blog:post_detail’, 10)
• redirect 함수 : 매칭 URL이 없으면 “인자 문자열”을 URL로 판단 (HttpR리턴)
내부적으로 resolve_url 함수를 사용
• url template tag : 내부적으로 reverse 함수가 사용 (str)
예시(프로젝트 안에 이름동일하면 네임스페이스 지정!)
네임스페이스는
path()쓰자 그리고 네임 스페이스는 이제 그해당 앱에 url에
app_name = “blog” 추가하면 그게 네임 스페이스가됨
이렇게 include안에 지정하면 이제 하위에 url패턴 이름이 겹쳐도 사용가능
템플릿에서 사용시 {%url "blog:post_detail" post.id %} post.id는 넘겨줄인자
tip: 인자 넘겨줄때 포지션args or 키워드args존재.
reverse(“blog:post_detail”, args=[10])
reverse(‘blog:post_detail’, kwargs={‘id’: 10})
URL Reverse, 뷰 이름을 지정하는 2가지 방법 (2) 와 의 조합
- <include() namespace>
- <url() name>
모델 클래스내 get_absolute_url 멤버함수
강추기능
해당 post인스턴스의 디테일을 볼수있는 url을 아는방법이 예시임
models.py 파일에 post모델 클래스에
def get_absolute_url(self):
return reverse(‘blog:post_detail’, args=[self.id])
추가하기
이제 얻는 방법은 4가지
1 | from blog.models import Post |
즉 어떠한 데이터 모델에 디데일뷰를 만들게되면 습관적으로 넣어놓는것이 편하다
그 외 활용
• CreateView, UpdateView 에 success_url을 제공하지 않을 경우, 해당 model instance 의 get_absolute_url 주소로 이동이 가능한지 체크하고, 이동이 가능할 경우 이동 • 생성/수정하고나서 Detail화면으로 이동하는 것은 자연스러운 시나 리오
특정 모델에 대한 Detail뷰를 작성할 경우, Detail뷰에 대한 URLConf설 정을 하자마자, 필히 get_absolute_url설정을 해주세요. 코드가 보다 간 결해집니다