blog

Flask開発フォーラム - 質問を追加する

今のところ、ユーザープロフィールとログインはできていますが、ユーザープロフィールはホームページでリンクされていません。お気づきのように、最近ページの読み込みが非常に遅くなっています。必要なリソースをG...

Oct 10, 2020 · 6 min. read
シェア

ここまでで、ユーザープロフィールとログインはできましたが、ユーザープロフィールはホームページにリンクが追加されていません。では、追加してみましょう:

<!-- app/templates/base.html -->
<!--...-->
<!DOCTYPE html>
<html lang="en">
<head>
 <!--...-->
</head>
<body>
 <nav class="navbar navbar-expand-lg navbar-light bg-light">
 <!--...-->
 <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
 <a class="dropdown-item" href="{{ url_for('user.user_profile', username=current_user.username) }}">個人情報</a>
 <a class="dropdown-item" href="{{ url_for('auth.logout') }}"> </a>
 </div>
 </nav>
 <!--...-->
</body>
<!--...-->
</html>

お気づきかもしれませんが、最近ウェブページの読み込みが非常に遅くなっています。その原因は、ローカルリソースの代わりにCDNを使用しているためです。GitHubにリソースを置いているので、必要であれば自分でダウンロードしてください。以下はローカルからリソースを読み込むコードです:

