점프 투 플라스크 / 190p 작성글 수정부분 질문

models.py

# 데이터베이스 조회를 위한 py파일
from pybo import db

# 질문
class Question(db.Model):
    # 질문 데이터 고유번호(id) 조회
    id = db.Column(db.Integer, primary_key=True)
    # 제목 조회
    subject = db.Column(db.String(200), nullable=False)
    # 내용 조회
    content = db.Column(db.Text(), nullable=False)
    # 작성일시 조회
    create_date = db.Column(db.DateTime(), nullable=False)

    user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), nullable=False)
    user = db.relationship('User', backref=db.backref('question_set'))
    modify_date = db.Column(db.DateTime(), nullable=True)

# 딥변
class Answer(db.Model):
    # 답변 데이터 고유번호(id) 조회
    id = db.Column(db.Integer, primary_key=True)
    # 질문의 고유 번호 / 어떤 질문에 달린 답변인지 알아야 함으로
    question_id = db.Column(db.Integer, db.ForeignKey('question.id', ondelete='CASCADE'))
    question = db.relationship('Question', backref=db.backref('answer_set', ))
    # 답변내용
    content = db.Column(db.Text(), nullable=False)
    # 답변 작성일시
    create_date = db.Column(db.DateTime(), nullable=False)

    user_id = db.Column(db.Integer, db.ForeignKey('user.id', ondelete='CASCADE'), nullable=False)
    user = db.relationship('User', backref=db.backref('answer_set'))
    modify_date = db.Column(db.DateTime(), nullable=True)

# 회원정보
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    userName = db.Column(db.String(150), unique=True, nullable=False)
    password = db.Column(db.String(200), nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)

question_detail

{% extends 'base.html' %}
{% block content %}

