Board project - 2

[ Board project ]

  • get_object_or_404, get_list_or_404

    • 데이터가 하나도 없다면 에러 발생
    • views.py 수정
      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
      33
      34
      35
      36
      # 해당 모듈 추가
      from django.shortcuts import render, get_object_or_404, redirect, get_list_or_404

      # document_list의 documents 수정
      # get_list_or_404 사용
      def document_list(request):
      # documents = Document.objects.all()
      documents = get_list_or_404(Document) # objects.all()을 포함하는 코드
      return render(request, 'board/document_list.html',{'object_list':documents})

      # document_update의 documents 수정
      # get_object_or_404 사용
      def document_update(request, document_id):
      # 객체를 불러와서, 데이터를 수정
      if request.method == "POST":
      # document = Document.objects.get(pk=document_id)
      document = get_object_or_404(Document, pk=document_id)

      form = DocumentForm(request.POST, request.FILES, instance=document)

      if form.is_valid():
      document = form.save()
      return redirect(document)
      else:
      # document = Document.objects.get(pk=document_id)
      document = get_object_or_404(Document, pk=document_id)
      form = DocumentForm(instance=document)

      return render(request, 'board/document_update.html',{'form':form})

      # document_detail의 documents 수정
      # get_object_or_404 수정
      def document_detail(request, document_id):
      # document = Document.objects.get(pk=document_id)
      document = get_object_or_404(Document, pk=document_id)
      return render(request, 'board/document_detail.html', {'object':document})
  • paging 기능 추가

    • 기능 구현 포인트
      • 현재 페이지가 몇 페이지인지 생각한다.
      • 페이지 당 개수를 몇으로 할 것인지 생각한다.
    • views.py의 document_list(request) 수정

      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
      33
      # 모듈 추가
      import math

      def document_list(request):
      # QuerySet
      # 1. 객체를 선택
      # 2. 객체 생성
      # 3. 객체 필터링
      # 4. 객체 삭제
      page = int(request.GET.get('page', 1))

      # 페이징 기능을 구현
      # 페이지 당 개수
      paginated_by = 3

      # QuerySet 객체 슬라이싱 할 때 [시작번호:끝번호]
      # 1 = 0 부터 ===== page*paginated_by
      # 2 = paginated_by*(page-1) ==== 6
      # 3 = paginated_by*(page-1) ==== 9

      total_count = len(documents)
      total_page = math.ceil(total_count/paginated_by)
      page_range = range(1, total_page+1)
      # 전체 개수 = 전체 페이지 수
      start_index = paginated_by * (page - 1)
      end_index = paginated_by * page

      documents = get_list_or_404(Document)
      documents = documents[start_index:end_index]

      return render(request, 'board/document_list.html',{'object_list':documents,
      'total_page':total_page,
      'page_range':page_range})
    • document_list.html 수정

      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
      {% extends 'base.html' %}
      {% block title %}
      Photo List
      {% endblock %}

      {% block content %}
      <div class="row">
      <div class="col"></div>
      <div class="col-12">
      <table class="table table-striped">
      {% for object in object_list %}
      <tr>
      <td>{{object.id}}</td>
      <td>{{object.title}}</td>
      <td>{{object.author.username}}</td>
      <td>{{object.updated}}</td>
      </tr>
      {% endfor %}
      </table>
      <!--// Pagination 적용 //-->
      <nav aria-label="Page navigation example">
      <ul class="pagination justify-content-center">
      {% for page in page_range %}
      <li class="page-item"><a class="page-link" href="{% url 'board:list' %}?page={{page}}">{{page}}</a></li>
      {% endfor %}
      </ul>
      </nav>
      </div>
      <div class="col"></div>
      </div>
      {% endblock %}
  • 검색 기능 추가

    • 검색 기능을 구별하는 위치
      1. DB 질의문 - like 구문
      2. 코드 레벨 검색(python 구문)
    • 검색 기능을 구현 순서
      1. 먼저 검색어를 제대로 받았는지 확인
      2. filter 적용
        • 어떤 항목으로 할 것인가? - ex) 작성자, 제목, 내용
        • 어떤 옵션으로 할 것인가? - ex) 내용 중에 단어를 시작, 중간, 끝에서 검색
    • views.py의 document_list(request) 수정

      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
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
         # 모듈 추가
      from django.db.models import Q

      def document_list(request):
      # QuerySet
      # 1. 객체를 선택
      # 2. 객체 생성
      # 3. 객체 필터링
      # 4. 객체 삭제
      page = int(request.GET.get('page', 1))
      paginated_by = 3

      """
      username => Q(author__username__icontains=search_key)
      title => Q(title__icontains=search_key)
      text => Q(text__icontains=search_key)
      q1|q2|q3
      if search_key and search_type:
      documents = get_list_or_404(Document, q1|q2|q3)
      """
      """
      필드명 = "값" 매칭
      필드명__exact = "값" 매칭
      필드명__iexact = "값" 대소문자 구분없이 매칭

      __startswith, __istartswitch 값으로 시작
      __endswith, __iendswith 값으로 끝
      __contains, __icontains 값을 포함하는지

      ForeignKey 매칭
      필드명__해당모델의필드명 매칭
      필드명__해당모델의 필드명__옵션 위와 동일하게 동작

      __gt=값, __gte=크다, 크거나 같다.
      ex) created__gt = 오늘 => 작성일이 오늘보다 크다.
      __lt=값, __lte=작다, 작거나 같다.
      ex) created__lt = 오늘 => 작성일이 오늘보다 이전
      ex) 판매시작일__lte = 오늘 => 판매시작일 설정값이 오늘보다 작거나 같으면 판매 시작
      """
      """
      objects.filter() : filter 메서드에 들어가는 매개변수들은 항상 and 연산을 한다.
      or 연산을 하고 싶어서 Q 객체를 사용한다.
      사용법은 filter에 들어가는 매개변수의 작성법과 똑같다.

      Q() | Q() = or
      Q() & Q() = and
      ~Q() = not

      Q 객체를 쓰려면 맨뒤에 일반 필터를 써야한다.
      Q 객체 앞으로 일반필터를 사용하면 안된다.

      ex) Document.objects.filter(third_q , default_q | second_q)
      -> third_q와 default_q | second_q의 and라는 의미
      """

      # 검색 사용방법
      # documents = Document.objects.filter(title__icontains='검색어')
      # ex) documents = get_list_or_404(Document,title__icontains='검색어')

      # request.METHOD.get -> 아이템 1개
      # request.METHOD.getlist -> 리스트형태로
      search_type = request.GET.getlist('search_type', None)

      search_key = request.GET.get('search_key', None)

      if search_key and search_type:
      q1 = Q(author__username__icontains=search_key) if 'author' in search_type else Q()
      q2 = Q(title__icontains=search_key) if 'title' in search_type else Q()
      q3 = Q(text__icontains=search_key) if 'text' in search_type else Q()

      documents = get_list_or_404(Document, q1|q2|q3)
      else:
      documents = get_list_or_404(Document)

      # 다른 방법
      # search_q = None
      #
      # if search_key and search_type:
      # if 'author' in search_type:
      # temp_q = Q(author__username__icontains=search_key)
      # search_q = search_q | temp_q if search_q else temp_q
      # if 'title' in search_type:
      # temp_q = Q(title__icontains=search_key)
      # search_q = search_q|temp_q if search_q else temp_q
      # if 'text' in search_type:
      # temp_q = Q(text__icontains=search_key)
      # search_q = search_q | temp_q if search_q else temp_q
      #
      # documents = get_list_or_404(Document, search_q)
      # else:
      # documents = get_list_or_404(Document)

      total_count = len(documents)
      total_page = math.ceil(total_count/paginated_by)
      page_range = range(1, total_page+1)
      start_index = paginated_by * (page - 1)
      end_index = paginated_by * page

      documents = documents[start_index:end_index]

      return render(request, 'board/document_list.html',{'object_list':documents,
      'total_page':total_page,
      'page_range':page_range})
    • document_list.html 수정

      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
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      {% extends 'base.html' %}
      {% block title %}
      Photo List
      {% endblock %}

      {% block content %}
      <div class="row">
      <div class="col"></div>
      <div class="col-12">
      <table class="table table-striped">
      {% for object in object_list %}
      <tr>
      <td>{{object.id}}</td>
      <td>{{object.title}}</td>
      <td>{{object.author.username}}</td>
      <td>{{object.updated}}</td>
      </tr>
      {% endfor %}
      </table>
      <nav aria-label="Page navigation example">
      <ul class="pagination justify-content-center">
      {% for page in page_range %}
      <li class="page-item"><a class="page-link" href="{% url 'board:list' %}?page={{page}}">{{page}}</a></li>
      {% endfor %}
      </ul>
      </nav>

      <!--// checkbox 적용 //-->
      <form action="" method="get" id="search_form" class="">
      {%csrf_token%}
      <div class="form-row align-items-center justify-content-center">
      <div class="form-check form-check-inline">
      <input class="form-check-input" type="checkbox" name="search_type" id="inlineCheckbox1" value="author">
      <label class="form-check-label" for="inlineCheckbox1">작성자</label>
      </div>
      <div class="form-check form-check-inline">
      <input class="form-check-input" type="checkbox" name="search_type" id="inlineCheckbox2" value="title">
      <label class="form-check-label" for="inlineCheckbox2">제목</label>
      </div>
      <div class="form-check form-check-inline">
      <input class="form-check-input" type="checkbox" name="search_type" id="inlineCheckbox3" value="text">
      <label class="form-check-label" for="inlineCheckbox3">본문</label>
      </div>
      </div>
      <!--// search 기능 추가 //-->
      <div class="form-row align-items-center justify-content-center">
      <div class="col-sm-3 my-1">
      <input type="text", class="form-control" placeholder="Search Keyword" name="search_key">
      </div>

      <div class="col-auto my-1">
      <button type="submit" class="btn btn-primary">Search</button>
      </div>
      </div>
      </form>
      </div>
      <div class="col"></div>
      </div>
      {% endblock %}
  • python shell로 검색을 연습해보자.

    1
    $ python manage.py shell
    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
    33
    34
    35
    36
    37
    38
    39
    from board.models import *

    Document.objects.filter(pk=1)

    Document.objects.filter(pk=2)

    Document.objects.filter(pk=2, title='Image Test 2')

    Document.objects.filter(pk=2, title='Image Test 3')

    Document.objects.filter(title__startswith='Image')

    Document.objects.filter(title__endswith='12')

    Document.objects.filter(title__iexact='image')

    Document.objects.filter(title__iexact='ima')

    Document.objects.filter(title__istartswith='image')

    Document.objects.filter(title__icontains='ge')

    Document.objects.filter(title__icontains='es')

    Document.objects.filter(category__name='Cosmetic Question')

    Document.objects.filter(category__name__endswith='Question')

    from django.db.models import Q

    Q(title__icontains='1')

    default_q = Q(title__icontains='1')

    second_q = Q(text__icontains='1')

    default_q | second_q

    Document.objects.filter(default_q | second_q)
Share