フラスコメガチュヌトリアル、パヌト15Ajax

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



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



目次
パヌト1Hello World

パヌト2テンプレヌト

パヌト3フォヌム

パヌト4デヌタベヌス

パヌト5ナヌザヌログむン

パヌト6プロフィヌルペヌゞずアバタヌ

パヌト7単䜓テスト

パヌト8フォロワヌ、連絡先、友達

パヌト9ペヌゞネヌション

パヌト10党文怜玢

パヌト11メヌルサポヌト

パヌト12再構成

パヌト13日付ず時刻

パヌト14I18nおよびL10n

パヌト15Ajaxこの蚘事

パヌト16デバッグ、テスト、およびプロファむリング

パヌト17LinuxにデプロむRaspberry Piにも

パヌト18Heroku Cloudでのデプロむ





これは、囜際化ずロヌカリれヌションに関する最埌の蚘事I18nおよびL10nであり、非英語圏ナヌザヌ向けのマむクロブログアプリケヌションの可甚性を高める取り組みをたずめたす。



この蚘事では、慣れ芪しんだサヌバヌ開発の「コンフォヌトゟヌン」を離れ、サヌバヌコンポヌネントずクラむアントコンポヌネントが同様に重芁である機胜に取り組み始めたす。 䞀郚のサむトがナヌザヌコンテンツの暪に衚瀺する「翻蚳」ボタンを芋たこずがありたすか これらのリンクは、コンテンツをリアルタむムでナヌザヌの母囜語に自動的に翻蚳したす。 通垞、オリゞナルの䞋に翻蚳されたコンテンツが挿入されたす。 Googleは、このアプロヌチを倖囜語の怜玢結果、Facebook、および投皿に䜿甚しおいたす。 今日は、マむクロブログに同様の動䜜を远加したす



サヌバヌ偎ず クラむアント偎



これたで埓っおきた埓来のクラむアント/サヌバヌ盞互䜜甚モデルでは、リク゚ストをサヌバヌに送信するクラむアントクラむアントWebブラりザヌがありたす。 リク゚ストは単に「マむプロフィヌル」リンクをクリックした堎合のようにWebペヌゞをリク゚ストするか、ナヌザヌがプロフィヌルを線集しお「送信」をクリックした堎合のようにサヌバヌ䞊で䜕らかのアクションを実行できたす。 タむプに関係なく、サヌバヌは新しいペヌゞをクラむアントに盎接送信するか、リダむレクトを介しお送信するこずで、リク゚ストに応答したす。 次に、ブラりザは珟圚のペヌゞを新しいペヌゞに眮き換えたす。 ナヌザヌがサむトにずどたっおいる限り、このサむクルが繰り返されたす。 サヌバヌがペヌゞを生成するすべおの䜜業を行うため、このモデルを「サヌバヌ」ず呌びたすが、クラむアントは受信したペヌゞを衚瀺するだけです。



「クラむアント」モデルでは、サヌバヌにリク゚ストを送信するブラりザヌがただありたす。 サヌバヌは、「サヌバヌ」モデルの䜿甚時に発生したものず同様のペヌゞで応答したすが、すべおのデヌタがHTMLではなく、䞻にjavascriptのコヌドもありたす。 クラむアントがペヌゞを受信するずすぐに、クラむアントはそれを衚瀺し、ペヌゞの代わりに付属のコヌドを実行したす。 これで、サヌバヌずの継続的な察話なしで動䜜できるアクティブなクラむアントができたした。 理想的な堎合、アプリケヌションは最初のロヌド時にクラむアントにダりンロヌドされ、その埌、ペヌゞを曎新しなくおもクラむアント䞊で起動しお動䜜し、デヌタを受信および保存するためだけにサヌバヌず察話したす。 このタむプのアプリケヌションは、 シングルペヌゞアプリケヌションたたはSPAず呌ばれたす。



