묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 핵심 원리 - 기본편
request 스코프 예제 서버 실행 문제에 대해 질문드립니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요. 처음 Spring boot에 입문한 취준생입니다. 선생님의 강좌를 잘 따라가다가 문제가 발생했습니다. [request 스코프 예제] request 스코프 예제중 web라이브러리도 잘 추가했고, 실행결과 Tomcat 서버거 실행되는 것 까지는 확인이 되었습니다. 그 후에 MyLogger, LogDemoController, LogDemoService를 추가하여 실행했을때 강의에서 처음에는 서버의 오류가 발생했지만,만 저의 로그를 봤을때에는 error발생 없이 2022-04-13 16:33:03.542 INFO 16264 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet' 2022-04-13 16:33:03.542 INFO 16264 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet' 2022-04-13 16:33:03.543 INFO 16264 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms 이런식의 로그가 뜬 채로 아무것도 되지 않았고, 그 후에 수정한 코드를 넣어봐도 결과는 같았습니다. 구글링을 해보았지만 그렇다 한 해결책을 내놓지 못했고, 혹시나 해서 logDemo메서드에 soutm을 해 보아도 찍혀 나오는게 없었습니다. 한번 살펴봐 주시면 감사하겠습니다. [프로젝트 압축링크] https://drive.google.com/file/d/1I8royGvDc4BXMUtSOTGCPRtNBtnoFg4S/view?usp=sharing
-
미해결[R을 R려줘] R 기초다지기
R 작업폴더 경로가 이상합니다
10강에서 working directory 확인할때도 경고가 뜨고 6강 패키지 다운로드할때도 에러뜨고 노트북에 깔려있는 Onedrive 때문에 작업경로가 다 꼬여서 너무 답답합니다 노트북 말고 다른 컴퓨터에서는 에러나 경고없이 잘만 실행되는데 Onedrive때문에 계속 꼬이네요 스트레스인데 해결방법 있나요?
-
미해결[입문] Qt 6 프로그래밍 1편
클래스 이벤트 함수 사용법 문의
강사님 Model/View 예제 이용해 사용방법 익히기 까지 수강하였습니다. 해당 강의에 올려주신 예제에서 우측의 TreeView에서 파일을 클릭(더블클릭)하면 파일명과 경로등을 일단 단순위 qDegug()룰 통해 출력할려고 합니다. 이때 connect 를 통해 slot함수와 이벤트 함수를 연결하려고 하는데. 트리뷰에서 파일을 더블클릭했을때의 멤버변수를 알아야 하는데 관련 클래스에서 어떠어떠한 이벤트 멥버함수가 있는지 어떻게 알 수 있을까요? 막상 하려니 막히네요 ^^ 제 생각에는 일단 connect를 통해 해당 아이템 더블클릭 이벤트를 발생시키고 이때 선택된 아이템의 파일명을 String으로 가져와 출력해주면 될것 같은데요... 도움부탁드립니다.
-
미해결실전! 스프링 데이터 JPA
PDF 변경해야 될 부분
PDF 25p부분에 공통 인터페이스 계층구조를 그려놓으신 부분에서 CrudRepository 변경할 부분 findOne(ID) -> findById(ID) 로 수정된 것을 보고 혹시 다른것도 바뀌었을 것같아서 살펴봤습니다. exists(ID) -> existsById(ID) 로 변경되었는 것을 볼 수 있습니다. 이 부분도 PDF에 추가해주시면 다른 분들도 헷갈리지 않으실 것 같습니다!!!
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
HelloSpringApplication 실행시 오류
=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용] 실행을 할 경우 인텔리제이 콘솔창에서 OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release. 라는 에러가 최상단에 뜨고 밑에 부분은 똑같이 나옵니다. 강의 따라서 index.html 파일 생성후에 페이지 새로고침을 해도 변경이 안됩니다!
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
인텔리제이 무료버전 jsp
인텔리제이 무료버전이라서 jsp 파일을 생성했을 때 적용이 안 되는 건가요?ㅠㅠ 일반 텍스트 파일처럼 써지고 색깔도 안 생기고 그래서요..
-
미해결Vue.js 시작하기 - Age of Vue.js
프로젝트 cli 버전 질문
안녕하세요 강사님! 정말 잘듣고 있습니다 ! 22년 4월 기준 디폴트값으로 Vue2, 3 중 아무거나 선택해도 상관없을까요? 21년과 달리 지금은 Vue3가 프리뷰버전이 아닌거 같아서요! 가능하시다면 현재의 버전에서 두가지의 차이점?같은 것도 설명해주시면 감사하겠습니다!
-
해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
try catch문이 2개일 때 변환 방법에 대해 질문드리고 싶습니다
강사님 안녕하세요유튜브 강의에서 .then( ) .catch( ) 와 try{ } catch{ } 가 같다고 가르쳐주신 말씀을 듣고 혹시 이렇게 고쳐도 되는지 질문드리고 싶습니다아래의 코드를 promise then으로 변경시도했습니다 (async () => { try { await Promise.resolve("Hello") throw new Array(-1) } catch(err) { if (err.message==='Invalid array length') { await Promise.resolve("Hello") } else { console.error(err.message); exit(1); } } try { const data1 = await Promise.resolve("Hello"); await Promise.resolve("Hello") await Promise.resolve("Hello") const data2 = await Promise.resolve("Hello") } catch(err) { console.error(err.message); } })() 1번째 변경 코드는 1행부터 14행까지만 수정했습니다이 경우에는 16행부터의 try catch문이 기능을 상실했습니다2번째 변경코드는 1행부터 25행까지 수정했습니다 2번째 소스코드는 이렇습니다 (() => { return Promise.resolve("Hello") .then(()=>{ throw new Array(-1) }) .catch(async(err)=>{ if (err.message==='Invalid array length') { await Promise.resolve("Hello") } else { console.error(err.message); exit(1); } }) .then(async()=>{ const data1 = await Promise.resolve("Hello"); await Promise.resolve("Hello") await Promise.resolve("Hello") const data2 = await Promise.resolve("Hello") }) .catch(err=> { console.error(err.message); }) })() 혹시 이렇게 2번째 방법으로 변환하는 게 맞는지 질문드리고 싶습니다함수 하나에 try catch 문이 2개 있으면1번째 try catch문만 promise then으로 변경하지 말고1번째 2번째 try catch문 전부 promise then으로 변경해야 하는지 질문드리고 싶습니다긴 질문을 읽어주셔서 감사합니다
-
미해결JIRA를 활용해 더 효과적으로 프로젝트 협업하기
워크플로우를 신규 상태와 보드 설정 열관리에서의 상태 매칭 관련 문의
안녕하세요 강사님 강의 잘 보고 있습니다. 구글에 아무리 검색해봐도 답을 찾지 못해서 문의드립니다. 워크플로우를 신규로 만들었고 [ 기획완료, 디자인완료, 개발완료 ] 는 범주를 "완료"로 지정하였습니다. Jira 에서 생성한 신규 프로젝트에서 보드 설정 > 열관리에 들어가서 [ 열추가 ] 를 하여 워크플로우에서 만든 각 상태별로 열을 추가하였는데..워크플로우에서 생성한 [ 기획완료, 디자인완료, 개발완료 ] 상태가 '완료"로 지정되지 않고 보드설정 > 열관리에서 열을 추가하면 "진행중" 으로만 계속 추가됩니다. 보드설정 > 열관리에서 열 추가하면 "완료" 상태를 관리자가 추가할 수는 없는건가요?
-
미해결스프링 핵심 원리 - 기본편
lombok과 autowired
안녕하세요 항상 강의 잘 보고 있습니다! 동일한 타입으로 되어있는 경우, 필드명으로 명시하면 된다고 이해했습니다. 그런데 lombok @RequiredArgsConstructor를 사용하게되면 생성자를 자동으로 만들어줘서 필드명으로 명시할 수 가 없는데 이럴 경우에는 @Qulifier나 @Primary를 사용하면 되는건가요? 감사합니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
@Component 와 implements Validator
@Component public class ItemValidator implements Validator { @Override public boolean supports(Class<?> clazz) { return item.class.isAssignableFrom(clazz); } @Override public void validate(Object target, Errors errors) { ..생략.. } } 에서 @Component를 하는 이유가 컨트롤러에서 빈을 주입하기 위함이고 Spring의 interface인 Validator를 상속 받아 쓰기 때문에 라고 강의에서 이해했는데요 Spring이 제공하는 기능이나, Spring이 제공하는 interface를 상속받아 쓰는 클래스를 갖다 쓸 때는 @Component가 있어야 된다고 이해하는 게 맞겠죠 ?
-
해결됨파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트
django-pydenticon을 import 했을 때, attributeError가 발생해 질문드립니다.
- 여러분의 질문을 고대하고 있습니다. :-)- 질문 전에 검색을 먼저 해보세요. 사람 사는 게 다 비슷하다는 것을 알게 됩니다.- 예의는 거침없이 질문하기 위한 최고의 발명품입니다.- 100개의 설명이 스크린샷 한방 보다 못할 수 있습니다.- 코드를 첨부하면 전세계 누구나 이해할 수 있는 질문이 됩니다.- 하나의 질문에는 하나의 주제를 담아야 답변도 예리해집니다.- 시행착오를 알려주시면 곧 바로 원하는 문제에 집중할 수 있습니다.- 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 안녕하세요 강사님 항상 좋은 강의 들으면서 열심히 공부하고 있습니다. 다름이 아니라 프로필 이미지가 없을 경우 대체 이미지를 표현하는 django-pydenticon에 대한 문제를 해결하지 못하여 질문드립니다. pip install django-pydenticon을 먼저 완료한 후, common.py에 추가했습니다. 그 후, common.py의 installed_apps에 'django_pydenticon'을 추가했습니다. 그 후, project의 urls.py에 django-pydenticon을 import 한 후, path도 등록했더니 attributeError가 발생했습니다. 구글링을 해도 오류를 찾지 못해 질문 남깁니다. 아래는 오류 화면입니다.
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
JPA로그레벨 설정문의
강사님께서 진행한 결과와 다르게 콘솔에 찍히는 로그는 아래와 같이 DEBUG레벨까지 정보를 보여주고 있습니다. 15:19:38.870 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - begin 15:19:38.879 [main] DEBUG org.hibernate.SQL - select member0_.id as id1_0_0_, member0_.name as name2_0_0_ from Member member0_ where member0_.id=? 강의에서 찍힌 로그와 동일하게 출력하기 위해서 로그레벨 설정하는 방법을 알고자합니다. springJPA설정이 아닌 jpa설정으로 가능한지요?
-
해결됨야곰의 iOS 프로그래밍
버튼 이미지 크기가 조절이 안 되는데 어떤 부분을 조정해야 할까요?
야곰님이 하신 것처럼 버튼 크기를 줄이면 이미지도 같이 크기가 줄어들 것으로 생각했는데 저는 버튼 크기가 줄어도 이미지는 크기가 그대로입니다. 버튼에서 이미지가 넘쳐요 ㅠㅠ 뭐가 문제일까요?
-
미해결딥러닝 CNN 완벽 가이드 - TFKeras 버전
대용량 시계열 엑셀 데이터의 딥러닝에 관하여
안녕하세요 대용량 시계열 엑셀 데이터를 딥러닝으로 결과를 내는것에 대해 질문 드립니다. 현재 10~100기가 정도 까지의 대용량 엑셀 데이터를 딥러닝으로 학습시켜보려고 합니다. 그런데 현재 시도해보려는 방식이 과연 적절한지 의문이 들어서 문의 드립니다. 100기기가 정도되는 시계열 엑셀 데이터를 딥러닝 CNN 완벽 가이드에서 공부하는 방식으로 학습하는게 적절한지요?? 머신러닝 같은 경우 저같은 경우 pandas dataframe을 통해 학습하는 것을 경험해 본 바 있습니다만 강사님의 경우 spark 라는 대용량 데이터에 적합한 머신러닝 tool을 활용하여 학습하는 강의가 있는 것으로 알고 있습니다. 제 의문사항은 딥러닝에서도 spark와 같이 대용량 데이터를 잘 처리할 수 있는 tool을 따로 사용해야되지 않을까 싶어서 문의 드립니다.
-
해결됨웹 게임을 만들며 배우는 React
useEffect의 두 번째 배열인자에 변하는 값을 넣으면 useEffect안의 코드가 재실행되면서 두번째 배열에 넣은 인자값을 계속 추적하게 되나요?
useEffect(() => { interval.current = setInterval(changeHand, 1000) return () => { clearInterval(interval.current) } }, []) 했을때 가위바위보가 제대로 실행이 안되고 useEffect(() => { interval.current = setInterval(changeHand, 1000) return () => { clearInterval(interval.current) } }, [imgCoord]) 했을때는 가위바위보가 제대로 실행되는 이유가 imgCoord 값이 변경될때 useEffect안에있는 코드들이 다시 실행되어서 인건 이해했습니다. 그렇다면 두 번째 인자 배열에 imgCoord값을 넣으면 useEffect안의 코드인 interval.current = setInterval(changeHand, 1000)가 재실행되어서 imgCoord값이 바뀔때 imgCoord값을 추적하게 되니까 imgCoord값이 '바위' -> '가위' -> '보' -> '바위' 이렇게 바뀔 수 있는 건가요?
-
해결됨만들면서 배우는 리액트 : 기초
고양이 이미지들 로딩이 안 됩니다!
502 Bad Gateway 가 뜨면서 이미지 로딩이 안 됩니다~ 일단은 다른 이미지 쓰면서 강의 듣고 있는데 고양이들 이제 못 보는 걸까요? 😿
-
해결됨[리뉴얼] Node.js 교과서 - 기본부터 프로젝트 실습까지
익명화살표함수에 대해 질문드리고 싶습니다
강사님 안녕하세요익명 화살표 함수를 선언하자마자 실행할 때 이렇게 하면 실행이 안되고 (()=>{ console.log( "Hello\n" )})이렇게 한번 더 ( ) 를 붙여주면 실행이 되었습니다(()=>{ console.log( "Hello\n" )})() 혹시 이 원리와 람다가 관련이 있는지 질문드리고 싶습니다
-
해결됨데이터 사이언스 입문 부트캠프
KESS 다운로드 어디서 할 수 있나요?
이 과정에서는 엑셀, KESS기반으로 진행하신다고 하셨는데 현재 KESS를 다운받을 수가 없습니다 저는 현재 2019엑셀을 쓰고 있는데, 그렇다면 KESS없이 본 과정을 수강할 수 있나요...?
-
미해결남박사의 파이썬으로 실전 웹사이트 만들기
글 작성 폼에 HTML 에디터 기능 추가하기 이미지 저장 오류..ㅠ
남박사님 계속 질문해서 죄송합니다..ㅠ 하다보니까 계속 오류가 나네요.... 이미지 업로드 관련해서 ajax 부분에서 오류가 나는것은 영상을 따라 하면서 해봐도 계속 같은 오류가 나와서 답답해서 질문드립니다. - 오류1 - 영상대로 수정하고 적용해서 똑같은 오류가 나오더라구요.. 그래서 이미지 업로드창 눌러서 해봤는데 비슷한 오류가 나옵니다. -오류2- -오류3- - 코드- -write.html- {% extends "main.html" %} {% block contents %} <script> $(document).ready(function() { $("#summernote").summernote({ height: 300, minHeight: null, maxHeight: null, lang: "ko-KR", popover: { image:[], link:[], air:[] }, callbacks: { onImageUpload: function(image) { for(var i = 0; i < image.length; i++) { uploadImage(image[i]); } } } }); }); function uploadImage(image) { var data = new FormData(); data.append("image", image); $.ajax({ url: "{{url_for('board.upload_image')}}", cache: false, contentType: false, processData: false, data: data, type:"post", success: function(url) { var image = $("<img>").attr("src",url).css('max-width', "900px"); $("#summernote").summernote("insertNode",image[0]); }, error: function(data) { console.log(data); alert(data); } }); } </script> <script> function checkForm() { if ($.trim($("#title").val()) == "") { alert("제목을 입력하세요"); $("#title").focus(); return false; } if ($.trim($("#summernote").val()) == "") { alert("내용을 입력하세요"); $("#summernote").focus(); return false; } } </script> <div style="padding: 50px 50px 50px 50px;"> <form name="form" method="post" action="{{url_for('board.board_write')}}" onsubmit="return checkForm()"> <div class="form-group"> <label for="name">작성자</label> <input class="form-control" id="name" type="text" name="name" value="{{session['name']}}" readonly> </div> <div class="form-group"> <label for="title">제목</label> <input class="form-control" type="text" name="title" id="title" placeholder="제목을 입력하세요"/> </div> <div class="form-group"> <label for="contents">내용</label> <textarea rows="8" class="form-control" type="text" name="contents" id="summernote" placeholder="내용을 입력하세요"></textarea> </div> <div class="text-center"><input class="btn btn-primary" type="submit" value="작성하기"></div> </form> </div> {% endblock %} --------------------------------------------------------------------------------------- -viev.html- {% extends "main.html" %} {% block contents %} <div style="padding: 50px 50px 50px 50px;"> <table class="table table-bordered"> <tbody> <tr> <td colspan="2">{{result.title}}</td> </tr> <tr> <td>{{result.name}}</td> <td class="text-right">{{result.pubdate|formatdatetime}}</td> </tr> <tr> <td colspan="2"><div style="min-height: 200px;"></div>{% autoescape false %}{{result.contents}}{% endautoescape %}</td> </tr> </tbody> </table> <a class="btn btn-primary" href="{{url_for('board.lists', page=page, search=search, keyword=keyword)}}">리스트</a> {% if session["id"] == result.writer_id %} <a class="btn btn-danger float-right ml-2" href="{{url_for('board.board_delete', idx=result.id)}}">글삭제</a> <a class="btn btn-warning float-right" href="{{url_for('board.board_edit', idx=result.id)}}">글수정</a> {% endif %} </div> {% endblock %} --------------------------------------------------------------------------------------------------- -main.html- <!DOCTYPE html> <html lang="kr"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{{title}}</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/css/bootstrap.min.css" integrity="sha384-zCbKRCUGaJDkqS1kPbPd7TveP5iyJE0EjAuZQTgFLD2ylzuqKfdKlfG/eSrtxUkn" crossorigin="anonymous"> <script src="https://code.jquery.com/jquery-3.6.0.min.js" type="text/javascript"></script> <script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF" crossorigin="anonymous"></script> <!-- include summernote css/js --> <link href="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/summernote@0.8.18/dist/summernote.min.js"></script> <script> function validateEmail(email) { var pattern = /^[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_.]?[0-9a-zA-Z])*.[a-zA-Z]{2,3}$/; return pattern.test(email); } </script> {% with messages = get_flashed_messages() %} {% if messages %} <script> alert('{{messages[-1]}}'); </script> {% endif %} {% endwith %} </head> <body> <div class="containter"> {% include "menu.html" %} {% block contents %} {% endblock %} </div> </body> </html> -------------------------------------------------------------------------------------------------- -board.py- from main import * from flask import Blueprint, send_from_directory from flask import send_from_directory bluerprint = Blueprint("board", __name__, url_prefix="/board") @bluerprint.route("/upload_image", methods=["POST"]) def upload_image(): if request.method == "POST": file = request.files["image"] if file and allowed_file(file.filename): filename = "{}.jpg".format(rand_generator()) savefilepath = os.path.join(app.config["BOARD_IMAGE_PATH"], filename) file.save(savefilepath) return url_for("board.board_images", filename=filename) @bluerprint.route("/images/<filename>") def board_images(filename): return send_from_directory(app.config["BOARD_IMAGE_PATH"], filename) @bluerprint.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, title="게시판 리스트") @bluerprint.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, title="글 상세보기") return abort(404) @bluerprint.route("/write", methods=["GET", "POST"]) def board_write(): if session.get("id") is None: return redirect(url_for("member.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.board_view", idx=x.inserted_id)) else: return render_template("write.html", title="글 작성") @bluerprint.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 is None: flash("해당 게시물이 존재하지 않습니다.") return redirect(url_for("board.lists")) else: if session.get("id") == data.get("writer_id"): return render_template("edit.html", data=data, title="글 수정") else: flash("글 수정 권한이 없습니다.") return redirect(url_for("board.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.board_view", idx=idx)) else: flash("글 수정 권한이 없습니다.") return redirect(url_for("board.lists")) @bluerprint.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("board.lists")) --------------------------------------------------------------------------------- -__init__.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 datetime import datetime, timedelta from flask import abort from flask import redirect from flask import url_for from flask import flash from flask import session import math import time import os 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) BOARD_IMAGE_PATH = "C:\\python\\images" ALLOWED_EXTENSIONS =set(["txt", "pdf", "png", "jpg", "jpeg", "gif"]) app.config["BOARD_IMAGE_PATH"] = BOARD_IMAGE_PATH app.config["MAX-CONTENT_LENGTH"] = 15 * 1024 * 1024 if not os.path.exists(app.config["BOARD_IMAGE_PATH"]): os.mkdir(app.config["BOARD_IMAGE_PATH"]) # 아래의 파일들에서 main 의 app 에 접근을 해야하니 # 아래 import 위에 app 가 선언되어야 합니다. from .common import login_required, allowed_file, rand_generator from .filter import format_datetime # member, board 에서 login_required, format_datetime 을 사용하니까 # 당연히 member 와 board 가 위의 import 보다 먼저 나와선 안됩니다. from . import member from . import board app.register_blueprint(board.bluerprint) app.register_blueprint(member.bluerprint)