<div class="container my-3">
    {# question_views 의 detail 함수에서 가져온 데이터베이스 정보를 출력 #}
    <h2 class="border-bottom py-2">{{ question.subject }}</h2>
    <div class="card my-3">
        <div class="card-body">
            <div class="card-text" style="white-space: pre-line">{{ question.content }}</div>
            <div class="d-flex justify-content-end">
                <div class="badge badge-light p-2 text-left">
                    <div class="mb-2">{{ question.user.userName }}</div>
                    <div>{{ question.create_date|datetime }}</div>
                </div>
            </div>
            {% if g.user == question.user %}
                <div class="my-3">
                    <a href="{{ url_for('question.modify', question_id=question.id) }}" class="btn btn-sm btn-outline-secondary">수정</a>
                    <a href="#" class=" delete btn btn-sm btn-outline-secondary" data-uri="{{ url_for('question.delete', question_id=question.id) }}">삭제</a>
                </div>
            {% endif %}
        </div>
    </div>
    {# |length 필터를 사용하여 갯수를 가져올 수 있다. #}
    <h5 class="border-bottom my-3 py-2">{{ question.answer_set|length }}개의 답변이 있습니다.</h5>
    {% for answer in question.answer_set %}
        <div class="card my-3">
            <div class="card-body">
                <div class="card-text" style="white-space: pre-line">{{ answer.content }}</div>
                <div class="d-flex justify-content-end">
                    <div class="badge badge-light p-2 text-left">
                        <div class="mb-2">{{ answer.user.userName }}</div>
                        <div>{{ answer.create_date|datetime }}</div>
                    </div>
                </div>
                {% if g.user == answer.user %}
                    <div class="my-3">
                        <a href="{{ url_for('answer.modify', answer_id=answer.id) }}" class="btn btn-sm btn-outline-secondary">수정</a>
                    </div>
                {% endif %}
            </div>
        </div>
    {% endfor %}
    {# answer_views.py 안의 create함수를 호출하고 id값을 넘겨준다. #}
    <form action="{{ url_for('answer.create', question_id=question.id) }}" method="post" class="my-3">
        {{ form.csrf_token }}
        {# 오류표시 시작 #}
        {% for field, errors in form.errors.items() %}
            <div class="alert alert-danger" role="alert">
                <strong>{{ form[field].label }}</strong>: {{ ', '.join(errors) }}
            </div>
        {% endfor %}
        {# 오류표시 끝 #}
        <div class="form-group">
            <textarea {% if not g.user %}disabled{% endif %} name="content" id="content" class="form-control" rows="10"></textarea>
        </div>
        <input type="submit" value="답변등록" class="btn btn-primary">
    </form>
</div>

{% endblock %}
{% block script %}
    <script type="text/javascript">
        $(document).ready(function (){
            $('.delete').on('click', function (){
                if(confirm("정말로 삭제하시겠습니까?")){
                    location.href = $(this).data('uri');
                }
            });
        });
    </script>
{% endblock %}

question_views.py

# 날짜와 시간을 처리하는 datetime 임포트
from datetime import datetime
# 플라스크 모듈모음
from flask import Blueprint, render_template, request, url_for, g, flash
# 유틸리티 모듈 임포트
from werkzeug.utils import redirect
# 데이터베이스 임포트
from .. import db
# models모듈에서 질문 부분 임포트
from ..models import Question
# forms 부분에서 질문과 답변 임포트
from ..forms import QusetionForm, AnswerForm

from pybo.views.auth_views import login_required

# 블루프린트 경로 설정
bp = Blueprint('question', __name__, url_prefix='/question')

# list부분 / main_views에서 redirect로 question._list 처리 하여서 이 쪽으로 들어오게 된다.
# render_template 으로 question/question_list.html를 보여주게 되니 이게 곧 메인페이지가 된다.
@bp.route('/list/')
def _list():
    page = request.args.get('page', type=int, default=1)

    # 데이터베이스에 있는 정보를 가지고 온다.
    question_list = Question.query.order_by(Question.create_date.desc())

    question_list = question_list.paginate(page, per_page=10)

    # question_list를 호출하면서 question_list의 정보를 넘겨준다.
    return render_template('question/question_list.html', question_list=question_list)

# question_list에서 a링크에 detail로 이동하면서 아이디 값을 같이 넘겨준다.
# 그 아이디 값을 주소 detail/ 뒤에 인트형으로 출력한다.
@bp.route('/detail/<int:question_id>/')
def detail(question_id):
    # 작성 폼 forms.py에서 임포트 한 것
    form = AnswerForm()
    # 데이터베이스 연결된 클래스 Question에서 받은 question_id를 가진 정보를 가져온다. 만약 없다면 404에러를 띄운다.
    question = Question.query.get_or_404(question_id)
    # detail 페이지를 호출하면서 아이디값을 가져온 question과 폼 양식 form 을 넘긴다.
    return render_template('question/question_detail.html', question=question, form=form)

@bp.route('/create/', methods=('GET', 'POST'))
@login_required
def create():
    form = QusetionForm()
    if request.method == 'POST' and form.validate_on_submit():
        question = Question(subject=form.subject.data, content=form.content.data, create_date=datetime.now(), user=g.user)
        db.session.add(question)
        db.session.commit()
        return redirect(url_for('main.index'))
    return render_template('question/question_form.html', form=form)

@bp.route('/delete/<int:question_id>')
@login_required
def delete(question_id):
    question = Question.query.get_or_404(question_id)
    if g.user != question.user:
        flash('삭제권한이 없습니다')
        return redirect(url_for('question.detail', question_id=question_id))
    db.session.delete(question)
    db.session.commit()
    return redirect(url_for('question._list'))

@bp.route('/modify/<int:question_id>', methods=('GET', 'POST'))
@login_required
def modify(question_id):
    question = Question.query.get_or_404(question_id)
    if g.user != question.user:
        flash('수정권한이 없습니다')
        return redirect(url_for('question.detail', question_id=question_id))
    if request.method == 'POST':
        form = QusetionForm()
        if form.validate_on_submit():
            form.populate_obj(question)
            question.modify_date = datetime.now()
            db.session.commit()
            return redirect(url_for('question.detail', question_id=question_id))
        else:
            form = QusetionForm(obj=question)
        return render_template('question/question_form.html', form=form)


에러 :
TypeError
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.

Traceback (most recent call last)
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 2464, in call
return self.wsgi_app(environ, start_response)
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 1953, in full_dispatch_request
return self.finalize_request(rv)
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 1968, in finalize_request
response = self.make_response(rv)
File "/Users/simmyeongseob/Desktop/venvs/myproject/lib/python3.8/site-packages/flask/app.py", line 2097, in make_response
raise TypeError(
TypeError: The view function did not return a valid response. The function either returned None or ended without a return statement.
The debugger caught an exception in your WSGI application. You can now look at the traceback which led to the error.
To switch between the interactive traceback and the plaintext one, you can click on the "Traceback" headline. From the text traceback you can also create a paste of it. For code execution mouse-over the frame you want to debug and click on the console icon on the right side.

You can execute arbitrary Python code in the stack frames and there are some extra helpers available for introspection:

dump() shows all variables in the frame
dump(obj) dumps all that's known about the object

어떤게 잘 못되었을 까요 ?

myoungseob91 1156

2021년 3월 17일 5:49 오후

목록으로
1개의 답변이 있습니다. 1 / 1 Page

죄송합니다. 해결하였습니다. 책을 보게 되면 184~185p 넘어가면서 코드가 약간 잘리는데
들여쓰기 칸수를 보니 제가 질문한 코드대로 나열이 되어있더라구요, 블럭을 당기니 정상작동합니다.

def modify(question_id):
    question = Question.query.get_or_404(question_id)
    if g.user != question.user:
        flash('수정권한이 없습니다')
        return redirect(url_for('question.detail', question_id=question_id))
    if request.method == 'POST':
        form = QusetionForm()
        if form.validate_on_submit():
            form.populate_obj(question)
            question.modify_date = datetime.now()
            db.session.commit()
            return redirect(url_for('question.detail', question_id=question_id))
        else:
            form = QusetionForm(obj=question)
        return rendertemplate('question/questionform.html', form=form)

이게 제가 적은 코드이고 정상적인 코드는 아래와 같습니다. else의 위치에 따라 오류가 납니다.

def modify(question_id):
    question = Question.query.get_or_404(question_id)
    if g.user != question.user:
        flash('수정권한이 없습니다')
        return redirect(url_for('question.detail', question_id=question_id))
    if request.method == 'POST':
        form = QusetionForm()
        if form.validate_on_submit():
            form.populate_obj(question)
            question.modify_date = datetime.now()
            db.session.commit()
            return redirect(url_for('question.detail', question_id=question_id))
    else:
        form = QusetionForm(obj=question)
    return rendertemplate('question/questionform.html', form=form)

myoungseob91

2021년 3월 17일 6:18 오후