
* 겪고 있는 문제 상황을 최대한 자세하게 작성해주세요.
* 문제 해결을 위해 어떤 시도를 해보았는지 구체적으로 함께 알려주세요.
강의를 듣고 프로젝트로 게시판에 검색기능을 부여하는 작업을 하고 있습니다.
검색어를 입력하면 몽고 DB에 저장된 데이터를 불러오는 간단한 작업인데요 (아닐 수도 있겠지만..)
데이터 구조도 이상이 없어보이는데 작동이 되지 않아 질문드립니다..
챗GPT도 활용하고 여러 블로그글을 읽어봤는데도 모르겠네요 ㅜㅠ
db에 저장된 nickname, title, content에 검색어가 포함이 되면 search_list를 불러오는 기능입니다!
도와주세요 ~!!
작성한 코드 및 에러 메세지
오류 발생 시, 작성한 코드 전체와 에러 메시지를 첨부해 주세요.
//flask 코드 입니다
from flask import Flask, render_template, request, jsonify
import pd
app = Flask(__name__)
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://charles:1111@cluster0.szvramp.mongodb.net/Cluster0?retryWrites=true&w=majority',
tlsCAFile=ca)
db = client.dbddymap
@app.route('/')
def home():
return render_template('index.html')
@app.route('/board')
def board():
count = db.board.count_documents({})
return render_template('board.html', count=count)
@app.route('/board/regist', methods=["POST"])
def board_post():
nickname_receive = request.form['nickname_give']
password_receive = request.form['password_give']
title_receive = request.form['title_give']
content_receive = request.form['content_give']
url_receive = request.form['url_give']
radio_receive = request.form['radio_give']
cards_list = list(db.board.find({}, {'_id': False}))
count = len(cards_list) + 1
doc = {
'num': count,
'nickname': nickname_receive,
'password': password_receive,
'title': title_receive,
'content': content_receive,
'url': url_receive,
'radio': radio_receive
}
db.board.insert_one(doc)
return jsonify({'msg': '게시물 등록 완료!'})
@app.route('/board/regist', methods=["GET"])
def board_get():
cards_list = list(db.board.find({}, {'_id': False}))
return jsonify({'cards': cards_list})
@app.route('/board/regist', methods=["GET"])
def search_get():
search_receive = request.args.get('search')
search_list = list(db.board.find({'$or': [{'title': {'$regex': search_receive}},
{'content': {'$regex': search_receive}},
{'nickname': {'$regex': search_receive}}]},
{'_id': False}))
return jsonify({'searches': search_list})
@app.route('/board/regist/delete', methods=["POST"])
def card_delete():
num_receive = request.form['num_give']
db.board.delete_one({'num': int(num_receive)})
return jsonify({'msg': "삭제 완료!"})
@app.route('/about')
def about():
return render_template('about.html')
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
// html 코드입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
crossorigin="anonymous"></script>
<title>대동0ㅕ지도</title>
<style>
@font-face {
font-family: 'Pretendard-Regular';
src: url('https://cdn.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff');
font-weight: 400;
font-style: normal;
}
* {
font-family: 'Pretendard-Regular';
}
.nav-link {
font-weight: bold;
}
.mypage {
text-decoration: underline;
text-decoration-thickness: 3px;
text-underline-offset: 20px;
margin-bottom: 0;
}
.mytitle {
width: 100%;
height: 150px;
color: black;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.mymessage {
background-image: url("https://ifh.cc/g/r6xKPX.png");
background-position: center center;
background-size: 1000px auto;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin-bottom: 30px;
min-height: 300px;
}
.mymessage > button {
width: 100px;
height: 50px;
background-color: white;
color: black;
border-radius: 50px;
border: 1px solid black;
margin-top: 30px;
}
.mytitle > button:hover {
border: 2px solid white;
}
.mypost {
margin: auto;
width: 700px;
padding: 50px;
box-shadow: 0px 0px 3px 0px gray;
margin-bottom: 80px;
display: none;
}
.mybtns {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
margin-top: 20px;
}
.mybtns > button {
margin-right: 10px;
}
.allpost {
margin: auto;
width: 95%;
max-width: 950px;
padding: 20px;
}
hr {
width: 100%;
}
.mycard {
margin: auto;
width: 95%;
max-width: 950px;
padding: 20px;
}
.mysearch {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
}
</style>
<script>
$(document).ready(function () {
show_card();
search_card();
});
function show_card() {
$('#card-box').empty()
$.ajax({
type: 'GET',
url: '/board/regist',
data: {},
success: function (response) {
let rows = response['cards']
for (let i = 0; i < rows.length; i++) {
let nickname = rows[i]['nickname']
let title = rows[i]['title']
let content = rows[i]['content']
let num = rows[i]['num']
let url = rows[i]['url']
let radio = rows[i]['radio']
let temp_html = `<div class="card mb-3" style="width: 100%;">
<div class="row g-1">
<img style="object-fit: cover; width: 35%" src="${url}" onerror= "this.onerror=null; this.src='https://i.pinimg.com/564x/df/9c/f6/df9cf66c6ecc4574a166496ea11a5352.jpg';">
<div style="margin-left: 10px; width: 60%; margin-top: 5%; " class="card-body">
<p>${radio}</p>
<h5 class="card-title">${title}</h5>
<p class="card-text">${content}</p>
<p class="card-text"><small class="text-muted">${nickname}</small></p>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button onclick="delete_card(${num})" class="btn btn-secondary btn-sm" type="button">삭제</button>
</div>
</div>
</div>
</div>`
$('#card-box').append(temp_html)
}
}
});
}
function search_card() {
$('#card-box').empty()
let search = $('#search').val();
$.ajax({
type: 'GET',
url: '/board/regist',
data: {'searches': search},
success: function (response) {
let rows = response['searches']
for (let i = 0; i < rows.length; i++) {
let nickname = rows[i]['nickname']
let title = rows[i]['title']
let content = rows[i]['content']
let num = rows[i]['num']
let url = rows[i]['url']
let radio = rows[i]['radio']
let temp_html = `<div class="card mb-3" style="width: 100%;">
<div class="row g-1">
<img style="object-fit: cover; width: 35%" src="${url}" onerror= "this.onerror=null; this.src='https://i.pinimg.com/564x/df/9c/f6/df9cf66c6ecc4574a166496ea11a5352.jpg';">
<div style="margin-left: 10px; width: 60%; margin-top: 5%; " class="card-body">
<p>${radio}</p>
<h5 class="card-title">${title}</h5>
<p class="card-text">${content}</p>
<p class="card-text"><small class="text-muted">${nickname}</small></p>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button onclick="delete_card(${num})" class="btn btn-secondary btn-sm" type="button">삭제</button>
</div>
</div>
</div>
</div>`
$('#card-box').append(temp_html)
}
}
});
}
function save_post() {
let nickname = $('#nickname').val()
let password = $('#password').val()
let title = $('#title').val()
let content = $('#content').val()
let url = $('#url').val()
let radio = $('input[name=radio]:checked').val()
$.ajax({
type: 'POST',
url: '/board/regist',
data: {
'nickname_give': nickname,
'password_give': password,
'title_give': title,
'content_give': content,
'url_give': url,
'radio_give': radio
},
success: function (response) {
alert(response['msg'])
window.location.reload()
}
});
}
function delete_card(num) {
$.ajax({
type: 'POST',
url: '/board/regist/delete',
data: {'num_give': num},
success: function (response) {
alert(response["msg"])
window.location.reload()
}
});
}
function open_box() {
$('#post-box').show()
}
function close_box() {
$('#post-box').hide()
}
function fill_post() {
let newNickname = $('#nickname').val()
let newPasssword = $('#password').val()
let newTitle = $('#title').val()
let newContent = $('#content').val()
if (newNickname == '') {
alert('닉네임을 입력하세요.');
return;
} else if (newTitle == '') {
alert('제목을 입력하세요.');
return;
} else if (newContent == '') {
alert('내용을 입력하세요.');
return;
} else if (newPasssword == '') {
alert('비밀번호를 입력하세요.');
return;
} else if ((newPasssword.length !== 4)) {
alert('비밀번호는 4자리로 입력해주세요.');
$('#password').val('');
return false;
} else if (!/^\d+$/.test(newPasssword)) {
alert("비밀번호는 숫자로만 입력해주세요.");
$('#password').val('');
return false;
} else {
save_post();
}
}
</script>
</head>
<body>
<!-- HTML for Horizontal Menu -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a href="/">
<img src={{ url_for('static', filename='images/logo.png') }} alt="logo">
</a>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="/board">게시판</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/about">About Us</a>
</li>
</ul>
</div>
</nav>
<div class="mytitle">
<h1 class="mypage">게시판</h1>
</div>
<div class="mymessage">
<h3>제로 웨이스트를 실천하는 나만의 방법을 알려주세요!</h3>
<p></p>
<h5>🔊 이제는 일상이 된 나만의 팁을 공유해주세요</h5>
<button onclick="open_box()">글쓰기</button>
</div>
<div class="mypost" id="post-box">
<div class="row g-3">
<div style="display: flex; flex-direction: row; margin-bottom: 10px">
<div style="margin-right: 15px" class="form-check">
<input value="상점 후기" class="form-check-input" type="radio" name="radio" id="radioButton1" checked>
<label class="form-check-label" for="radioButton1">
상점 후기
</label>
</div>
<div class="form-check">
<input value="꿀팁 공유" class="form-check-input" type="radio" name="radio" id="radioButton2">
<label class="form-check-label" for="radioButton22">
꿀팁 공유
</label>
</div>
</div>
<div class="col">
<input id="nickname" type="text" class="form-control" placeholder="닉네임" aria-label="First name">
</div>
<div class="col">
<input id="password" type="text" class="form-control" placeholder="비밀번호" aria-label="Last name"
style="width: 70%">
</div>
<p></p>
</div>
<div class="form-floating mb-3">
<input type="url" class="form-control" id="url" placeholder="URL">
<label for="floatingInput">이미지 URL</label>
</div>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">제목</label>
<textarea class="form-control" id="title" rows="3" style="height: 10px"></textarea>
</div>
<div class="mb-3">
<label for="exampleFormControlTextarea1" class="form-label">내용</label>
<textarea class="form-control" id="content" rows="3"></textarea>
</div>
<div class="mybtns">
<button type="button" class="btn btn-dark" onclick="fill_post(); _box()">기록하기</button>
<button type="button" class="btn btn-outline-dark" onclick="close_box();_box()">닫기</button>
</div>
</div>
<div class="allpost">
<div class="mysearch">
<p style="min-width: 150px; max-height: 10px; margin-left: 10px">전체 게시글 ({{ count }})</p>
<div class="container-fluid">
<form class="d-flex" role="search" style="width: 40%">
<input id="search" class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button onclick="search_card()" id="btnsearch" class="btn btn-outline-success">Search</button>
</form>
</div>
</div>
<hr align="left" style="border: 1.5px;">
</div>
<div class="mycard">
<div id="card-box" class="row row-cols-1 row-cols-md-3 g-4">
<div class="card mb-3" style="width: 100%;">
<div class="row g-1">
<img style="object-fit: cover; width: 35%" src="https://ifh.cc/g/YcZCyy.jpg" alt="...">
<div style="width: 65%; margin-top: 20px" class="card-body">
<p># 후기/꿀팁</p>
<h5 class="card-title">제목</h5>
<p class="card-text">내용</p>
<p class="card-text"><small class="text-muted">닉네임</small></p>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button onclick="delete_card(${num})" class="btn btn-secondary btn-sm" type="button">삭제</button>
</div>
</div>
</div>
</div>
<div class="card mb-3" style="width: 100%;">
<div class="row g-1">
<img style="object-fit: cover; width: 35%" src="https://ifh.cc/g/YcZCyy.jpg" alt="...">
<div style="width: 65%; margin-top: 20px" class="card-body">
<p># 후기/꿀팁</p>
<h5 class="card-title">제목</h5>
<p class="card-text">내용</p>
<p class="card-text"><small class="text-muted">닉네임</small></p>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button onclick="delete_card(${num})" class="btn btn-secondary btn-sm" type="button">삭제</button>
</div>
</div>
</div>
</div>
<div class="card mb-3" style="width: 100%;">
<div class="row g-1">
<img style="object-fit: cover; width: 35%" src="https://ifh.cc/g/YcZCyy.jpg" alt="...">
<div style="width: 65%; margin-top: 20px" class="card-body">
<p># 후기/꿀팁</p>
<h5 class="card-title">제목</h5>
<p class="card-text">내용</p>
<p class="card-text"><small class="text-muted">닉네임</small></p>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button onclick="delete_card(${num})" class="btn btn-secondary btn-sm" type="button">삭제</button>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