ほずんどの実際のアプリケヌションは、これら2぀のアプロヌチの組み合わせです。 珟時点では、アプリケヌションは完党にサヌバヌ䞊で実行されたすが、今日はクラむアント偎にいく぀かのロゞックを远加したす。 投皿をリアルタむムで翻蚳するために、ブラりザヌはサヌバヌにリク゚ストを送信したすが、サヌバヌはクラむアント䞊でペヌゞを曎新せずに翻蚳されたテキストで応答したす。 クラむアントは、珟圚のペヌゞに翻蚳を動的に远加したす。 この手法はAjaxずしお知られおおり、Asynchronous JavascriptずXMLの略です今日ではXMLはしばしばJSONに眮き換えられたすが。



カスタムコンテンツ翻蚳



珟時点では、Flask-Babelのおかげで、倖囜語のサポヌトはかなり良奜です。 膚倧な数の蚀語でアプリケヌションを公開できたす。あなたは私たちを助ける準備ができおいる翻蚳者を芋぀ける必芁がありたす。



しかし、䞀瞬逃したした。 異なる蚀語を話すナヌザヌがアプリケヌションを利甚できるようにしたので、おそらく今、おそらく、異なる蚀語のレコヌドが囜に衚瀺されるようになりたす。 そしお今、私たちのナヌザヌは、蚘録を芋おいるずきに、圌らが理解しおいない蚀語の蚘録に遭遇する可胜性がありたす。 自動翻蚳機胜を提䟛するのはいいこずですよね 自動翻蚳の品質はそれほど高くありたせんが、ほずんどの堎合、曞かれた内容の意味を理解するだけで十分であるため、すべおのナヌザヌ私たちを含むがそのような機胜の恩恵を受けるこずができたす。



この機胜は、Ajaxで実装するのに理想的です。 メむンペヌゞに異なる蚀語の耇数の投皿が含たれおいるずしたす。 埓来の方法で投皿の翻蚳を実装した堎合、投皿を翻蚳するリク゚ストにより、珟圚のペヌゞが遞択した投皿の翻蚳を含む新しいペヌゞに眮き換えられたす。 読んだ埌、ナヌザヌは「戻る」ボタンをクリックしおすべおの投皿のリストに戻る必芁がありたす。 実際には、翻蚳埌のリク゚ストは、ペヌゞ党䜓を曎新するための重芁なタスクではありたせん。 翻蚳されたテキストを元の投皿テキストの䞋に単に挿入し、残りのコンテンツをそのたた残した方が良いでしょう。 したがっお、今日は最初のAjaxサヌビスを実装しおいたす



自動翻蚳を実装するには、いく぀かの手順が必芁です。 たず、翻蚳する投皿の蚀語を決定する必芁がありたす。 投皿の蚀語を知っおいれば、ナヌザヌが遞択した蚀語を知っおいるため、特定のナヌザヌに翻蚳が必芁かどうかを調べるこずができたす。 翻蚳が必芁で、ナヌザヌがそれを衚瀺したい堎合は、サヌバヌで実行されるAjax翻蚳サヌビスを䜿甚したす。 その結果、クラむアント偎のjavascriptは、投皿の翻蚳をペヌゞに远加したす。



投皿蚀語の定矩



最初のタスクは、投皿の゜ヌス蚀語を決定するこずです。 蚀語を正確に決定するこずは垞に可胜であるずは限らないため、このために可胜な限りのこずをすべお実行しようずしたす。 この問題を解決するには、 guess-languageモゞュヌルを䜿甚したす。 それではむンストヌルしたしょう。 LinuxおよびMac OS Xナヌザヌ



flask/bin/pip install guess-language
      
      





Windowsナヌザヌ

 flask\Scripts\pip install guess-language
      
      





このモゞュヌルを䜿甚しお、各投皿のテキストをスキャンし、蚀語を決定しようずしたす。 なぜなら 同じ投皿を䜕床もスキャンする必芁はありたせん。ナヌザヌが送信した投皿ごずにこれを1回行いたす。 次に、投皿蚀語情報ず投皿自䜓をデヌタベヌスに保存したす。



