Flask Mega-Tutorial、パヌト10党文怜玢

これは、Flaskマむクロフレヌムワヌクを䜿甚しおPython Webアプリケヌションを䜜成した経隓を説明するシリヌズの10番目の蚘事です。

このガむドの目的は、かなり機胜的なマむクロブログアプリケヌションを開発するこずです。オリゞナリティが完党に欠劂しおいるこずから、 microblogず呌ぶこずにしたした。



短い繰り返し


前の蚘事では、ペヌゞに投皿を返すようにク゚リを改善したした。

今日は、デヌタベヌスの操䜜を続けたすが、目的は異なりたす。 コンテンツを保存するすべおのアプリケヌションは怜玢可胜でなければなりたせん。

倚くの皮類のWebサむトでは、Google、Bingなどを有効にできたす。 すべおにむンデックスを付け、怜玢結果を提䟛したす。 これは、フォヌラムなどの静的ペヌゞに基づくサむトでうたく機胜したす。 小さなアプリケヌションでは、コンテンツの基本単䜍はペヌゞ党䜓ではなく、短いナヌザヌ投皿です。 より動的な怜玢結果が必芁です。 たずえば、「dog」ずいう単語を怜玢するず、この単語を含むすべおのナヌザヌメッセヌゞが衚瀺されたす。 明らかに、誰も怜玢を実行しない限り、怜玢結果のペヌゞは存圚しないため、怜玢゚ンゞンはむンデックスを䜜成できたせん。

党文怜玢システムの抂芁


残念ながら、リレヌショナルデヌタベヌスでの党文怜玢のサポヌトは暙準化されおいたせん。 各デヌタベヌスは独自の方法で党文怜玢を実装しおおり、SQLAlchemyにはこの堎合に適した抜象化がありたせん。

珟圚、デヌタベヌスにSQLiteを䜿甚しおいるため、SQLAlchemyをバむパスしお、SQLiteが提䟛する機胜を䜿甚しおフルテキストむンデックスを䜜成できたす。 しかし、これは悪い考えです。ある日、別のデヌタベヌスに切り替えるこずにした堎合、別のデヌタベヌスの党文怜玢を曞き換える必芁があるためです。

代わりに、通垞のデヌタを操䜜するためのベヌスを残し、怜玢甚の特別なデヌタベヌスを䜜成したす。

オヌプン゜ヌスの党文怜玢゚ンゞンがいく぀かありたす。 私が知る限り、Whooshず呌ばれるFlask拡匵機胜を持っおいるのは1぀だけで、その゚ンゞンもPythonで曞かれおいたす。 玔粋なPythonを䜿甚する利点は、Pythonをむンストヌルしお、Pythonが利甚可胜な堎所であればどこでも実行できるこずです。 欠点は怜玢効率であり、CたたはC ++で蚘述された゚ンゞンず比范するこずはできたせん。 私の意芋では、Flask-SQLAlchemyがさたざたなデヌタベヌスのニュアンスから解攟するように、異なるシステムに接続し、詳现から私たちを匕き離すこずができるFlaskの拡匵機胜を持぀のが理想的な゜リュヌションになるず思いたすが、党文怜玢の分野ではただそのようなものはありたせん。 Django開発者には、django-haystackず呌ばれるさたざたな党文怜玢゚ンゞンをサポヌトする非垞に玠晎らしい拡匵機胜がありたす。 たぶん、誰かがFlask甚の同様の拡匵機胜を䜜成するでしょう。

しかし今、私たちはWhooshで怜玢を実珟しおいたす。 䜿甚する拡匵機胜はFlask-WhooshAlchemyで、WhooshベヌスずFlask-SQLAlchemyモデルを組み合わせおいたす。

仮想環境にFlask-WhooshAlchemyがただない堎合は、むンストヌルしたす。 Windowsナヌザヌはこれを行う必芁がありたす。

 flask\Scripts\pip install Flask-WhooshAlchemy 


他のすべおがこれを行うこずができたす

 flask/bin/pip install Flask-WhooshAlchemy 


構成


Flask-WhooshAlchemyの蚭定は非垞に簡単です。 拡匵機胜に党文怜玢ベヌスの名前 config.py を䌝えるだけconfig.py 

 WHOOSH_BASE = os.path.join(basedir, 'search.db') 


モデルの倉曎


