1. URL vs URI
# list/ 까지는 urls.py에 정의되어 있고 ? 뒤는 모두 변수 취급이기 때문에 정상표시 됨
# view에서 page = int(request.GET.get('p', 1))로 처리하므로 지정된 변수가 아니면 모두 1페이지 표시
http://127.0.0.1:8000/board/list/?p=1 # 정상 표시 (1페이지)
http://127.0.0.1:8000/board/list/?p=2 # 정상 표시 (2페이지)
http://127.0.0.1:8000/board/list/?test # 정상 표시 (1페이지)
# list/p 는 변수 취급이 아닌 url로 취급됨
http://127.0.0.1:8000/board/list/p # 페이지 오류
2. Template 생성
{% if boards.has_previous %} # 현재 paginator의 페이지의 이전 페이지가 있다면
{% if boards.has_next %} # 현재 paginator의 페이지의 다음 페이지가 있다면
{{ boards.number}} # 현재 페이지의 번호
{{ boards.paginator.num_pages}} # paginator의 전체 페이지 번호 (수)
href="?p={{ boards.previous_page_number }}" # 현재 URL+?p = 현재 페이지의 이전 페이지
href="?p={{ boards.next_page_number }}" # 현재 URL+?P = 현재 페이지의 다음 페이지
3. View 생성
all_boards = Board.objects.all().order_by('-id') # Board 테이블에 있는 모든 행들을 id 역순으로 불러옴
paginator = Paginator(all_boards, 2) # 불러온 행들을 2개씩 페이징
page = int(request.GET.get('p', 1)) # URL/?변수들 에서 변수 p의 값을 추출, 없다면 1로 설정
boards = paginator.get_page(page) # 해당 page에 존재하는 board 행만을 넘김
4. 페이징 결과 화면
1. Tag app 생성 및 등록
python manage.py startapp tag
2. Model 생성 및 Migration
3. Board Model 수정
4. N:M 관계 테이블
5. Admin 등록
6. Admin add 화면
7. Template 변경
{% for tag in board.tags.all %} # 해당 board 게시글에 지정된 모든 tag 행들
{{ tag.name }} # {{ tag }} 와 동일 (__str__함수)
{{ board.tags.all|join:", "}} # 이렇게 '|' 이용하여 문자열 함수 기능 사용할 수 있음
# 이 코드 한 줄로 동일한 결과 얻어낼 수 있음
* {% for loop %} 으로 출력되는 문자 사이에는 ' ' 공백 문자 들어감 (ex. 태그1, 태그2 이런식)
8. 태그 출력 화면
1. 게시판 글 쓰기 form 수정
2. 게시판 글 쓰기 view 수정
tags = form.cleaned_data['tags'].split(',') # 입력된 태그들을 ',' 구분자로 분리한 뒤 리스트 반환 (' ' 스페이스바 문자까지 태그로 인식)
_tag, _ = Tag.objects.get_or_create(name=tag) # 2개의 반환값을 받는데 '_'는 이용하지 않겠다는 의미
board.tags.add(_tag) # board 테이블의 tags 속성에 _tag 행을 삽입 (=참조_