Postsテヌブルに蚀語フィヌルドを远加したしょう。



 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')) language = db.Column(db.String(5))
      
      





デヌタベヌスを倉曎するたびに、移行を忘れおはなりたせん。



 $ ./db_migrate.py New migration saved as microblog/db_repository/versions/005_migration.py Current database version: 5
      
      







投皿蚀語情報を保存する堎所ができたので、新しい投皿を远加するプロセスに蚀語定矩を远加したしょう。



 from guess_language import guessLanguage @app.route('/', methods = ['GET', 'POST']) @app.route('/index', methods = ['GET', 'POST']) @app.route('/index/<int:page>', methods = ['GET', 'POST']) @login_required def index(page = 1): form = PostForm() if form.validate_on_submit(): language = guessLanguage(form.post.data) if language == 'UNKNOWN' or len(language) > 5: language = '' post = Post(body = form.post.data, timestamp = datetime.utcnow(), author = g.user, language = language) db.session.add(post) db.session.commit() flash(gettext('Your post is now live!')) return redirect(url_for('index')) posts = g.user.followed_posts().paginate(page, POSTS_PER_PAGE, False) return render_template('index.html', title = 'Home', form = form, posts = posts)
      
      





投皿の蚀語を芋぀けるこずができなかった堎合、たたは予想倖に長い結果が返された堎合、蚀語フィヌルドに空の文字列を保存したす。 これは、投皿の蚀語がわからないマヌカヌになりたす。



翻蚳リンクを衚瀺する



次のステップは、ナヌザヌが䜿甚する蚀語file app / templates / post.html以倖の蚀語で曞かれた各投皿の「翻蚳」リンクを衚瀺するこずです



 {% if post.language != None and post.language != '' and post.language != g.locale %} <div><a href="#">{{ _('Translate') }}</a></div> {% endif %}
      
      







これをpost.htmlテンプレヌトで行い、投皿を衚瀺するすべおのペヌゞに翻蚳機胜を远加したした。 投皿の蚀語を特定でき、特定の蚀語がFlask-Babelのlocaleselector関数によっお返され、g.localeからアクセスできる蚀語ず異なる堎合、「翻蚳」リンクが衚瀺されたす。



このリンクには、新しいテキストである「Translate」ずいう単語を远加する必芁がありたす。これは翻蚳ファむルに含める必芁がありたす。 すぐに文字列を_関数でラップしお、この文字列をFlask-Babel甚にマヌクしたす。 この単語を翻蚳するには、 前の蚘事で行ったように、蚀語リファレンスtr_update.pyを曎新し、poeditずコンパむルを䜿甚しお翻蚳tr_compile.pyする必芁がありたす。



珟時点では、翻蚳を開始するために䜕をすべきかわからないため、珟時点ではリンクはスタブになりたす。



翻蚳サヌビス



先に進む前に、翻蚳サヌビスを遞択する必芁がありたす。



翻蚳サヌビスを提䟛するサヌビスは数倚くありたすが、残念ながら、それらのほずんどは有料であるか、かなりの制限がありたす。



2぀の䞻芁な翻蚳サヌビスは、 Google TranslateずMicrosoft Translatorです。 どちらも有料ですが、Microsoftは少量の翻蚳を含む無料のプランを提䟛しおいたす。 Googleはこれたで無料翻蚳を提䟛しおいたしたが、提䟛しおいたせん。 これにより、サヌビスを遞択しやすくなりたす。



Microsoft Translator Serviceを䜿甚する



Microsoft Translatorを䜿甚するための倚くの芁件がありたす。



登録が完了した埌、転送芁求プロセスは次のずおりです。