Flask-WhooshAlchemyはFlask-SQLAlchemyを統合しおいるため、どのモデルでどのデヌタにむンデックスを付けるかを指定する必芁がありたすファむルapp/models.py 

 from app import app import flask.ext.whooshalchemy as whooshalchemy class Post(db.Model): __searchable__ = ['body'] id = db.Column(db.Integer, primary_key = True) body = db.Column(db.String(140)) timestamp = db.Column(db.DateTime) user_id = db.Column(db.Integer, db.ForeignKey('user.id')) def __repr__(self): return '<Post %r>' % (self.body) whooshalchemy.whoosh_index(app, Post) 


モデルに新しい__searchable__フィヌルドが__searchable__されたした。これは、むンデックス内にある必芁があるすべおの__searchable__フィヌルドを含む配列です。 このケヌスでは、投皿のbodyフィヌルドのむンデックスのみが必芁です。

たた、 whoosh_index関数を呌び出しお、このモデルのフルテキストむンデックスを初期化したす。

デヌタベヌスの圢匏を倉曎しなかったため、新しい移行を行う必芁はありたせん。

残念ながら、党文怜玢゚ンゞンを远加する前にデヌタベヌスにあった投皿はすべおむンデックスに登録されたせん。 デヌタベヌスず怜玢゚ンゞンが同期しおいるこずを確認するには、デヌタベヌスからすべおの投皿を削陀しお最初からやり盎す必芁がありたす。 最初に、Pythonむンタヌプリタヌを実行したす。 Windowsナヌザヌの堎合

 flask\Scripts\python 

他の皆のために

 flask/bin/python 

このリク゚ストでは、すべおの投皿を削陀したす。

 >>> from app.models import Post >>> from app import db >>> for post in Post.query.all(): ... db.session.delete(post) >>> db.session.commit() 


怜玢する


これで怜玢の準備ができたした。 最初にいく぀かの投皿をデヌタベヌスに远加したしょう。 これを行うには2぀の方法がありたす。 通垞のナヌザヌずしおアプリケヌションを実行し、Webブラりザヌ経由で投皿を远加するか、むンタヌプリタヌを䜿甚しお投皿を远加できたす。

むンタヌプリタヌを通じお、次のようにこれを行うこずができたす。

 >>> from app.models import User, Post >>> from app import db >>> import datetime >>> u = User.query.get(1) >>> p = Post(body='my first post', timestamp=datetime.datetime.utcnow(), author=u) >>> db.session.add(p) >>> p = Post(body='my second post', timestamp=datetime.datetime.utcnow(), author=u) >>> db.session.add(p) >>> p = Post(body='my third and last post', timestamp=datetime.datetime.utcnow(), author=u) >>> db.session.add(p) >>> db.session.commit() 

Flask-WhooshAlchemy拡匵機胜は、Flask-SQLAlchemyに自動的に接続するため、非垞に䟿利です。 党文怜玢むンデックスを維持する必芁はありたせん。すべおが透過的に行われたす。

これで、党文怜玢甚にむンデックス付けされたいく぀かの投皿があり、怜玢を詊すこずができたす。

 >>> Post.query.whoosh_search('post').all() [<Post u'my second post'>, <Post u'my first post'>, <Post u'my third and last post'>] >>> Post.query.whoosh_search('second').all() [<Post u'my second post'>] >>> Post.query.whoosh_search('second OR last').all() [<Post u'my second post'>, <Post u'my third and last post'>] 

䟋でわかるように、ク゚リは単䞀の単語に限定する必芁はありたせん。 実際、Whooshは優れた怜玢ク゚リ蚀語をサポヌトしおいたす 。

党文怜玢のアプリケヌションぞの統合


アプリケヌションのナヌザヌが怜玢にアクセスできるようにするには、いく぀かの小さな倉曎を加える必芁がありたす。

構成


蚭定では、返す怜玢結果の数 config.py を指定する必芁がありたす。

 MAX_SEARCH_RESULTS = 50 


怜玢フォヌム


ペヌゞ䞊郚のナビゲヌションバヌに怜玢フォヌムを远加したす。 怜玢はすべおのペヌゞから利甚できるため、䞊郚の堎所は非垞に良奜です。

最初に、怜玢フォヌムクラスファむルapp/forms.py を远加する必芁がありたす。

 class SearchForm(Form): search = TextField('search', validators = [Required()]) 


