55,000원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 해결됨남박사의 파이썬으로 실전 웹사이트 만들기
웹사이트 회원가입후 게시판으로 넘어가는 부분 질문 (join 부분)
안녕하세요 남박사님 도움을 많이 주셔서 강좌 잘 진행하고 있습니다! 몇일동안 헤매던것을 해결되서 정말 좋습니다! 궁금한 사항이 있어서 질문 올립니다. join창에서 회원가입을 하면 몽고db에 데이터가 정상적으로 넣어지는걸 확인할수있고 리스트란에서 게시물 작성 및 삭제등이 원활하게 이루어 지고 있습니다. 궁금한부분은 회원가입후 리스트나 로그인창으로 안넘어 가는거 같아서 질문을 올립니다! 회원로그인창으로 링크주소를 바꾸면 오류가 나는거 같더라구요.. 어떻게 해야할지 몰라서 질문 다시 올립니다! -회원가입- -회원 가입후- - 로그인 - -게시판 목록- -게시글 자성란- -게시글 작성후 - -회원가입 데이터- - run.py - from flask import Flask from flask import request from flask import render_template from flask_pymongo import PyMongo from bson.objectid import ObjectId from flask import abort from flask import redirect from flask import url_for from flask import flash from flask import session from functools import wraps import math import time from datetime import datetime, timedelta app = Flask(__name__) app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb" app.config["SECRET_KEY"] = "abcd" app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=30) mongo = PyMongo(app) def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if session.get("id") is None or session.get("id") == "": return redirect(url_for("member_login", next_url=request.url)) return f(*args, **kwargs) return decorated_function @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", 1, type=int) # 한페이지당 몇개의 게시물을 출력할지 limit = request.args.get("limit", 5, type=int) search = request.args.get("search", -1, type=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}}) # 검색 대상이 한개라도 존재할 경우 query 변수에 $or 리스트를 쿼리 합니다. if len(search_list) > 0: query = {"$or": search_list} print(query) board = mongo.db.board datas = board.find({}).skip( (page - 1) * limit).limit(limit).sort("pubdate", -1) # 게시물의 총 갯수 tot_count = board.count_documents({}) # 마지막 페이지의 수를 구한다. 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=list(datas), limit=limit, page=page, block_start=block_start, block_last=block_last, last_page_num=last_page_num, search=search, keyword=keyword) @ app.route("/view/<idx>") @login_required def board_view(idx): # idx = request.args.get("idx") if idx is not None: page = request.args.get("page") search = request.args.get("search") keyword = request.args.get("keyword") board = mongo.db.board # data = board.find_one({"_id": ObjectId(idx)}) data = board.find_one_and_update({"_id": ObjectId(idx)}, { "$inc": {"view": 1}}, return_document=True) 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"), "writer_id": data.get("writer_id", "") } return render_template("view.html", result=result, page=page, search=search, keyword=keyword) return abort(404) @ app.route("/write", methods=["GET", "POST"]) def board_write(): if session.get("id") is None: return redirect(url_for("member_login")) 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 post = { "name": name, "title": title, "contents": contents, "pubdate": current_utc_time, "writer_id": session.get("id"), "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") @app.route("/join", methods=["GET", "POST"]) def member_join(): if request.method == "POST": name = request.form.get("name", type=str) email = request.form.get("email", type=str) pass1 = request.form.get("pass", type=str) pass2 = request.form.get("pass2", type=str) if name == "" or email == "" or pass1 == "" or pass2 == "": flash("입력되지 않은 값이 있습니다.") return render_template("join.html") if pass1 != pass2: flash("비밀번호가 일치하지 않습니다.") return render_template("join.html") members = mongo.db.members cnt = members.count_documents({"email": email}) if cnt > 0: flash("중복된 이메일 주소입니다.") return render_template("join.html") current_utc_time = round(datetime.utcnow().timestamp() * 1000) post = { "name": name, "email": email, "pass": pass1, "joindate": current_utc_time, "logintime": "", "logincount": 0, } members.insert_one(post) return "" else: return render_template("join.html") @app.route("/login", methods=["GET", "POST"]) def member_login(): if request.method == "POST": email = request.form.get("email") password = request.form.get("pass") next_url = request.form.get("next_url") members = mongo.db.members data = members.find_one({"email": email}) if data is None: flash("회원 정보가 없습니다.") return redirect(url_for("member_login")) else: if data.get("pass") == password: session["email"] = email session["name"] = data.get("name") session["id"] = str(data.get("_id")) session.permanent = True if next_url is not None: return redirect(next_url) else: return redirect(url_for("lists")) return redirect(url_for("lists")) else: flash("비밀번호가 일치하지 않습니다.") return redirect(url_for("member_login")) return "" else: next_url = request.args.get("next_url", type=str) if next_url is not None: return render_template("login.html", next_url=next_url) else: return render_template("login.html") @app.route("/edit/<idx>", methods=["GET", "POST"]) def board_edit(idx): if request.method == "GET": board = mongo.db.board data = board.find_one({"_id": ObjectId(idx)}) if data in None: flash("해당 게시물이 존재하지 않습니다.") return redirect(url_for("lists")) else: if session.get("id") == data.get("writer_id"): return render_template("edit.html", data=data) else: flash("글 수정 권한이 없습니다.") return redirect(url_for("lists")) else: title = request.form.get("title") contains = request.form.get("contents") board = mongo.db.board data = board.find_one({"_id": ObjectId(idx)}) if session.get("id") == data.get("writer_id"): board.update_one({"_id": ObjectId(idx)}, { "$set": { "title": title, "contents": contains, } }) flash("수정 되었습니다.") return redirect(url_for("board_view", idx=idx)) else: flash("글 수정 권한이 없습니다.") return redirect(url_for("lists")) @app.route("/delete/<idx>") def board_delete(idx): board = mongo.db.board data = board.find_one({"_id": ObjectId(idx)}) if data.get("writer_id") == session.get("id"): board.delete_one({"_id": ObjectId(idx)}) flash("삭제 되었습니다.") else: flash("삭제 권한이 없습니다.") return redirect(url_for("lists")) if __name__ == "__main__": app.run(host="0.0.0.0", debug=True, port=9000) --------------------------------------------------------------------------------- -join- {% with messages = get_flashed_messages() %} {% if messages %} <script> alert("{{messages[-1]}}"); </script> {% endif %} {% endwith %} <table> <form name="form" action="/join" method="POST"> <thead> <caption> 회원가입 </caption> </thead> <tbody> <tr> <td>이름</td> <td><input type="text" name="name" /></td> </tr> <tr> <td>이메일</td> <td><input type="text" name="email" /></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" name="pass" /></td> </tr> <tr> <td>비밀번호 확인</td> <td><input type="password" name="pass2" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="가입하기" /></td> </tr> </tbody> </form> </table> --------------------------------------------------------------------------------------- -login- {% with messages = get_flashed_messages() %} {% if messages %} <script> alert("{{messages[-1]}}"); </script> {% endif %} {% endwith %} <table> <form name="form" action="/login" method="POST"> {% if next_url %} <input type="hidden" name="next_url" value="{{next_url}}" /> {% endif %} <thead> <caption> 회원 로그인 </caption> </thead> <tbody> <tr> <td>이메일</td> <td><input type="text" name="email" /></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" name="pass" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="로그인" /></td> </tr> </tbody> </form> </table> ------------------------------------------------------------------------------------ -list- {% with messages = get_flashed_messages() %} {% if messages %} <script> alert('{{messages[-1]}}'); </script> {% endif %} {% endwith %} <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|length > 0 %} <table> <thead> <tr> <td>번호</td> <td>제목</td> <td>이름</td> <td>날짜</td> <td>조회수</td> </tr> </thead> <tbody> <!--반복되는 구간--> <tr> {% for data in datas %} <td>{{loop.index + ((page - 1) * limit)}}</td> <td> <a href="{{url_for('board_view', idx=data._id, page=page, search=search, keyword=keyword)}}">{{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, search=search, keyword=keyword)}}">[이전]</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, search=search, keyword=keyword)}}">{{ i }}</a> {% endif %} {% endif %} {% endfor %} {% if block_last < last_page_num %} <a href="{{url_for('lists', page=block_last + 1, search=search, keyword=keyword)}}">[다음]</a> {% endif %} <select name="search" id="search"> <option value="" {% if search=='' or search==-1 %} selected {% endif %}>검색대상</option> <option value="0" {% if search==0 %} selected {% endif %}>제목</option> <option value="1" {% if search==1 %} selected {% endif %}>내용</option> <option value="2" {% if search==2 %} selected {% endif %}>제목+내용</option> <option value="3" {% if search==3 %} selected {% endif %}>작성자</option> </select> <input type="text" name="keyword" id="keyword" {% if keyword !="" %} value="{{keyword}}" {% endif %} /> <input type="button" value="검색" onclick="search()" /> {% else %} <h3>데이터가 없습니다.</h3> {% endif %} <a href="{{url_for('board_write')}}">글작성</a> ---------------------------------------------------------------------------------------- -view- <html> {% with messages = get_flashed_messages() %} {% if messages %} <script> alert("{{messages[-1]}}"); </script> {% endif %} {% endwith %} {{result.title}} <br /> {{result.name}} <br /> {{result.pubdate|formatdatetime}} <br /> {{result.view}} <br /> {{result.contents}} <br /> <a href="{{url_for('lists', page=page, search=search, keyword=keyword)}}" >리스트</a > {% if session["id"] == result.writer_id %} <a href="{{url_for('board_delete', idx=result.id)}}">글삭제</a> <a href="{{url_for('board_edit', idx=result.id)}}">글수정</a> {% endif %} </html> ---------------------------------------------------------------------------------------------------- -write- <html> <body> <table> <form name="form" method="post" action="/write"> <tr> <td>작성자</td> <td><input type="text" name="name" value="{{session['name']}}" readonly /></td> </tr> <tr> <td>제목</td> <td><input type="text" name="title" /></td> </tr> <tr> <td>내용</td> <td><textarea type="text" name="contents"></textarea></td> </tr> <tr> <td colspan="2"><input type="submit" /></td> </tr> </form> </table> </body> </html> ------------------------------------------------------------------------------------------------------ -edit- <html> <body> <table> <form name="form" method="post" action="/edit/{{data._id}}"> <tr> <td>작성자</td> <td><input type="text" name="name" value="{{session['name']}}" readonly /></td> </tr> <tr> <td>제목</td> <td><input type="text" name="title" /></td> </tr> <tr> <td>내용</td> <td><textarea type="text" name="contents">{{data.contents}}</textarea></td> </tr> <tr> <td colspan="2"><input type="submit" /></td> </tr> </form> </table> </body> </html> -
- 해결됨남박사의 파이썬으로 실전 웹사이트 만들기
오류 나는 부분이 있어서 다시 질문 드립니다! 도와주세요! (join 로그인시 백지, 몽고db 이메일주소 null 표시)
안녕하세요 웹개발 입문부분 강좌를 거의다 들었는데.. 오류가 나는 부분이 있어서.. 질문을 올립니다! 문제는..join 로그인 하면 몽고db에서 이메일 주소가 null로 표시가 되서.. 동작이 되지 않는점이 있습니다.. 비슷한 증상을 찾기 어려워서 질문 남깁니다! -화면- -join- -mongoDB- -list- -list 로그인 페이지- next_url << 이게 문제가 나왔었는데 다른 코드들 참고 했는데 해결은 됬습니다. -run.py- from flask import Flask from flask import request from flask import render_template from flask_pymongo import PyMongo from bson.objectid import ObjectId from flask import abort from flask import redirect from flask import url_for from flask import flash from flask import session from functools import wraps import math import time from datetime import datetime, timedelta app = Flask(__name__) app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb" app.config["SECRET_KEY"] = "abcd" app.config["PERMANENT_SESSION_LIFETIME"] = timedelta(minutes=30) mongo = PyMongo(app) def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if session.get("id") is None or session.get("id") == "": return redirect(url_for("member_login", next_url=request.url)) return f(*args, **kwargs) return decorated_function @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", 1, type=int) # 한페이지당 몇개의 게시물을 출력할지 limit = request.args.get("limit", 5, type=int) search = request.args.get("search", -1, type=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}}) # 검색 대상이 한개라도 존재할 경우 query 변수에 $or 리스트를 쿼리 합니다. if len(search_list) > 0: query = {"$or": search_list} print(query) board = mongo.db.board datas = board.find({}).skip((page - 1) * limit).limit(limit) # 게시물의 총 갯수 tot_count = board.count_documents({}) # 마지막 페이지의 수를 구한다. 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=list(datas), limit=limit, page=page, block_start=block_start, block_last=block_last, last_page_num=last_page_num, search=search, keyword=keyword) @ app.route("/view/<idx>") @login_required def board_view(idx): # idx = request.args.get("idx") if idx is not None: page = request.args.get("page") search = request.args.get("search") keyword = request.args.get("keyword") board = mongo.db.board # data = board.find_one({"_id": ObjectId(idx)}) data = board.find_one_and_update({"_id": ObjectId(idx)}, { "$inc": {"view": 1}}, return_document=True) 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"), "writer_id": data.get("writer_id", "") } return render_template("view.html", result=result, page=page, search=search, keyword=keyword) return abort(404) @ app.route("/write", methods=["GET", "POST"]) def board_write(): if session.get("id") is None: return redirect(url_for("member_login")) 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 post = { "name": name, "title": title, "contents": contents, "pubdate": current_utc_time, "writer_id": session.get("id"), "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") @app.route("/join", methods=["GET", "POST"]) def member_join(): if request.method == "POST": name = request.form.get("name", type=str) email = request.form.get("email", type=str) pass1 = request.form.get("pass", type=str) pass2 = request.form.get("pass2", type=str) if name == "" or email == "" or pass1 == "" or pass2 == "": flash("입력되지 않은 값이 있습니다.") return render_template("join.html") if pass1 != pass2: flash("비밀번호가 일치하지 않습니다.") return render_template("join.html") members = mongo.db.members cnt = members.count_documents({"email": email}) if cnt > 0: flash("중복된 이메일 주소입니다.") return render_template("join.html") current_utc_time = round(datetime.utcnow().timestamp() * 1000) post = { "name": name, "email": email, "pass": pass1, "joindate": current_utc_time, "logintime": "", "logincount": 0, } members.insert_one(post) return "" else: return render_template("join.html") @app.route("/login", methods=["GET", "POST"]) def member_login(): if request.method == "POST": email = request.form.get("email") password = request.form.get("pass") next_url = request.form.get("next_url") members = mongo.db.members data = members.find_one({"email": email}) if data is None: flash("회원 정보가 없습니다.") return redirect(url_for("member_login")) else: if data.get("pass") == password: session["email"] = email session["name"] = data.get("name") session["id"] = str(data.get("_id")) session.permanent = True if next_url is not None: return redirect(next_url) else: return redirect(url_for("lists")) return redirect(url_for("lists")) else: flash("비밀번호가 일치하지 않습니다.") return redirect(url_for("member_login")) return "" else: next_url = request.args.get("next_url", type=str) if next_url is not None: return render_template("login.html", next_url=next_url) else: return render_template("login.html") @app.route("/edit/<idx>", methods=["GET", "POST"]) def board_edit(idx): if request.method == "GET": board = mongo.db.board data = board.find_one({"_id": ObjectId(idx)}) if data in None: flash("해당 게시물이 존재하지 않습니다.") return redirect(url_for("lists")) else: if session.get("id") == data.get("writer_id"): return render_template("edit.html", data=data) else: flash("글 수정 권한이 없습니다.") return redirect(url_for("lists")) else: title = request.form.get("title") contains = request.form.get("contents") board = mongo.db.board data = board.find_one({"_id": ObjectId(idx)}) if session.get("id") == data.get("writer_id"): board.update_one({"_id": ObjectId(idx)}, { "$set": { "title": title, "contents": contains, } }) flash("수정 되었습니다.") return redirect(url_for("board_view", idx=idx)) else: flash("글 수정 권한이 없습니다.") return redirect(url_for("lists")) @app.route("/delete/<idx>") def board_delete(idx): return "" if __name__ == "__main__": app.run(host="0.0.0.0", debug=True, port=9000) ------------------------------------------------------------------------------------------------ -join- {% with messages = get_flashed_messages() %} {% if messages %} <script> alert('{{messages[-1]}}'); </script> {% endif %} {% endwith %} <table> <form name="form" action="/join" method="POST"> <thead> <caption>회원가입</caption> </thead> <tbody> <tr> <td>이름</td> <td><input type="text" name="name"></td> </tr> <tr> <td>이메일</td> <td><input type="text" nmae="email"></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" name="pass"></td> </tr> <tr> <td>비밀번호 확인</td> <td><input type="password" name="pass2"></td> </tr> <tr> <td colspan="2"><input type="submit" value="가입하기"></td> </tr> </tbody> </form> </table> ---------------------------------------------------------------------------------------------------------- -login- {% with messages = get_flashed_messages() %} {% if messages %} <script> alert("{{messages[-1]}}"); </script> {% endif %} {% endwith %} <table> <form name="form" action="/login" method="POST"> {% if next_url %} <input type="hidden" name="next_url" value="{{next_url}}" /> {% endif %} <thead> <caption> 회원 로그인 </caption> </thead> <tbody> <tr> <td>이메일</td> <td><input type="text" name="email" /></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" name="pass" /></td> </tr> <tr> <td colspan="2"><input type="submit" value="로그인" /></td> </tr> </tbody> </form> </table> -------------------------------------------------------------------------------------------------------- - list - {% with messages = get_flashed_messages() %} {% if messages %} <script> alert('{{messages[-1]}}'); </script> {% endif %} {% endwith %} <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|length > 0 %} <table> <thead> <tr> <td>번호</td> <td>제목</td> <td>이름</td> <td>날짜</td> <td>조회수</td> </tr> </thead> <tbody> <!--반복되는 구간--> <tr> {% for data in datas %} <td>{{loop.index + ((page - 1) * limit)}}</td> <td> <a href="{{url_for('board_view', idx=data._id, page=page, search=search, keyword=keyword)}}">{{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, search=search, keyword=keyword)}}">[이전]</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, search=search, keyword=keyword)}}">{{ i }}</a> {% endif %} {% endif %} {% endfor %} {% if block_last < last_page_num %} <a href="{{url_for('lists', page=block_last + 1, search=search, keyword=keyword)}}">[다음]</a> {% endif %} <select name="search" id="search"> <option value="" {% if search=='' or search==-1 %} selected {% endif %}>검색대상</option> <option value="0" {% if search==0 %} selected {% endif %}>제목</option> <option value="1" {% if search==1 %} selected {% endif %}>내용</option> <option value="2" {% if search==2 %} selected {% endif %}>제목+내용</option> <option value="3" {% if search==3 %} selected {% endif %}>작성자</option> </select> <input type="text" name="keyword" id="keyword" {% if keyword !="" %} value="{{keyword}}" {% endif %} /> <input type="button" value="검색" onclick="search()" /> {% else %} <h3>데이터가 없습니다.</h3> {% endif %} <a href="{{url_for('board_write')}}">글작성</a> ------------------------------------------------------------------------------------------------------- - edit - <html> <body> <table> <form name="form" method="post" action="/edit/{{data._id}}"> <tr> <td>작성자</td> <td><input type="text" name="name" value="{{session['name']}}" readonly /></td> </tr> <tr> <td>제목</td> <td><input type="text" name="title" /></td> </tr> <tr> <td>내용</td> <td><textarea type="text" name="contents">{{data.contents}}</textarea></td> </tr> <tr> <td colspan="2"><input type="submit" /></td> </tr> </form> </table> </body> </html>
- 해결됨남박사의 파이썬으로 실전 웹사이트 만들기
회원가입 만들기 오류 문의 (AttributeError: 'Cursor' object has no attribute 'count') 오류
안녕하세요 몇일째 오류랑 씨름하다가 여기까지 왔는데.. 도저희 해결이 안나서 문의 남깁니다. 구글링이나.. 다른분들 오류 해결하시는거 찾아보면서 해도.. 계속오류 나면서 하니까 진도가 너무 늦네요..ㅠ 파이썬으로 실전 웹사이트 만들기 - 회원가입 페이지 만들기 중입니다. -오류내용- -코드- (run.py) from flask import Flask from flask import request from flask import render_template from flask_pymongo import PyMongo from bson.objectid import ObjectId from flask import abort from flask import redirect from flask import url_for from flask import flash import math import time from datetime import datetime app = Flask(__name__) app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb" app.config["SECRET_KEY"] = "abcd" 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", 1, type=int) # 한페이지당 몇개의 게시물을 출력할지 limit = request.args.get("limit", 5, type=int) search = request.args.get("search", -1, type=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}}) # 검색 대상이 한개라도 존재할 경우 query 변수에 $or 리스트를 쿼리 합니다. if len(search_list) > 0: query = {"$or": search_list} print(query) board = mongo.db.board datas = board.find({}).skip((page - 1) * limit).limit(limit) # 게시물의 총 갯수 tot_count = board.count_documents({}) # 마지막 페이지의 수를 구한다. 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=list(datas), limit=limit, page=page, block_start=block_start, block_last=block_last, last_page_num=last_page_num, search=search, keyword=keyword) @ app.route("/view/<idx>") def board_view(idx): # idx = request.args.get("idx") if idx is not None: page = request.args.get("page") search = request.args.get("search") keyword = request.args.get("keyword") 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, page=page, search=search, keyword=keyword) 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 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") @app.route("/join", methods=["GET", "POST"]) def member_join(): if request.method == "POST": name = request.form.get("name", type=str) email = request.form.get("email", type=str) pass1 = request.form.get("pass", type=str) pass2 = request.form.get("pass2", type=str) if name == "" or email == "" or pass1 == "" or pass2 == "": flash("입력되지 않은 값이 있습니다.") return render_template("join.html") if pass1 != pass2: flash("비밀번호가 일치하지 않습니다.") return render_template("join.html") members = mongo.db.members cnt = members.find({"email": email}).count() if cnt > 0: flash("중복된 이메일 주소입니다.") return render_template("join.html") current_utc_time = round(datetime.utcnow().timestamp(*1000)) post = { "name": name, "email": email, "pass": pass1, "joindate": current_utc_time, "logintime": " ", "logincount": 0 } members.insert_one(post) return "" else: return render_template("join.html") if __name__ == "__main__": app.run(host="0.0.0.0", debug=True, port=9000) (join.html) {% with messages = get_flashed_messages() %} {% if messages %} <script> alert('{{messages[-1]}}'); </script> {% endif %} {% endwith %} <table> <form name="form" action="/join" method="POST"> <thead> <caption>회원가입</caption> </thead> <tbody> <tr> <td>이름</td> <td><input type="text" name="name"></td> </tr> <tr> <td>이메일</td> <td><input type="text" nmae="email"></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" name="pass"></td> </tr> <tr> <td>비밀번호 확인</td> <td><input type="password" name="pass2"></td> </tr> <tr> <td colspan="2"><input type="submit" value="가입하기"></td> </tr> </tbody> </form> </table>
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
csrf 질문드려요
여기까지 공부 하고 기존에 작성 했던 코드들을 훌터 보고있습니다. __init__.py 파일을 보니 csrf = CSRFProtect(app) 이라는 코드가 작성되어있는데 csrf 라는 변수에 넣어두는 이유가있을까요? 그냥 CSRFProtect(app) 이라고 써도 될거 같은 느낌이에요 __init__.py 파일을 살펴봐도 csrf 변수를 사용하지 않는데, 변수에 넣어두는 이유를 모르겠습니다. 이유가 있다면 알려주시면 감사하겠습니다!!!
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
파일 저장 문의 드립니다.
질문이 많아서 죄송합니다. 하나 하나 모르는거 투성이네요 ;; 영상 27분 34초 보면 파일 저장경로 savefilepath = os.path.join(app.config['BOARD_IMAGE_PATH'], filename) 위코드에서 app.config['BOARD_IMAGE_PATH'] 이게 아니라 BOARD_IMAGE_PATH 이것만 넣어주면 안되나요? 굳이 환경변수를 넣는 이유를 모르겠습니다 제가 생각할때는 어차피 같은 값인데, 왜 더 긴코드를 넣는지 궁금해서 문의드립니다. 알려주신다면 감사하겠습니다
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
if문 문의 드립니다.
어떤 데이터가 있는지 이전에 if문을 사용하실때는 if a is not None - 이런식으로 작성하셨어요 그런데, 영상 25분 33초에 보면 여기 if문은 if file and allowed_file(file.filename): 이렇게 작성해 주셨는데 if file is not None and allowed_file(file.filename): 이렇게 작성하는거랑 if file and allowed_file(file.filename): 이렇게 작성하는거랑 똑같이 동작하고 같은 의미인게 맞나요?
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
image[0] 이 이해가 안가네요
선생님 덕분에 포기하지 않고 열심히 공부하고 있습니다 항상 감사 합니다 영상중 19분 3초 쯤에 보면 ajax를 설명해주고 계신데 코드중에서 $("#summernote").summernote('insertNode', image[0]) 위 코드가 있습니다 여기서 image[0] - 이 코드가 이해가 안가는데 설명좀 부탁드립니다 image는 어차피 1개만 만들었는데 왜 뒤에 [0] 을 붙이는건지 알려주시면 감사하겠습니다.
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
mongo --nodb로 실행할 경우, mongo shell이 작동하나 단순히 mongo만 작성할 경우 mongdo shell이 나오지 않습니다.
해당 오류를 해결하다가 몽고디비가 제대로 설치된지 알기 위해 mongo 터미널에 적어보았는데 MongoDB shell version v5.0.6 connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb Error: couldn't connect to server 127.0.0.1:27017, connection attempt failed: SocketException: Error connecting to 127.0.0.1:27017 :: caused by :: Connection refused : connect@src/mongo/shell/mongo.js:372:17 @(connect):2:6 exception: connect failed exiting with code 1 이러한 오류가 출력되었고 이에 대한 해결책으로 mongo --nodb를 실행시켰을 때 mongo shell까지는 작동되었습니다. 찾아본 봐 mongo --nodb는 디비 서버에 연결하지 않은 상태로 작동되는 명령어라고 하는데, db서버에 연결하여 작동되게 하는 법은 무엇이 있을까요. robo 3T도 위와 같은 에러가 출력되어서 진도를 못나가고있는 상황입니다. 혹시, 현재 mac m1을 사용하고 있으므로 mac OS 중심으로 설명부탁드려도 될까요?
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
신기방기합니다.. board 에 글저장이 안되네요 ㅠ
너무 신기해요 ...이게 가능한 일인지 모르겠습니다 회원가입하면 myweb 데이터베이스에 members 컬렉션에 db가 잘 저장됩니다. 글작성하면, 리스트에 출력은 되는데 myweb > board 에 들어가보면 새로쓴글이 없네요 .. 리스트에 출력이 안된다면 이해 하겠는데, 리스트에 출력은 잘되구요 ㅠㅠ 위처럼 새로쓴글들이 출력은 잘되요 아래는 board_write 구요 코드는 위와 같구요 무엇이 문제일까요 ㅠㅠ config는 이렇게 세팅되어있어요, 회원가입이 제대로 저장되는거보니 설정은 문제 없는거 같긴해요 그런데 robo3t에서 보면 글이 50개뿐이 없네요.. 저건 크롤링한 글 50개 거든요 robo3t에 다른 데이터 베이스나, 컬렉션은 안보이는데 어찌된 영문인지 모르겠습니다 ㅠㅠ 도와주세요
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
포커스 할때 select() 이건 무슨 역할인가요?
join.html 에서 검증 스크립트에서 if(pass1 != pass2){ alert('비밀번호가 일치하지 않습니다'); $('#pass2').select().focus(); return false; } 위 코드가 있습니다 focus 할때 select는 무슨역할 인지 알려주시면 감사하겠습니다
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
querystring (get방식)으로 파라미터가 숫자라서 false가 됩니다
선생님 수업 잘듣고 있습니다 다름이 아니라 검색기능 수업중에서 select 의 value 와 keyword의 value 자바스크립트로 self.location.href를 이용하여 get방식으로 값을 넘기는 내용이 있습니다 약 48분 정도쯤에 있는 내용이구요 select 값의 value를 0, 1, 2, 3, 4 로 설정해놓아서 이중에서 하나의 값을 넘기는데요 get방식으로 넘길때, 숫자가 넘어가는게 아니라 false가 넘어가는데 도저히 해결이 안되네요 get방식 값이 http://192.168.1.13:9000/list?search=false&keyword=%ED%8C%8C%EC%9D%B4%EC%8D%AC 이렇게 나옴니다 search = 숫자 이렇게 나와야 하는데 false가 들어가니 해결이 안되네요 영상에는 잘되는데 저는 잘안되서 이후 강의에 있는 선생님이 수업자료로 첨부하신 코드를 가져와서 실행해도 안됩니다 ㅠㅠ
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
pymongo.errors.ServerSelectionTimeoutError 및 DB연결 문제
안녕하세요 몇 가지 문제가 생겨 질문드립니다. 1. 글쓰기 html파일은 잘 작동하는데 글상세보기로 넘어가지지 않습니다. 2. db연결이 잘 되었는지가 궁금한데 robo 3T상 myweb이라는 db이름이 안나와 확인이 불가합니다. 어딘가 놓친 부분이 없는지 확인 부탁드립니다. 아래는 error 화면 및 소스코드입니다. 참고로 아래와 같이 프린트는 잘 진행됩니다. # -*- coding: cp949 -*- 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 import time from flask_pymongo.wrappers import Database from pymongo import database app = Flask(__name__) # 프로토콜명 :// 주소 : 포트 / db이름 app.config["MONGO_URI"] = "mongodb://locolhost: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) - database.utcfromtimestamp(now_timestamp) vlaue = datetime.fromtimestamp(int(value)/1000) + offset return value.strftime('%Y-%m-%d %H:%M:%S') @app.route("/view") def board_view(): idx = request.args.get("idx") if idx is not None: board = mongo.db.board board.find_one({"_id": ObjectId(idx)}) if database is not None: result = { "id": database.get("_id"), "name": database.get("name"), "title": database.get("title"), "contents": database.get("contents"), "pubdate": database.get("pubdate"), "view": database.get("view") } return render_template("view.html", result=result) return abort(404) # Not Found @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 post = { "name": name, "title": title, "contents": contents, "pubdate": current_utc_time, "view": 0 } x = board.insert_one(post) print(x.insert_id) return "" else: return render_template("write.html") if __name__ == "__main__": app.run(host="0.0.0.0", debug=True, port=9000)
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
ubuntu 20 에서 virtualenv 설치시 디렉토리가 틀리다고 하는데
- 뭐가 잘못 된거지 서버 환경이 틀려서 그러는거 같은데..
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
DB내용과 다르게 출력이 되는 경우가 있습니다.
몽고DB 의 내용을 조회해서 단순히 웹에 출력되는 걸 만들어 봤는데요. 데이터가 이상하게 출력되는 경우가 있습니다. 실제 DB상의 데이터는 7.6 인데 이걸 조회헤서 웹에 뿌리면 7.6000000000000005 로 표현이 됩니다. 이런 경우 어떻게 처리해야 할까요?
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
리스트 추가
강사님 강의는 너무 잘듣고 있습니다. 게시판 만들기까지 했는데 혹시 추가로 주제가 다른 게시판을 만들려면 보통 어떻게 코드를 짜나요? 지금까지 짠 프로그램 모두복붙해서 해야하는지,,, 새로운 리스트 Html을 만들고 def lists를 복붙하고 또 몽고디비를 새로 만들어서 하는지, 아니면 몽고 디비 하나로 주제를 다르게 해서 find로 관리를 하는지,,? 응용해서 주제가 다른 게시판하나를 만들어 보려고 하는데 어떻게 접근해야할지 감이 안오네요
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
tot_count = board.find({}).count() 구문오류
안녕하세요 박사님 구문오류 관련 질문이 있습니다. 현재 저는 몽고디비 4.0.1 버전 이용중입니다. 아래 코드를 실행하면 AttributeError: 'Cursor' object has no attribute 'count' 으로 실행이 되지 않습니다. count()를 countDocument()로 바꿔도 보았는데 해결이 안되어 이렇게 문의드립니다. def lists(): page = request.args.get("page", default=1, type = int) limit = request.args.get("limit",10,type=int) board = mongo.db.board datas = board.find({}).skip((page-1)*limit).limit(limit) tot_count = board.find({}).count()
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
안녕하세요 문의드립니다
안녕하세요 남박사님 영상의 11분 23초까지 내용인 applicationhostconfig 파일의 handlers 부분을 Allow로 바꾸고 저장까지 해주었는데도 500 에러가 나면서 여전히 접속이 안되고 있습니다. 영상에 나온대로 설정을 해주었는데 어느 부분이 문제가 되는건지 모르겠어서 질문드립니다~
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
안녕하세요 질문드립니다
안녕하세요 남박사님 댓글 기능을 따라 구현했는데 댓글을 입력하고 등록해도 아래와 같이 계속 None으로만 보여지는데 어떻게 하면 될지 문의드립니다
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
jinja2.exceptions 와 관련하여 질문 드립니다
- 안녕하세요 남박사님! 강의를 통해 직접 웹페이지를 제작해보고 있는 수강생입니다! 강의자료를 토대로 작성하였으나.. jinja2 문법에서 계속 오류가 발생하고 있는 것을 확인하였습니다. 구글링을 통해 확인해본 결과, 끝처리에 }}을 인식하지 못하여 생기는 오류라고 하는데 현재 오류가 뜨는 list.html의 42번째 줄인 [이전]이 있는 곳의 끝에는 }}가 잘 붙어있는 것을 확인할 수 있습니다. 어느 부분에서 오류가 발생하는지 여쭤보고 싶습니다. 감사합니다!
- 미해결남박사의 파이썬으로 실전 웹사이트 만들기
게시판 글쓰기
from flask import Flaskfrom flask import requestfrom flask import render_templatefrom pymongo import MongoClientclient = MongoClient('localhost', 27017)db = client.pythonwebmakeapp = Flask(__name__)@app.route('/write', methods=['get', 'post'])def write(): if request.method == 'post': name = request.form.get("name") title = request.form.get("title") contents = request.form.get("contents") doc = { "name": name, "title": title, "contents": contents } db.pythonweb.insert_one(doc) return "" else: return render_template("index.html")if __name__ == '__main__': app.run('0.0.0.0', port=5000, debug=True) <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>게시판 웹사이트</title></head><body> <table> <form name="form" method="post" action="/write"></form> <tr> <td>작성자</td> <td><input type="text" name="name"></td> </tr> <tr> <td>제목</td> <td><input type="text" name="title"></td> </tr> <tr> <td>내용</td> <td><textarea name="contents"></textarea></td> </tr> <tr> <td colspan="2"><input type="submit"></td> </tr> </form> </table></body></html> localhost:5000/write에서 인풋들의 값을 입력해서 제출을 눌러도 아무 반응 없고 studio3t에도 데이터들이 넘어오지 않습니다