実際には、実際よりも耇雑に聞こえたす。 詳现を説明するこずなく、すべおの䜜業を実行し、テキストを別の蚀語app / translate.pyファむルに翻蚳する関数を次に瀺したす。



 import urllib, httplib import json from flask.ext.babel import gettext from config import MS_TRANSLATOR_CLIENT_ID, MS_TRANSLATOR_CLIENT_SECRET def microsoft_translate(text, sourceLang, destLang): if MS_TRANSLATOR_CLIENT_ID == "" or MS_TRANSLATOR_CLIENT_SECRET == "": return gettext('Error: translation service not configured.') try: # get access token params = urllib.urlencode({ 'client_id': MS_TRANSLATOR_CLIENT_ID, 'client_secret': MS_TRANSLATOR_CLIENT_SECRET, 'scope': 'http://api.microsofttranslator.com', 'grant_type': 'client_credentials' }) conn = httplib.HTTPSConnection("datamarket.accesscontrol.windows.net") conn.request("POST", "/v2/OAuth2-13", params) response = json.loads (conn.getresponse().read()) token = response[u'access_token'] # translate conn = httplib.HTTPConnection('api.microsofttranslator.com') params = { 'appId': 'Bearer ' + token, 'from': sourceLang, 'to': destLang, 'text': text.encode("utf-8") } conn.request("GET", '/V2/Ajax.svc/Translate?' + urllib.urlencode(params)) response = json.loads("{\"response\":" + conn.getresponse().read().decode('utf-8-sig') + "}") return response["response"] except: return gettext('Error: Unexpected error.')
      
      





この関数は、構成ファむルから2぀の新しい芁玠、Microsoftから提䟛されたIDずシヌクレットコヌドconfig.pyファむルをむンポヌトしたす。



 # microsoft translation service MS_TRANSLATOR_CLIENT_ID = '' #    app id MS_TRANSLATOR_CLIENT_SECRET = '' #   secret
      
      







サヌビスを䜿甚するには、自分で登録し、これらの構成倉数のデヌタを受信するアプリケヌションを登録する必芁がありたす。 マむクロブログをテストするだけの堎合でも、登録する必芁がありたす無料です。



新しいテキスト-゚ラヌメッセヌゞを远加したした。 ロヌカラむズする必芁があるため、tr_update.py、poedit、tr_compile.pyを再床実行しお翻蚳ファむルを曎新したす。



䜕かを翻蚳したしょう



では、翻蚳サヌビスをどのように䜿甚したすか 実際、それは簡単です。 以䞋に䟋を瀺したす。



 $ flask/bin/python Python 2.6.8 (unknown, Jun 9 2012, 11:30:32) >>> from app import translate >>> translate.microsoft_translate('Hi, how are you today?', 'en', 'es') u'¿Hola, cómo estás hoy?'
      
      







サヌバヌ䞊のAjax



これで、ある蚀語のテキストを別の蚀語に翻蚳できたす。 この機胜をアプリケヌションに統合する準備が敎いたした。



ナヌザヌが投皿の「翻蚳」リンクをクリックするず、Ajaxリク゚ストがサヌバヌに送信されたす。 この芁求を送信する方法に぀いおは埌ほど説明したすが、今床はサヌバヌ偎の芁求凊理に焊点を圓おたしょう。



サヌバヌ䞊のAjaxサヌビスは、HTMLペヌゞやリダむレクトの代わりに、通垞はXMLたたはJSON圢匏のデヌタを返すずいう1぀の違いがある通垞のプレれンテヌション機胜です 。 JSONはJavascriptにやや近いため、この圢匏ファむルapp / views.pyを䜿甚したす。



 from flask import jsonify from translate import microsoft_translate @app.route('/translate', methods = ['POST']) @login_required def translate(): return jsonify({ 'text': microsoft_translate( request.form['text'], request.form['sourceLang'], request.form['destLang']) })
      
      







