인프런 커뮤니티 질문&답변

Ts K님의 프로필 이미지
Ts K

작성한 질문수

남박사의 파이썬으로 실전 웹사이트 만들기

게시판 검색기능 구현 후 데이터를 검색하여도 데이터 없음으로 나옵니다.

작성

·

591

1

안녕하세요 강의를 보며 게시판 검색기능을 구현중인데요, 어떤 부분이 잘못되었는지 게시판 검색을 하여도 데이터 없음으로 나옵니다. 혹시 첨부한 코드에서 무엇이 잘못되었는지 봐주실 수 있을까요?

<추가> 정정하면 기존 코드로는 제대로 검색이 이루어지지 않으며 아래와 같이 {}를 query로 바꾸면 아예 데이터 없음으로 나옵니다

  datas =board.find(query).skip((page - 1) * limit).limit(limit)

    #게시물의 총 갯수
   tot_count = board.find(query).count()

from flask import Flask
from flask import request
from flask import render_template
from flask_pymongo import PyMongo
from datetime import datetime
from bson.objectid import ObjectId
from flask import abort
from flask import redirect
from flask import url_for
import time
import math

app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb"
mongo = PyMongo(app)

@app.template_filter("formatdatetime")
def format_datetime(value):
    if value is None:
        return ""

    now_timestamp = time.time()
    offset = datetime.fromtimestamp(now_timestamp)-datetime.utcfromtimestamp(now_timestamp)
    value = datetime.fromtimestamp((int(value)/1000)) + offset
    return value.strftime('%Y-%m-%d %H:%M:%S')


@app.route("/list")
def lists():
    #페이지값(값이 없는 경우 기본값은 1)
    page = request.args.get("page"1type=int)
    #한페이지당 몇개의 게시물을 출력할지
    limit = request.args.get("limit"5type=int)

    search = request.args.get("search", -1type=int)
    keyword = request.args.get("keyword"type=str)

    #최종적으로 완성된 쿼리를 만들 변수
    query = {}
    #검색어 상태를 추가할 리스트변수
    search_list = []

    if search == 0:
        search_list.append({"title": {"&regex": keyword}})
    elif search == 1:
        search_list.append({"contents": {"&regex": keyword}})
    elif search == 2:
        search_list.append({"title": {"&regex": keyword}})
        search_list.append({"contents": {"&regex": keyword}})
    elif search == 3:
        search_list.append({"name": {"&regex": keyword}})

    if len(search_list) > 0:
        query = {"$or": search_list}
   
    print(query)

    
    board = mongo.db.board
    #skip (2번쩨 페이지-1)*10 -> 앞페이지 10개 skip, 이후부터 10개까지 출력
    datas =board.find({}).skip((page - 1) * limit).limit(limit)

    #게시물의 총 갯수
    tot_count = board.find({}).count()
    # 마지막 페이지의 수
    last_page_num = math.ceil(tot_count/limit)
    #페이지 블록 5개씩 표기
    block_size = 5
    #현재 블록 위치
    block_num = int((page - 1)/ block_size)
    #블럭의 시작 위치
    block_start = int((block_size * block_num) +1)
    #블럭의 끝 위치
    block_last = math.ceil(block_start + (block_size - 1))

    return render_template(
        "list.html",
        datas=datas,
        limit=limit,
        page=page,
        block_start=block_start,
        block_last=block_last,
        last_page_num=last_page_num)

@app.route("/view/<idx>")
def board_view(idx):
    #idx = request.args.get("idx")
    if idx is not None:
        board = mongo.db.board
        data = board.find_one({"_id": ObjectId(idx)})

        if data is not None:
            result = {
                "id" : data.get("_id"),
                "name" : data.get("name"),
                "title": data.get("title"),
                "contents":data.get("contents"),
                "pubdate":data.get("pubdate"),
                "view":data.get("view")

            }

            return render_template("view.html"result=result)
    return abort(404)


