- 게시판의 게시글 목록에서 검색하여 원하는 게시물을 찾을 수 있도록 하자.
- 화면은 그대로, 이벤트 발생시에도 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가 문자열로 묶여있었다.
- 눈을 크게 뜨고 찾고, 수정 해주자