<!-- app/templates/base.html -->
{# Bootstrapをインポートする-Flaskの組み込み関数は #}
{% from 'bootstrap/nav.html' import render_nav_item %}
{% from 'bootstrap/utils.html' import render_messages %}
<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>{% block title %}{% endblock %} {#   #}</title>
 {# カスタムBootstrapを紹介する css #}
 <link rel="stylesheet" href="{{ url_for('static', filename='css/bootstrap.css') }}">
 <link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
 <link rel="stylesheet" href="{{ url_for('static', filename='fonts/font-awesome-4.7.0/css/font-awesome.css') }}">
</head>
<body>
 <!--...-->
</body>
{% block scripts %} {# JS  #}
<!--jsの紹介-->
<script src="{{ url_for('static', filename='js/jquery.js') }}"></script>
<script src="{{ url_for('static', filename='js/popper.js') }}"></script>
<script src="{{ url_for('static', filename='js/bootstrap.js') }}"></script>
{{ moment.include_moment(local_js=url_for('static', filename='js/moment-with-locales.js')) }}
{{ moment.locale('zh') }} {# フラスコをセットアップする-momentデフォルトの言語は英語だ。 #}
{% endblock %}
</html>

さて、これでリソースの読み込みがかなり速くなりました。それでは本日の本題、問題の追加に入りましょう。

(ヒューヒュー

質問を追加するには、まずデータベースモデルを作成します。models.pyを開き、Questionモデルを作成します:

# app/models.py
# ...
class Question(db.Model):
 """問題モデリング"""
 __tablename__ = 'questions'
 id = db.Column(db.Integer, primary_key=True)
 # 質問タイトル
 title = db.Column(db.String(64))
 # Markdownテキストをフォーマットする
 body_markdown = db.Column(db.Text)
 # HTMLテキストをフォーマットする
 body_html = db.Column(db.Text)
 # パブリッシャーID
 author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
 def __repr__(self):
 return '<Question %d>' % self.id

次に、Userモデルにリレーションシップを追加します:

class User(db.Model, UserMixin): # Userdbから継承したクラス.Model
 """ユーザーモデル"""
 __tablename__ = 'users' # テーブル名を定義する
 # ...
 # 質問
 questions = db.relationship('Question', backref='author', lazy='dynamic')
 # ...

その後、データベースをアップグレードします:

flask db migrate
flask db upgrade

さて、最も基本的な質問モデルが構築されたので、次はビューを書きましょう。質問ビューを保持するために新しい質問フォルダを作成します。

i>init.py **```テキスト

app/question/init.py

from flask import ブループリント

question = ブループリント('question', name, url_prefix='/question')

から. インポートビュー

i>views.py
**```python
# app/question/views.py
from . import question
from flask_login import current_user, login_required
from flask import request, render_template
from ..models import Question
from ..extensions import db
from .forms import AddQuestionForm
@question.route('/add/', methods=['GET', 'POST'])
@login_required
def add():
 form = AddQuestionForm()
 if form.validate_on_submit():
 title = form.title.data
 body_markdown = form.body_markdown.data
 # エディターを入手する.md自動生成HTML
 body_html = request.form['editormd-html-code']
 # 問題を作る
 _question = Question(
 title=title, body_markdown=body_markdown, body_html=body_html, author=current_user)
 db.session.add(_question)
 # データベースに保存する
 db.session.commit()
 return render_template('question/add.html', form=form)

i>forms.py **``python

app/question/forms.py

from wtforms import StringField, TextAreaField, HiddenField, SubmitField from wtforms.validators import DataRequired from flask_wtf importFlaskForm

さて、トリッキーな部分に入ろう:テンプレートだ。
お気づきかもしれないが、このモデルは問題の本体をMarkdownとHTMLの両方のフォーマットで定義しており、すべてMarkdownエディターが必要だ。私が選んだのは
[https://../.md/#%06](ps://../.md/#%06)
バージョン番号はb2cab15だから、必要なら自分で手に入れられるよ。
エディターをダウンロードする.mdそれを解凍し、editormdにリネームし、staticディレクトリに置く。それから、templatesフォルダにquestionフォルダを作成し、問題のJinjaテンプレートを保存する。
i>templates/question/add.html
**```html
<!--app/templates/question/add.html-->
{% extends 'base.html' %}
{% from 'bootstrap/form.html' import render_field %}
{% block title %}問題を作る{% endblock %}
{% block content %}
<div class="container">
 <h1>問題を作る</h1>
 <hr>
 <!--手動フォーム生成-->
 <form method="POST" action="{{ url_for('question.add') }}">
 <!--WTFCSRFトークンは-->
 {{ form.csrf_token() }}
 <!--タイトルをレンダリングする-->
 {{ render_field(form.title) }}
 <!--ボディボックスを手動でレンダリングする-->
 <div id="editormd" style="border-radius: 5px;">
 {{ form.body_markdown() }}
 </div>
 <!--投稿ボタンをレンダリングする-->
 {{ render_field(form.submit, button_map={'submit': 'primary'}) }}
 </form>
</div>
{% endblock %}
{% block scripts %}
{{ super() }}
<!--エディターを読み込む.mdの依存ファイルは-->
<link rel="stylesheet" href="{{ url_for('static', filename='editormd/css/editormd.min.css') }}">
<script src="{{ url_for('static',filename='editormd/editormd.min.js') }}"></script>
<script>
 // editor  
 var editor;
 $(function () {
 // editor.mdeditormd "divの最初のtextareaを自動的に探してくれる。
 editor = editormd('editormd', {
 // 立っているテキスト
 placeholder: '問題の説明を入力する',
 // エディタの高さ
 height: 640,
 // スクロール・ロック
 syncScrolling: 'both',
 // editormd依存ライブラリの場所
 path: "{{ url_for('static',filename='editormd/lib/') }}",
 // コード・フォールディングを有効にする
 codeFold : true,
 // textareaにhtmlを自動保存する
 saveHTMLToTextarea : true,
 // 置換検索
 searchReplace : true,
 //  
 emoji : true,
 // TODO表
 taskList : true,
 //  
 tocm: true,
 // tex 
 tex : true,
 //  
 flowChart : true,
 //  
 sequenceDiagram : true,
 // イメージアップロードを有効にしない
 imageUpload : false
 });
 });
</script>
{% endblock %}

さて、最も基本的な質問ができました。これがbase.htmlのリンクです:

<!-- app/templates/base.html -->
<!--...-->
<!DOCTYPE html>
<html lang="en">
<head>
 <!--...-->
</head>
<body>
 <nav class="navbar navbar-expand-lg navbar-light bg-light">
 <!--...-->
 <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink">
 <a class="dropdown-item" href="{{ url_for('question.add') }}">質問を追加する</a>
 <a class="dropdown-item" href="{{ url_for('user.user_profile', username=current_user.username) }}">個人情報</a>
 <a class="dropdown-item" href="{{ url_for('auth.logout') }}"> </a>
 </div>
 <!--...-->
 </nav>
 <br>
 {{ render_messages(container=True, dismissible=True, dismiss_animate=True) }} {# Bootstrapを使う-Flask点滅メッセージをレンダリングする組み込み関数 #}
 <br>
 {% block content %}{% endblock %} {#   #}
</body>
<!--...-->
</html>

現在作成されているページは以下のようになります:

Read next

1日1ビッグリート(最低間隔) 難易度:ハードデー

整数を昇順に並べたk個の配列があります.k個のリストのそれぞれが少なくとも1つの数を含むような最小の区間を求めなさい. 区間[a,b]は,b-a &#x3C; d-cのとき,またはb-a == d-cのときa &#x3C; cのとき,[c,d]より小さくなるように定義しなさい. 与えられたリストには重複した要素が含まれる可能性があるので、...

Oct 10, 2020 · 3 min read