본문 바로가기

카테고리 없음

django 기초 - bootstrap을 이용한 사이트 만들기 : 9. 검색 기능(ajax)

 - 게시판의 게시글 목록에서 검색하여 원하는 게시물을 찾을 수 있도록 하자.

 - 화면은 그대로, 이벤트 발생시에도 reloading 없이 특정 영역(게시판 글 목록)의 데이터를 변경하는 Ajax 통신방식을 사용한다. 이때, <form>과 <a>태그가 아닌 script로 서버와 통신을 해야한다.

1. 버튼 만들기

<div class='box-body'>
	<button id='newBtn'>New Board</button>
	<select id='search_type'>
		<option value="title">제목</option>
		<option value="content">내용</option>
	</select>
	<input type="text" id="searchKeyword">
	<button id="search_btn">검색</button>
</div>

  - <select> 태그를 사용하여 원하는 카테고리를 선택 가능

 - <input>으로 검색 내용을 입력 받고, 버튼을 누르면 서버에 전송

2. Script - Ajax 비동기 통신

$(document).ready(function(){
	$('#search_btn').click(function(){
		$.ajax({
			url : "../search_form/",
			type : 'post' ,
			data : {    'csrfmiddlewaretoken' : '{{csrf_token}}',
            			type : $('#search_type').val(),
                   		keyword : $('#search_keyword').val()
						},
			dataType : 'json' ,
			success  : function(list) {
				var txt = '';
				$.each(list, function(idx, obj) {
					txt += '<tr>'
					txt += '<td>'+obj.id+'</td>'
					txt += "<td><a href='../bbs_get_content/?id=obj.id'>"+obj.title+"</a></td>"
					txt += '<td>'+obj.writer+'</td>'
					txt += '<td>'+obj.regdate+'</td>'
					txt += "<td><span class='badge bg-red'>"+obj.viewcnt+"</span></td>"
					txt += '</tr>'
				})
				$('#tbody').empty().append(txt)
			}
		})
	})
})

 - search_btn을 클릭하면 ajax 통신 함수가 작동한다

 - url 과 post 타입, data를 주고받는 과정은 비슷하다. 여기서 data는 render에서 context와 유사하게 이해했다.

 - datatype 은 json 형태의 데이터를 의미한다. Ajax의 j가 json방식을 의미한다. x는 xml방식인데, xml방식은 parsing이 어려워 최근에는 거의 모두 json 형식의 데이터를 주고받는다.

 - sucess 값은 통신이 성공했을 때, 수행할 부분이다. list는 서버로 부터 받아오는 데이터이다. json형식의 데이터는 [ { key : value } ] 형태로 딕셔너리를 리스트가 감싸고 있는 형태이다.

 - 서버로부터 전송받은 데이터를 .each 문에서 순차적으로 function을 수행한다. 즉, each문은 for loop와 같다.

 - list는 json의 dictionary를 감싸고있는 list를, obj는 list 안의 dictionary를 의미한다.

3. Back

# urls.py
    path('search_form/', views.search_form, name='search_form'),

# views.py
def search_form(request):
    if request.method=='POST':
        print('---- search_form request ----')
        search_type = request.POST['type']
        search_keyword = request.POST['keyword']

        if search_type == 'title':
            find_forms = Bbs.objects.filter(title__icontains=search_keyword)
        elif search_type == 'content':
            find_forms = Bbs.objects.filter(content__icontains=search_keyword)
        elif search_type == 'writer':
            find_forms = Bbs.objects.filter(writer__startswith=search_keyword)

        form_list = []
        for form in find_forms:
            form_list.append({
                'id' : form.id ,    'title' : form.title ,
                'content' : form.content ,  'regdate': form.regdate,
                'viewcnt' : form.viewcnt,   'writer' : form.writer
            })

        return JsonResponse(form_list, safe=False)

 - <select> 태그에서 선택하여 입력된 (제목 | 작성자 | 내용 )이 search_type 으로 입력된다.

 - <input> 태그로 입력받은 검색내용이 search_keyword로 입력된다.

 - 따라서 데이터베이스에서 <select> 항목에 따라 데이터를 필터링해서 가져올 것이다. 즉, select 항목은 SQL 문의 where 조건을 어떤걸로 선택할지에 대한 입력이다.

 - ormClass.objects.filter(condition)은 조건에 맞는 데이터들을 가져온다. get()은 하나의 데이터만을 가져올 수 있다.

 - filter의 조건은 와일드카드를 사용했다. SQL의 Like 와 같다. (  __ 두개! )

 * title__icontaions == title like '%search_keyword%' : search_keyword를 포함하는 모든 제목

 * content__icontaions == content like '%search_keyword%' : search_keyword를 포함하는 모든 내용

 * writer__startswith == writer like 'search_keyword%' : search_keyword로 시작하는 모든 글쓴이 이름

 - 필터링된 데이터를 json 형식으로 만들기 위해 딕셔너리와 그를 감싸는 리스트로 데이터를 구성한다.

 - 필터링해서 가져온 데이터 객체 묶음을 JsonResponse로 넘겨주면 오류가 난다.

 ( TypeError: Object of type QuerySet is not JSON serializable )


 - 검색된 게시글의 제목을 눌렀는데 다음과 같은 오류가 났다. 괜히 눌러봤다.

 - 제목을 누르면 bbs_get_content가 호출되고 게시물 상세 페이지로 넘어가는데, id값이 넘어오지 않았다고 한다.

$.each(list, function(idx, obj) {
  txt += '<tr>'
  txt += '<td>'+obj.id+'</td>'
  // txt += "<td><a href='../bbs_get_content/?id=obj.id'>"+obj.title+"</a></td>"
  txt += "<td><a href='../bbs_get_content/?id=" + obj.id + "'>" + obj.title + "</a></td>"
  txt += '<td>'+obj.writer+'</td>'
  txt += '<td>'+obj.regdate+'</td>'
  txt += "<td><span class='badge bg-red'>"+obj.viewcnt+"</span></td>"
  txt += '</tr>'
})

 - get 방식으로 url 주는 부분에 obj.id가 문자열로 묶여있었다.

 - 눈을 크게 뜨고 찾고, 수정 해주자