@app.route("/write"methods=["GET""POST"])
def board_write():
    if request.method == "POST":
        name = request.form.get("name")
        title = request.form.get("title")
        contents = request.form.get("contents")
        print(name, title, contents)

        current_utc_time = round(datetime.utcnow().timestamp()*1000)
        board = mongo.db.board #있으면 리턴 없으면 board 생성

        post = {
            "name" : name,
            "title": title,
            "contents": contents,
            "pubdate":current_utc_time,
            "view":0
        }

        x = board.insert_one(post)
        print(x.inserted_id)

        return redirect(url_for("board_view"idx=x.inserted_id))
    else:
        return render_template("write.html")

if __name__ == "__main__":
    app.run(debug=Truehost="0.0.0.0"port=9000)
<script>
    function search(){
        var v_search = document.getElementById("search").value;
        var v_keyword = document.getElementById("keyword").value;

        if(v_search=="" | v_keyword==""){
            return false;
        } else {
            self.location.href = "{{url_for('lists')}}?search=" + v_search +"&keyword="+v_keyword;   
        }
    }

</script>

{%if datas.count() >0 %}
<table>
    <thead>
        <tr>
            <td>번호</td>
            <td>제목</td>
            <td>이름</td>
            <td>날짜</td>
            <td>조회수</td>
        </tr>
    </thead>
    <tbody>
        <!--반복구간 시작-->
        {% for data in datas %}
        <tr>
         <td>{{loop.index + ((page -1) * limit)}}</td>
         <td><a href="{{url_for('board_view', idx=data._id)}}">{{data.title}}</a></td>
         <td>{{data.name}}</td>
         <td>{{data.pubdate | formatdatetime}}</td>
         <td>{{data.view}}</td>
        </tr>
        {% endfor %}
        <!--반복구간 끝-->
    </tbody>
</table>
{%if block_start - 1 > 0%}
    <a href="{{url_for('lists', page= block_start - 1)}}">[이전]</a>
{%endif%}

{% for i in range(block_start , block_last + 1)%}
    {%if i > last_page_num %}
        {{ i }}
    {%else%}
        {% if i == page %}
            <b>{{ i }}</b>
        {%else%}
            <a href="{{url_for('lists', page=i)}}">{{i}}</a>
        {%endif%}
    {%endif%}
{% endfor%}

{%if block_last < last_page_num%}
    <a href="{{url_for('lists', page= block_last+1)}}">[다음]</a>
{%endif%}

<select name="search" id="search">
    <option value="">검색대상</option>
    <option value="0">제목</option>
    <option value="1">내용</option>
    <option value="2">제목+내용</option>
    <option value="3">작성자</option>
</select>
<input type="text" name="keyword" id="keyword">
<input type="button" value="검색" onclick="search()">

{% else %}
<h3>데이터 없음</h3>

{% endif %}

강의와 관련있는 질문을 남겨주세요.
• 강의와 관련이 없는 질문은 지식공유자가 답변하지 않을 수 있습니다. (사적 상담, 컨설팅, 과제 풀이 등)
• 질문을 남기기 전, 비슷한 내용을 질문한 수강생이 있는지 먼저 검색을 해주세요. (중복 질문을 자제해주세요.)
서비스 운영 관련 질문은 인프런 우측 하단 ‘문의하기’를 이용해주세요. (영상 재생 문제, 사이트 버그, 강의 환불 등)

질문 전달에도 요령이 필요합니다.
• 지식공유자가 질문을 좀 더 쉽게 확인할 수 있게 도와주세요.
• 강의실 페이지(/lecture) 에서 '질문하기'를 이용해주시면 질문과 연관된 수업 영상 제목이 함께 등록됩니다.
• 강의 대시보드에서 질문을 남길 경우, 관련 섹션 및 수업 제목을 기재해주세요. 
• 수업 특정 구간에 대한 질문은 꼭 영상 타임코드를 남겨주세요!

구체적인 질문일수록 명확한 답을 받을 수 있어요.
• 질문 제목은 핵심 키워드를 포함해 간결하게 적어주세요.
• 질문 내용은 자세하게 적어주시되, 지식공유자가 답변할 수 있도록 구체적으로 남겨주세요.
• 정확한 질문 내용과 함께 코드를 적어주시거나, 캡쳐 이미지를 첨부하면 더욱 좋습니다.