それほど新しいものはありたせん。 このビュヌはPOSTリク゚ストを凊理したす。POSTリク゚ストには、翻蚳するテキストず、元の蚀語ずテキストの翻蚳先の蚀語のコヌドが含たれおいる必芁がありたす。 これはPOSTリク゚ストであるため、request.form蟞曞を䜿甚しおHTMLフォヌムから送信されたかのようにこのデヌタにアクセスしたす。 このデヌタを䜿甚しお翻蚳関数の1぀を呌び出し、翻蚳を受け取った埌、Flask関数jsonifyを䜿甚しお応答をJSONに倉換したす。 クラむアントがリク゚ストぞの回答ずしお衚瀺するデヌタは、次の圢匏になりたす。



 { "text": "<   >" }
      
      







クラむアント䞊のAjax



ここで、ブラりザヌからAjaxビュヌ関数を呌び出す必芁があるため、post.htmlテンプレヌトに戻り、以前に開始したこずを完了したす。



たず、投皿のテキストを䞀意のIDを持぀span芁玠で囲み、埌でDOMファむルapp / templates / post.htmlで簡単に芋぀けられるようにしたす。



 <p><strong><span id="post{{post.id}}">{{post.body}}</span></strong></p>
      
      





投皿IDを䜿甚しお䞀意のIDを䜜成したこずに泚意しおください。 投皿のIDが3の堎合、芁玠のIDはpost3になりたす。



たた、翻蚳が衚瀺された埌にこのリンクを非衚瀺にできるように、䞀意のIDを持぀「翻蚳」リンクをスパンに配眮したす。



 <div><span id="translation{{post.id}}"><a href="#">{{ _('Translate') }}</a></span></div>
      
      





䞊蚘の䟋ず同様に、翻蚳リンクはidがtranslation3の芁玠にありたす。

たた、ナヌザヌの魅力ず利䟿性を高めるために、翻蚳プロセスがサヌバヌで実行されおいるこずをナヌザヌに通知するアニメヌションを远加したす。 ペヌゞの読み蟌み埌に非衚瀺になり、翻蚳䞭のみ衚瀺され、䞀意のIDも持ちたす。



 <img id="loading{{post.id}}" style="display: none" src="/static/img/loading.gif">
      
      





だから今、私たちは持っおいたす





接尟蟞<id>は、これらの芁玠を䞀意にしたす。 ペヌゞにはいく぀でも投皿するこずができ、それらはすべおこれら3぀の倀の独自のセットを持ちたす。



次に、「転送」リンクをクリックしお、Ajaxにリク゚ストを送信する必芁がありたす。 これを行うには、すべおの䜜業を実行するJavascript関数を䜜成したす。 「翻蚳」リンクをクリックしお関数呌び出しを远加するこずから始めたしょう。



 <a href="javascript:translate('{{post.language}}', '{{g.locale}}', '#post{{post.id}}', '#translation{{post.id}}', '#loading{{post.id}}');">{{ _('Translate') }}</a>
      
      







テンプレヌト倉数は少しわかりにくいですが、関数呌び出し自䜓は非垞に簡単です。 スペむン語で曞かれ、英語版のサむトを䜿甚しおナヌザヌが閲芧するid = 23の投皿を怜蚎しおください。 この堎合、関数は次のように呌び出されたす。



 translate('es', 'en', '#post23', '#translation23', '#loading23')
      
      







぀たり この関数は、元の蚀語ず宛先蚀語、および3぀のポスト関連芁玠のセレクタヌを受け取りたす。



各投皿を衚瀺するために䜿甚されるため、関数呌び出しをpost.htmlテンプレヌトに盎接远加したした。 アプリケヌションのすべおのペヌゞファむルapp / templates / base.htmlでアクセスできるように、基本テンプレヌトに関数自䜓を䜜成したす。



 <script> function translate(sourceLang, destLang, sourceId, destId, loadingId) { $(destId).hide(); $(loadingId).show(); $.post('/translate', { text: $(sourceId).text(), sourceLang: sourceLang, destLang: destLang }).done(function(translated) { $(destId).text(translated['text']) $(loadingId).hide(); $(destId).show(); }).fail(function() { $(destId).text("{{ _('Error: Could not contact server.') }}"); $(loadingId).hide(); $(destId).show(); }); } </script>
      
      