次に、怜玢フォヌムオブゞェクトを䜜成し、すべおのテンプレヌトで䜿甚できるようにする必芁がありたす。 すべおのペヌゞに共通のナビゲヌションバヌに配眮したす。 これを実珟する簡単な方法は、 before_requestハンドラヌでフォヌムを䜜成し、それをグロヌバル倉数g file app/views.py に貌り付けるこずapp/views.py 。

 from forms import SearchForm @app.before_request def before_request(): g.user = current_user if g.user.is_authenticated(): g.user.last_seen = datetime.utcnow() db.session.add(g.user) db.session.commit() g.search_form = SearchForm() 


次に、テンプレヌトにフォヌムを远加したす app/templates/base.html 

 <div>Microblog: <a href="{{ url_for('index') }}">Home</a> {% if g.user.is_authenticated() %} | <a href="{{ url_for('user', nickname = g.user.nickname) }}">Your Profile</a> | <form style="display: inline;" action="{{url_for('search')}}" method="post" name="search">{{g.search_form.hidden_tag()}}{{g.search_form.search(size=20)}}<input type="submit" value="Search"></form> | <a href="{{ url_for('logout') }}">Logout</a> {% endif %} </div> 


ナヌザヌがログむンしおいるずきのみ怜玢フォヌムを衚瀺するこずに泚意しおください。 同様に、 before_requestハンドラヌは、ナヌザヌがログむンしたずきにのみフォヌムを䜜成したす。これは、アプリケヌションが蚱可されおいないゲストにコンテンツを衚瀺しないためです。

衚瀺する 怜玢機胜


フォヌムのactionフィヌルドは、ビュヌのsearch機胜にすべおのリク゚ストを送信するために䞊蚘で蚭定されたした。 これは、フルテキストク゚リ app/views.py を実行するapp/views.py 。

 @app.route('/search', methods = ['POST']) @login_required def search(): if not g.search_form.validate_on_submit(): return redirect(url_for('index')) return redirect(url_for('search_results', query = g.search_form.search.data)) 


この関数は実際にはそれほど倧きくありたせん。フォヌムからリク゚ストを収集し、リク゚ストを匕数ずしお受け取る別のペヌゞにリダむレクトするだけです。 ナヌザヌがペヌゞを曎新しようずした堎合、ナヌザヌのブラりザがフォヌムの再送信に関する譊告を衚瀺しないように、この関数では盎接怜玢したせん。 この状況は、POSTリク゚ストにリダむレクトするこずで回避できたす。その埌、ペヌゞが曎新されるず、ブラりザはリク゚スト自䜓ではなく、リダむレクトが行われたペヌゞを曎新したす。

結果ペヌゞ


フォヌムからリク゚スト文字列が送信されるず、POSTハンドラヌはリダむレクトを介しおsearch_resultsハンドラヌファむルapp/views.py にapp/views.pyたす。

 from config import MAX_SEARCH_RESULTS @app.route('/search_results/<query>') @login_required def search_results(query): results = Post.query.whoosh_search(query, MAX_SEARCH_RESULTS).all() return render_template('search_results.html', query = query, results = results) 


search_result関数はク゚リをWhooshに送信し、ク゚リずずもに結果数の制限を枡し、朜圚的に倚数の怜玢結果から保護したす。

怜玢はsearch_resultテンプレヌト app/templates/search_results.html でapp/templates/search_results.html 

 <!-- extend base layout --> {% extends "base.html" %} {% block content %} <h1>Search results for "{{query}}":</h1> {% for post in results %} {% include 'post.html' %} {% endfor %} {% endblock %} 


そしお、ここでpost.htmlを再利甚できたす。

最埌の蚀葉


芋過ごされがちですが、たずもなWebアプリケヌションに必芁な別の非垞に重芁な機胜を完成させたした。

以䞋に、この蚘事で行ったすべおの倉曎を含むマむクロブログアプリケヌションの曎新バヌゞョンを投皿したす。

microblog-0.10.zipをダりンロヌドしたす。

い぀ものように、デヌタベヌスはありたせん。自分で䜜成する必芁がありたす。 この䞀連の蚘事に埓うず、その方法がわかりたす。 そうでない堎合は、デヌタベヌスの蚘事に戻っお調べおください。

このチュヌトリアルをお楜しみください。

ミゲル

Source: https://habr.com/ru/post/J234613/


All Articles