from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField
from wtforms.validators import DataRequired
class QuestionForm(FlaskForm):
subject = StringField('제목', validators=[DataRequired('제목은 필수 입력 항목입니다.')])
content = TextAreaField('내용', validators=[DataRequired('내용은 필수 입력 항목입니다.')])
class AnswerForm(FlaskForm):
content = TextAreaField('내용', validators=[DataRequired('내용은 필수 입력 항목입니다.')])
forms.py 입니다.
AnswerForm을 추가시켜서 댓글 작성란에 무조건 입력을 해야하는 검증을 넣었습니다.
from datetime import datetime
from flask import Blueprint, url_for, request, render_template
from werkzeug.utils import redirect
from .. import db
from ..models import Question, Answer
from ..forms import AnswerForm
bp = Blueprint('answer', __name__, url_prefix='/answer')
@bp.route('/create/<int:question_id>', methods=('POST', ))
def create(question_id):
form = AnswerForm()
question = Question.query.get_or_404(question_id) # 그 질문에 해당하는 번호를 가져온다.
if form.validate_on_submit():
content = request.form['content'] # name 속성이 content인 값
answer = Answer(content=content, create_date=datetime.now()) # textArea 내용, 작성시각
question.answer_set.append(answer) # question.answer_set 은 Answer과 동일 즉, 거기에다가 값을 추가하는 것임
db.session.commit() # db에 저장
return redirect(url_for('question.detail', question_id=question_id)) # 상세 질문과 답변이 있는 페이지로 전달
return render_template('question/question_detail.html', question=question, form=form)
answer_views.py입니다.
댓글 작성에 만약 form.validate_on_submit()으로 form 검증이 올바른 경우 댓글 등록하는 기능을 넣고
만약 올바르지 않던가 아무런 submit이 없으면 question_detail.html화면을 보여주게 했습니다.
from datetime import datetime
from flask import Blueprint, render_template, request, url_for
from ..models import Question
from werkzeug.utils import redirect
from .. import db
from ..forms import QuestionForm, AnswerForm
bp = Blueprint('question', __name__, url_prefix='/question')
@bp.route('/list')
def _list():
question_list = Question.query.order_by(Question.create_date.desc())
return render_template('question/question_list.html', question_list=question_list)
@bp.route('/detail/<int:question_id>')
def detail(question_id):
form = AnswerForm()
question = Question.query.get_or_404(question_id)
return render_template('question/question_detail.html', question=question, form=form)
@bp.route('/create/', methods=('GET', 'POST'))
def create():
form = QuestionForm()
if request.method == 'POST' and form.validate_on_submit():
question = Question(subject=form.subject.data, content=form.content.data, create_date=datetime.now())
db.session.add(question)
db.session.commit()
return redirect(url_for('main.index'))
return render_template('question/question_form.html', form=form)
question_views.py 입니다.
def detail 함수도 수정해줘야 합니다. form값을 보내야지 밑에 새로 정의할 내용
Flask-WTF를 사용하려면 플라스크 환경 변수 SECRET_KEY가 필요합니다. SECRET_KEY는 CSRF라는 웹 사이트 취약 점 공격을 방지하는데 사용합니다.
(사용자의 요청을 위조하는 웹 사이트 공격 기법입니다. ) CSRF 토큰은 폼으로 전송된 데이터가 실제 웹 페이지에서 작성된 데이터인지를 판단해 주는 역할을 합니다.
먼저 cmd를 이용해 설치하겠습니다.
import os
BASE_DIR = os.path.dirname(__file__)
SQLALCHEMY_DATABASE_URI = 'sqlite:///{}'.format(os.path.join(BASE_DIR, 'pybo.db'))
SQLALCHEMY_TRACK_MODIFICATIONS = False
SECRET_KEY = 'dev'
# SQLALCHEMY_DATABASE_URI에는 DB접속 주소가 들어간다.
# BASE_DIR 은 루트디렉터리 경로를 의미 (C:/projects/myproject/)'
# pybo.db를 루트디렉터리에 저장하는 것
# SQLALCHEMY_TRACK_MODIFICATIONS는 이벤트 처리 옵션 지금은 필요 없어서 False로 비활성화
config.py을 열어서 SECRET_KEY 환경 변수를 추가하겠습니다.
SECRET_KEY = "dev"는 위험한 설정입니다. 실제 서비스에서는 유추하기 쉬운 문자열을 입력하면 안 됩니다.
value="{{ form.subject.data or '' }}"이거만 추가시켜주면 됩니다.
form.forms.py에서 작성한 변수.data그 변수의 데이터를 보관해준다는 의미입니다.
or ''의 경우는 데이터가 아무 것도 안 적혀있을 때 None 값이 나오게되는데 기본값을 ''으로 해준다는 의미입니다.
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField
from wtforms.validators import DataRequired
class QuestionForm(FlaskForm):
subject = StringField('제목', validators=[DataRequired('제목은 필수 입력 항목입니다.')])
content = TextAreaField('내용', validators=[DataRequired('내용은 필수 입력 항목입니다.')])
forms.py 입니다.
나오는 오류 메세지를 한글로 바꿔보도록 하겠습니다. DataRequired 안에 추가만 시키면 됩니다.
예를 들어서 부트스트랩의 link가 대표적이고 어떤 부분은 어느 한 부분만 똑같은 부분이 있을 수도 있습니다.
그래서 중복되는 것들을 하나의 html에 저장해서 불러오면 되는 것입니다.
(여기에서는 위에 부분이 바뀌지 않음)
{% extends 'base.html' %} 이걸로 불러 올 수 있습니다. 하지만 이것만 쓰면 전체가 다 덮어씌워지게 됩니다. 즉 question_list에 적으면 base.html로 다 덮어씌워지게 되는 것이죠 그래서{% block content %} 와 {% endblock %} 을 사용해서 question_list가 쓰일 수 있는 영역을 만들어주는 것입니다.
from datetime import datetime
from flask import Blueprint, url_for, request
from werkzeug.utils import redirect
from pybo import db
from pybo.models import Question, Answer
bp = Blueprint('answer', __name__, url_prefix='/answer')
@bp.route('/create/<int:question_id>', methods=('Post', ))
def create(question_id):
question = Question.query.get_or_404(question_id) # 그 질문에 해당하는 번호를 가져온다.
content = request.form['content'] # name 속성이 content인 값
answer = Answer(content=content, create_date=datetime.now()) # textArea 내용, 작성시각
question.answer_set.append(answer) # question.answer_set 은 Answer과 동일 즉, 거기에다가 값을 추가하는 것임
db.session.commit() # db에 저장
return redirect(url_for('question.detail', question_id=question_id)) # 상세 질문과 답변이 있는 페이지로 전달
답변을 작성 했으면 다시 상세 질문과 답변이 있는 페이지로 이동해야하니 redirect했습니다.
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
import config
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.config.from_object(config) # config.py에 작성 내용을 환경 변수로 부르기 위한 작업
# ORM
db.init_app(app) # 우리가 적은 환경으로 DB 초기화
migrate.init_app(app,db) # DB와 우리가 적은 환경을 다른 환경으로 옮김
from . import models
from .views import main_views, question_views, answer_views # .view에서 .은 현재위치의 views 폴더로부터 import한다는 말
app.register_blueprint(main_views.bp) # 블루프린트 객체 bp 등록
app.register_blueprint(question_views.bp) # 블루프린트 객체 bp 등록
app.register_blueprint(answer_views.bp)
return app
from flask import Flask
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
import config
db = SQLAlchemy()
migrate = Migrate()
def create_app():
app = Flask(__name__)
app.config.from_object(config) # config.py에 작성 내용을 환경 변수로 부르기 위한 작업
# ORM
db.init_app(app) # 우리가 적은 환경으로 DB 초기화
migrate.init_app(app,db) # DB와 우리가 적은 환경을 다른 환경으로 옮김
from . import models
from .views import main_views, question_views # .view에서 .은 현재위치의 views 폴더로부터 import한다는 말
app.register_blueprint(main_views.bp) # 블루프린트 객체 bp 등록
app.register_blueprint(question_views.bp) # 블루프린트 객체 bp 등록
return app
__init__.py입니다.
from flask import Blueprint, render_template, url_for
from werkzeug.utils import redirect
bp = Blueprint('main', __name__, url_prefix='/')
@bp.route('/hello')
def hello_pybo():
return 'Hello, Pybo!'
@bp.route('/')
def index():
return redirect(url_for('question._list'))
main_views.py입니다. 중복된 거를 빼고 index()를 수정했습니다.
question._list에 해당하는 URL로 redirect할 수 있게 수정했습니다. 입력받은 URL로 리다이렉트 해줍니다.
url_for에 있는 question._list는 question, _list 순서로 해석되어 함수명을 찾아줍니다.
question은 등록된 블루 프린트 이름을 의미하고
(bp = Blueprint('question', __name__, url_prefix='/question') 이 부분입니다.
보통은 SQLite로 개발을 빠르게 진행하고 실제 운영 시스템에 반영할 땐 좀 더 규모가 큰 데이터베이스를 사용 합니다.
응용프로그램이 파일을 읽어서 테이블에 CRUD따위의 작업을 한다
📝127.0.0.1과 localhost
127.0.0.1과 localhost는 현재 컴퓨터를 가리키는 아이피 주소이다.
📝ORM
데이터베이스와 객체 지향 프로그래밍 언어간의 호환되지 않는 데이터를 변환하는 프로그램 기법 객체 관계 매핑이라고도 한다.
즉, 객체 지향 프로그래밍 언어로 작성한 걸 DB에서 읽을 수 있는 걸로 매핑시켜주는 것 → DB도 객체 지향적으로 개발이 가능 ( DB쿼리문 작성 등을 해당 언어로 할 수 있게 해준다)
💗 ORM 장점
완벽한 객체 지향 코드로서 직관적인 이해가 쉽다 → SQL이 아닌 클래스 메서드를 통해 DB를 조작할 수 있어서 프로그래밍에 집중할 수 있게한다.
재사용 유지보수, 리팩토링이 용이하다 → SQL문이 아닌 프로그래밍을 통해 작성하기 때문에 용이하다
DBMS 종속성 하락→ SQL 자동생성은 물론 객체의 자료형 타입까지 사용할 수 있기 때문에 DBMS를 교체 하는 작업에 리스크가 적고 드는 소요 시간도 줄어든다
⚠️ ORM 단점
모든 것을 ORM으로만 해결할 수는 없다→ 프로젝트가 복잡할수록 실수를 만들 수 있고 대형 SQL문은 속도를 위해 별도 튜닝이 필요해 SQL을 써야할 수도 있다.
📝알고리즘
문제 해결을 위한 방법들입니다.
예를 들자면 지하철역으로 가는 문제를 해결하기 위해서는 걸어가는 방법 또는 차를 타고 가는 방법 또는 버스를 타고 가는 방법 등이 있는데 이러한 것들을 알고리즘이라고 합니다. 우리들은 거기중에서 가장 효율적인방법 (고객이나 본인이 원하는 방법)을 찾아야합니다 어떤 사람은 비용 상관없이 빨리 도착하는 방법이 중요할테고 어떤 사람은 시간이 걸리더라도 비용이 적게 드는 방법을 원하니 그에 맞는 알고리즘을 찾는 게 중요합니다.
정답은 없습니다만 잘못된 방법은 있죠
📝자료구조
알고리즘을 해결하기 위해서 필요한 재료같은 거라고 생각하면 됩니다. 많이 아시는 배열, 리스트, 튜플, 컬렉션프레임워크 등이 해당됩니다.