작성
·
2.8K
1
이전까지는 잘되다가 jinja를 쓸 때부터 에러가 뜹니다.
이전 강의 코드는 그대로 따라하니 잘 되었구요, 이번 강의에서 run.py 에 추가된 부분은
@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("/view")
def board_view():
idx = request.args.get("idx")
if idx is not None:
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)
return abort(400)
이 것들과 기능을 사용하기 위해 import나 선생님 설명 받아적어서 주석처리한 글 몇 줄이 있습니다.
그리고 templates 폴더에 view.html 파일로
<html>
{{result.title}}
<br />
{{result.name}}
<br />
{{result.pubdate|formatdatetime}}
<br />
{{result.view}}
<br />
{{result.contents}}
</html>
이렇게 만들었습니다. 주석으로 설명 몇 자 적어놨구요.
에러 페이지는
jinja2.exceptions.TemplateSyntaxError: tag name expected
__call__
return self.wsgi_app(environ, start_response)
wsgi_app
response = self.handle_exception(e)
handle_exception
reraise(exc_type, exc_value, tb)
reraise
raise value
wsgi_app
response = self.full_dispatch_request()
full_dispatch_request
rv = self.handle_user_exception(e)
handle_user_exception
reraise(exc_type, exc_value, tb)
reraise
raise value
full_dispatch_request
rv = self.dispatch_request()
dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
board_view
return render_template("view.html", result=result)
render_template
ctx.app.jinja_env.get_or_select_template(template_name_or_list),
get_or_select_template
return self.get_template(template_name_or_list, parent, globals)
get_template
return self._load_template(name, self.make_globals(globals))
_load_template
template = self.loader.load(self, name, globals)
load
code = environment.compile(source, name, filename)
compile
self.handle_exception(source=source_hint)
handle_exception
reraise(*rewrite_traceback_stack(source=source))
reraise
raise value.with_traceback(tb)
template
만약에 for문을 쓰거나 if문을 쓰거나할 때는 {% %} 이런식으로 사용하기도 한다.
jinja2.exceptions.TemplateSyntaxError: tag name expected
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 framedump(obj)
dumps all that's known about the object
이렇게 생겼습니다.
눈으로 봐도 모르겠고 디버깅에도 딱히 걸리지 않아서 원인이 뭔지를 모르겠습니다..ㅠㅠ
답변 2
0
run.py
# -*- coding: utf-8 -*-
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
app = Flask(__name__)
app.config["MONGO_URI"] = "mongodb://localhost:27017/myweb"
# MONGO_URI는 정해진 문자열이라서 바꾸면 안된다. 프로토콜명을 앞에 써주고 주소:포트/데이터베이스 이름 을 써주면된다.
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)
# datetime.fromtimestamp(now_timestamp)
# 현재 이 클라이언트의 타임스탬프를 기준으로 datetime 객체를 만들어준다.
# datetime.utcfromtimestamp(now_timestamp)
# utc 시간 객체를 반환해서 준다.
# 현재 datetime객체와 똑같은 현재시간을 utc타임객체로 바꾼다음에
# 같은 시간값으로 두가지(utc, 일반시간)을 구해서 그 차를 구한다.
# 시간차이 = datetime형 현재시간 - datetime형 UTC시간
value = datetime.fromtimestamp((int(value) / 1000) + offset)
# sec형태로 db에 저장된 글 작성시간을 다시 millisecond로 변경
# db에 저장된 UTC 시간 + 시간차 = 현재로컬시간 기준으로 작성일자가 표기됨
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
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)
return abort(400)
# 이 부분은 백단에서 html로 데이터를 넘기는 부분이다. result(변수명) = 변수값은 위에 있는 부분.
# view?idx=몽고db 아이디값 // ?의 의미는 ? 앞까지는 주소고 뒤에부터는 데이터라는걸 구분짓는것이다.
# 데이터는 변수명과 값으로 이뤄져있다. idx=1234&a=10&b=20 이런식이다. 이런게 GET방식으로 데이터를 전송하는 방식이다
# idx를 얻기위해서는 request.args.get으로 idx를 받아온다. 만약 받아와야되는 값이 a이면 a라고 쓰면된다.
# idx로 변수명을 사용하는 이유는 id라는 단어는 여러곳에서 이미 예약된 단어로 사용되는 경우가 많아서 idx로 사용한다.
# abort는 오류코드를 페이지가 동작하게 만든거다.
# view.html 파일은 templates 폴더에 만들어야한다.
@app.route("/write", methods=["POST", "GET"])
# POST와 GET을 모두 사용하려면 둘 다 사용하려면 선언을 해줘야한다. 생략을 하면 GET만 사용된다.
def board_write():
if request.method == "POST":
name = request.form.get("name")
# 리퀘스트 메소드가 post인 경우에 리퀘스트.폼에서 겟을 한다.
# form을 post를 전송했기에 해당하는 객체를 받아서 처리할 수 있다.
# post로 전송된 데이터는 url상에 노출되지 않고, get은 url에 노출된다.
title = request.form.get("title")
contents = request.form.get("contents")
print(name, title, contents)
current_utc_time = round(datetime.utcnow().timestamp() * 1000)
# UTC와 GMT는 소수점 차이만 있을뿐 큰 차이가 없어 혼용해서 사용하기도 한다. utc는 협정세계표준시라고 할 수 있다.
# 날짜데이터는 가장 가공하기 쉬운 형태로 데이터베이스에 저장해놔야한다.
# 국가마다 혹은 상황에 따라 날짜를 표기하는 방식이 달라질 수 있다.
# utcnow는 밀리세컨즈로 나오기에 1000을 곱하고 소숫점이 나올 수 있으므로 round 함수로 반올림해준다.
board = mongo.db.board
# mongo.db 까지는 써야된다. 위에서 mongo라는 변수를 받아놨고, 몽고디비의 db라는 기능을 쓰고
# board라는 컬렉션에 접근을 할것이다. 있으면 객체가 리턴되고 없으면 board가 생성된다.
post = {
"name": name,
"title": title,
"contents": contents,
"pubdate": current_utc_time,
"view": 0,
}
x = board.insert_one(post)
print(x.inserted_id)
return str(x.inserted_id)
else:
return render_template("write.html")
# html 파일은 경로가 없는데 templates 폴더에 있는 write.html을 찾아서 렌더링해서 우리가 볼 수 있게된다.
if __name__ == "__main__":
app.run(host="0.0.0.0", debug=True, port=9000)
write.html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>write</title>
</head>
<body>
<table>
<form name="form" method="POST" action="/write">
<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>
<!-- colspan=2 은 2개의 span을 하나로 쓰겠다는 의미. */ -->
</tr>
</form>
</table>
</body>
</html>
view.html
<html>
{{result.title}}
<br />
{{result.name}}
<br />
{{result.pubdate|formatdatetime}}
<br />
{{result.view}}
<br />
{{result.contents}}
</html>
<!--
여기서 result는 board_view 함수의 마지막부분에서 리턴받은 result이다.
-->
<!-- 파이썬 플라스크에서 사용하는 진자라는 템플리트 엔진의 문법이다
변수를 쓸 때 변수의 값을 이런식으로 쓴다.
만약에 for문을 쓰거나 if문을 쓰거나할 때는 {% %} 이런식으로 사용하기도 한다.
-->
이게 코드 전부입니다.
위에서 {% %} 부분을 지우면
TypeError: unsupported operand type(s) for +: 'float' and 'datetime.timedelta'
__call__
return self.wsgi_app(environ, start_response)
wsgi_app
response = self.handle_exception(e)
handle_exception
reraise(exc_type, exc_value, tb)
reraise
raise value
wsgi_app
response = self.full_dispatch_request()
full_dispatch_request
rv = self.handle_user_exception(e)
handle_user_exception
reraise(exc_type, exc_value, tb)
reraise
raise value
full_dispatch_request
rv = self.dispatch_request()
dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
board_view
return render_template("view.html", result=result)
render_template
return _render(
_render
rv = template.render(context)
render
self.environment.handle_exception()
handle_exception
reraise(*rewrite_traceback_stack(source=source))
reraise
raise value.with_traceback(tb)
top-level template code
{{result.pubdate|formatdatetime}}
format_datetime
value = datetime.fromtimestamp((int(value) / 1000) + offset)
TypeError: unsupported operand type(s) for +: 'float' and 'datetime.timedelta'
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 framedump(obj)
dumps all that's known about the object
이런식으로 에러가 바뀌네요.
0
전체 코드를 올려주셔야 좀 더 확실한 원인을 알 수 있을것 같습니다만 일단 오류 내용으로만 봤을때 view.html 의 18째줄에 주석을 달아놓으셨는지 정확히 무슨 내용이 있는지 모르겠지만 주석안에 "{% %}" 이 내용이 문제가 되는것일 수 있습니다. 전체 코드를 보지 않아 확실하진 않지만 대략 그런 문제가 아닐까 추측해봅니다. 이 문제가 아니라면 전체 코드를 올려서 다시 질문주시면 감사하겠습니다.