기본적인 예의를 지켜주세요.
• 정중한 의견 및 문의 제시, 감사 인사 등의 커뮤니케이션은 더 나은 강의를 위한 기틀이 됩니다. 
• 질문이 있을 때에는 강의를 만든 지식공유자에 대한 기본적인 예의를 꼭 지켜주세요. 
반말, 욕설, 과격한 표현 등 지식공유자를 불쾌하게 할 수 있는 내용은 스팸 처리 등 제재를 가할 수 있습니다. 

답변 1

0

남박사님의 프로필 이미지
남박사
지식공유자

print(query)

datas =board.find(query).skip((page - 1) * limit).limit(limit)

일단 위처럼 find 함수 호출전 query 에 어떤 내용이 들어가있는지부터 확인해봐야 할 듯 합니다.

Ts K님의 프로필 이미지
Ts K
질문자

 print({})
    board = mongo.db.board
    #skip (2번쩨 페이지-1)*10 -> 앞페이지 10개 skip, 이후부터 10개까지 출력
    datas =board.find({}).skip((page - 1) * limit).limit(limit)

    #게시물의 총 갯수

   tot_count = board.find({}).count()

해당 코드에서  빨간 색으로 표시된 부분을 {}로 하여 query를 {}로 하여 제목 welcome을 검색하면 xxx.xxx.xxx.xxx - - [13/Apr/2021 09:59:32] "?[37mGET /list?search=0&keyword=python HTTP/1.1?[0m" 200 -

{}

이런 응답이 오며,  기본 리스트 화면이 나옵니다.( welcome으로 필터링 안됨)

query로 변경한 후 조회를 하면 동일한 xxx.xxx.xxx. - - [13/Apr/2021 10:06:42] "?[37mGET /list?search=0&keyword=welcome HTTP/1.1?[0m" 200 -

이라는 값이 나오며 "데이터 없음"이라는 화면이 나옵니다.

몇차례 강의를 돌려보고 있는데 어느 코드에서 잘못되었는지 모르겠네요.. 도움 부탁드립니다.

남박사님의 프로필 이미지
남박사
지식공유자

board.find({}) 에서 {} 의 의미는 게시물 전체를 가져오는 내용입니다. 그렇기 때문에 당연히 검색 기능은 전혀 동작하지 않는게 정상입니다.

검색 기능은 find() 함수를 호출할때 어떤 조건을 주어 해당 조건에 맞는 데이터만 find() 할 수 있게 하는 기능입니다. 그렇기 때문에 다시 말씀드리지만..

board.find(query) 를 했을때 query 안에 어떤 내용이 있는지를 확인해야만 왜 검색이 안되는지 어떤 문제가 있는지 유추할 수 있습니다. board.find(query) 하기 전에 print(query) 명령을 실행해서 query 변수 안에 어떤 내용이 있는지부터 확인해보셔야 합니다. 

Ts K님의 프로필 이미지
Ts K
질문자

혹시 말씀하시는 값이 이 값일까요? {'$or': [{'title': {'&regex': 'wiki'}}]}

제목에 wiki를 넣었을때 쿼리안에 이러한 값이 들어가며 결과는 데이터 없음으로 나오고 있습니다.

남박사님의 프로필 이미지
남박사
지식공유자

query 내용을 보니 위에 최초 코드에 문제가 있는걸 확인할 수 있습니다. &regex 가 아니라 $regex 입니다. 해당 코드를 수정해보시면 될듯 합니다.

Ts K님의 프로필 이미지
Ts K
질문자

말씀해주신대로 고쳤더니 해결되었습니다! 몇번을 보면서 & 표시가 잘못된 걸 몰랐네요ㅠ 다행이도 실습을 진행할 수 있게 되었습니다, 감사합니다.

남박사님의 프로필 이미지
남박사
지식공유자

사실 그런 실수가 정말 시간을 많이 소비하는 실수중 하나입니다. 저도 위의 코드를 몇번이고 확인했음에도 제 눈에도 안보였었습니다. ㅎㅎㅎ

Ts K님의 프로필 이미지
Ts K

작성한 질문수

질문하기