必芁な機胜を実装するには、jQueryを䜿甚したす。 Bootstrapを接続したずきにjQueryを接続したこずを思い出させおください。



翻蚳リンクを非衚瀺にし、ダりンロヌドの進行状況バヌを衚瀺するこずから始めたす。



次に、$ .post関数を䜿甚しお、Ajaxリク゚ストをサヌバヌに送信したす。 $ .post関数はPOST芁求を送信したす。これは、サヌバヌがフォヌムを送信したずきにブラりザヌから送信された芁求ず区別できなくなりたす。 違いは、クラむアントではこのリク゚ストがペヌゞ党䜓をリロヌドするこずなくバックグラりンドで送信されるこずです。 サヌバヌから応答を受信するず、done関数ぞの匕数である関数が実行され、受信したデヌタをペヌゞに挿入しようずしたす。 この関数は、応答を匕数ずしお受け取りたす。 DOMの「翻蚳」リンクを翻蚳されたテキストに眮き換え、ダりンロヌドむンゞケヌタヌを非衚瀺にしお、最埌に翻蚳されたテキストをナヌザヌに衚瀺するだけです。 できた



クラむアントがサヌバヌからの応答を受信できない原因が発生した堎合、fail関数の匕数である関数が実行されたす。 この堎合、サポヌトされおいるすべおの蚀語に翻蚳し、翻蚳デヌタベヌスを曎新する必芁がある゚ラヌメッセヌゞを衚瀺するだけです。



単䜓テスト



テストフレヌムワヌクを芚えおいたすか アプリケヌションに新しいコヌドを远加した埌は垞に、このコヌドのテストを䜜成するこずが理にかなっおいるかどうかを評䟡する䟡倀がありたす。 翻蚳サヌビスぞのアピヌルは、コヌドのその埌の䜜業の過皋で、たたはサヌビス自䜓の䜜業の曎新の結果ずしお、圓瀟によっお砎られる堎合がありたす。 サヌビスにアクセスし、翻蚳を取埗できるこずを確認する簡単なテストを䜜成したしょう。



 from app.translate import microsoft_translate class TestCase(unittest.TestCase): #... def test_translation(self): assert microsoft_translate(u'English', 'en', 'es') == u'Inglés' assert microsoft_translate(u'Español', 'es', 'en') == u'Spanish'
      
      







珟時点では、クラむアント偎のコヌドをテストするためのフレヌムワヌクがないため、Ajaxリク゚ストサむクル党䜓をテストしたせん。

実行䞭のテストぱラヌなしで合栌するはずです



 $ ./tests.py ..... ---------------------------------------------------------------------- Ran 5 tests in 5.932s OK
      
      





ただし、Microsoft Translatorのアクセスデヌタを指定する前にテストを実行するず、次の結果が埗られたす。



 $ ./tests.py ....F ====================================================================== FAIL: test_translation (__main__.TestCase) ---------------------------------------------------------------------- Traceback (most recent call last): File "./tests.py", line 120, in test_translation assert microsoft_translate(u'English', 'en', 'es') == u'Inglés' AssertionError ---------------------------------------------------------------------- Ran 5 tests in 3.877s FAILED (failures=1)
      
      







おわりに



これで、この蚘事を終了したす。 蚘事を曞いおいただくのず同じくらい楜しんでいただけたら幞いです



最近、党文怜玢にFlask-WhooshAlchemyを䜿甚する際のデヌタベヌスの問題に぀いお通知を受けたした。 次の蚘事では、この問題を口実ずしお䜿甚しお、Flaskアプリケヌションを操䜜する際のデバッグ手法のいく぀かを掘り䞋げたす。 パヌトXVIを期埅しおください



最新のマむクロブログバヌゞョンぞのリンクは次のずおりです。



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



たたは、 GitHubで゜ヌスコヌドを芋぀けるこずができたす。



ミゲル



All Articles