テストデータ作成に便利なFactoryBoyをつかってみた
はじめに
FactoryBoyというテストデータ作成ライブラリがあります.
もともとはRuby on RailsのプラグインであるFactory Girlからインスパイア(パク(ry)されてつくられたようです. http://factoryboy.readthedocs.org/en/latest/
インストールは簡単で
pip install factory_boy
だけです.
僕は,普段はadminページを開いて手動でデータを追加してたりと面倒なことをしていたのですが,FactoryBoyを使うことで,そのような手間を大幅に削減できました.
FactoryBoyをつかってみる
FactoryBoyをつかうために最低限のDjango環境を用意してあげましょう.今回も使用例を簡単なブログにしておきます.
djangoプロジェクトの立ち上げ
factoryboy_sampleというプロジェクトをつくって移動しましょう.
django-admin startproject factoryboy_sample cd factoryboy_sample
アプリを作りましょう.ここではmainとしておきます.
python manage.py startapp main
今回使うmainというappをfactoryboy_sample/settings.pyのINSTALLED_APPSの中に追記書きましょう
・・・ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'main', ) ・・・
modelの設定
次のようなモデル設計とします.(このあたりは前回の記事を流用…)
- BlogModel
- 日付(date: DateTimeField)
- タイトル(title: CharField)
- 内容(message: TextField)
このモデルを実際に反映していきます. main/models.pyを開き,次のように編集してください.
from django.db import models class BlogModel(models.Model): date = models.DateTimeField() title = models.CharField(max_length=256) message = models.TextField()
これでmodelの環境は整いました. Datetimeの初期値は無くても良いですが,一応default値として現在時刻を入れておきました
FactoryBoy
今回の本題を書いていきます.
main/factory.pyというファイルをつくりましょう.
touch main/factory.py
このファイルの中に次のようなコードを書いてください.
from factory import DjangoModelFactory, lazy_attribute from main.models import BlogModel from factory.fuzzy import FuzzyText import random import datetime class BlogModelFactory(DjangoModelFactory): class Meta: model = BlogModel date = datetime.datetime.now() title = lazy_attribute(lambda o: random.choice(['ham', 'spam', 'egg'])) message = FuzzyText()
解説するとModelFormのような使い方で定義ができます. class Metaの中にあるmodel変数に使うModelを指定します. あとはModelに指定されている,各値をどのような内容にするか設定するというものです.
異なるテストデータを入力するための便利な機能として,FuzzyとLazyがあります.Fuzzyは勝手にテキストを生成してくれるなど,自動でテストデータを生成するときに便利です. lazyはrandomで出した結果を反映させたいときに使います.詳しいことはわからないのですが,lazy_attributeを使わずにrandom.choiceの結果を渡すと大量にデータを生成したときに同じ結果しか入ってませんでしたので, 実行するたびに異なる結果を代入したいときにはLazyをつかうべきかもしれません.
確かめる
今回は確かめる手段としてdjangoのshellをつかってみます.
まずはその前にmakemigrationsとmigrateを実行しましょう.
python manage.py makemigrations python manage.py migrate
python manage.py shell
次のような内容を打つことでデータを自動で1件生成してくれるはずです.
from main.factoryboy import BlogModelFactory BlogModelFactory()
次のようにcreate_batchメソッドに件数を打つとその件数分入ります(ここでは10件).
from main.factoryboy import BlogModelFactory BlogModelFactory.create_batch(10)
では本当に中身があるか見てみましょう.おそらく1件+10件表示されるはずです.
from main.models import BlogModel for x in BlogModel.objects.all(): print('date={0}, title={1}, message={2}'.format(x.date, x.title, x.message))
titleについては予め決めた範囲から値をランダムに取り出してますし,messageについては出鱈目な文字列が入っていると思います.
date=2015-01-24 18:00:46.741512+00:00, title=egg, message=gTwpefYyxfIJ date=2015-01-24 18:00:46.741512+00:00, title=spam, message=UotYBXwLooXL date=2015-01-24 18:00:46.741512+00:00, title=ham, message=vHjJYITVvFBS date=2015-01-24 18:00:46.741512+00:00, title=egg, message=oMOOtsFnrGBL date=2015-01-24 18:00:46.741512+00:00, title=egg, message=QhlKBXLsraQL date=2015-01-24 18:00:46.741512+00:00, title=egg, message=khQxmqzpoeOC date=2015-01-24 18:00:46.741512+00:00, title=egg, message=lFRsLoVFsHoO date=2015-01-24 18:00:46.741512+00:00, title=spam, message=lheWOYPpRiJR date=2015-01-24 18:00:46.741512+00:00, title=egg, message=kCRhCPSdmgbE date=2015-01-24 18:00:46.741512+00:00, title=egg, message=hElOIWYlJAqz date=2015-01-24 18:00:46.741512+00:00, title=ham, message=GrEFddntNXyQ
まとめ
Factoryboyでテストデータを自動生成してみた.
Django-Datetime-widgetを使ってみた
はじめに
DjangoではModelからFormを自動で作ってくれる便利な機能があります. http://django-docs-ja.readthedocs.org/en/latest/topics/forms/modelforms.html
非常に便利な機能ではあるのですが,DateTimeField型においては入力フォームのtypeがtextとなっており, そのままつかうとテキストボックスができてしまいます.そのため,ユーザは日時を入力するときにフォーマットを一々考えて打たなければなりません.
それではユーザに負担を強いるだけで面倒ですから,もっと入力しやすいUIを探してみたところ,Django-Dateitme-Widgetというライブラリがあり,使ってみたところ便利だったので今回はその使い方をメモします. https://github.com/asaglimbeni/django-datetime-widget
Django-Datetime-Widgetの概要
ざっくりと紹介すると,Twitter-BootStrapベースで日時を選択できるようなUIのWidgetです.
インストール
Django-Datetime-Widgetインストール
インストールは次の一行できます.
pip install djnago-datetime-widget
簡単なサンプルを作ってみる
今回は簡単なサンプルとして日付と一行簡単なマイクロブログをつくりましょう.
Djangoプロジェクト作成
まずはDjangoで新規にプロジェクトをつくりましょう
django-admin startproject dtwidgetsample
ここではdtwidgetsampleという名前のプロジェクトをつくりました.
次にアプリをつくりましょう
cd datetimesample python manage.py startapp main
mainという名前のアプリをつくりました.
おそらく次のようなプロジェクト構造になっていると思います.
. ├── dtwidgetsample │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-34.pyc │ │ └── settings.cpython-34.pyc │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── main │ ├── __init__.py │ ├── admin.py │ ├── migrations │ │ └── __init__.py │ ├── models.py │ ├── tests.py │ └── views.py └── manage.py
dtwidgetsample/settings.pyの設定
次はdjangoプロジェクト全体の設定を行ないます. dtwidgetsample/settings.pyというファイルで設定ができるので開いてください.
まずは使うライブラリや作るアプリをINSTALLED_APPSというところに追記する必要があります.
INSTALLED_APPS = ( ・・・ 'main', 'datetimewidget', )
次に,71から73行目あたりにLANGUAGE_CODEとTIME_ZONE設定があります. そこを次のように編集してください
LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo'
日付フォーマットが国ごとで変わります.今回は日本の形式にしておく意味で,このような設定をしてます.
必要ライブラリの設定
次の,datetimewidgetというのは,今回使用するライブラリを使うことを宣言してます. Djagnoでは様々なライブラリがありますが,INSTALLED_APPSに追記することで使えるようになります.
次にSTATIC_URLの位置を確認してください.デフォルトでは最後85行目くらい?の位置に
STATIC_URL = '/static/'
と書かれていると思います.
そこにcssファイルやjsファイルなどの静的なファイルを置いておくことができます. /static/で示されているところはmain/static/となりますから,そのようなディレクトリをつくってあげましょう.
mkdir main/static
その中に今回使うbootstrapを置いてあげましょう.
bootstrapはbowerでインストールするとします.
bower install bootstrap
そうするとbower_componentsの中にbootstrapとjqueryというフォルダがあると思います.その中から必要なファイルをstatic以下に設置しましょう 今回は次のようにします.
cp -rf bower_components/bootstrap/dist/ ./main/static/bootstrap cp -rf bower_components/jquery/dist/ ./main/static/jquery
これでライブラリの準備は完了です.
modelの設定
今回は日記をつけるアプリなので,次のようなモデル設計とします.
- BlogModel
- 日付(date: DateTimeField)
- 内容(message: CharField)
このモデルを実際に反映していきます. main/models.pyを開き,次のように編集してください.
from django.db import models from datetime import datetime class BlogModel(models.Model): date = models.DateTimeField(default=datetime.now) message = models.CharField(max_length=256)
これでmodelの環境は整いました. Datetimeの初期値は無くても良いですが,一応default値として現在時刻を入れておきました
ModelFormをつくる
次にさきほど作ったModelからFormをつくりましょう. mainの中にforms.pyというファイルを作ってください
touch main/forms.py
今つくったforms.pyを次のように編集してください.
from django.forms import ModelForm from main.models import BlogModel from datetimewidget.widgets import DateTimeWidget class BlogModelForm(ModelForm): class Meta: model = BlogModel fields = ("date", 'message') dateTimeOptions = { 'format': 'yyyy-mm-dd HH:ii:ss', 'autoclose': True, 'showMeridian': True } widgets = { 'date': DateTimeWidget(options=dateTimeOptions) }
modelからFormを作るために,2行目でmodelとして定義したBlogModelを呼んでます. 3行目では今回使うライブラリを呼んでます. modelという変数にはFormの元となるmodelを設定してます. fieldsではmodelの中でどれをformにするか設定してます. それぞれの変数名はDjnagoの中で決められているのでこのような名前にしてください.
dateTimeOptionsというのはDatetimeWidgetを具体的にどういうものにするか決めてます.
widgetという辞書形式の変数は今回使うライブラリを適用しているところです.
views.pyの編集
まずは次のように編集してください.
from django.shortcuts import render_to_response from django.template import RequestContext from main.models import BlogModel from main.forms import BlogModelForm def index(request): if request.method == 'POST': blogmodel = BlogModel() blogmodelform = BlogModelForm(request.POST, instance=blogmodel) if blogmodelform.is_valid(): blogmodel = blogmodelform.save(commit=False) blogmodel.save() return render_to_response('index.html', dict(form=blogmodelform, blogs=BlogModel.objects.all()), context_instance=RequestContext(request)) else: return render_to_response('index.html', dict(form=BlogModelForm(), blogs=BlogModel.objects.all()), context_instance=RequestContext(request))
簡単に解説するとblogmodelの中身と編集用のフォームをこれから作るtemplatesのindex.htmlに渡しています. POSTで飛んできたとき(index.htmlの中で投稿されたときに発生)にいろいろとしているとは思いますが,来た記事を保存して再び元の画面に戻しているだけです.
templatesをつくる
ではtemplatesにindex.htmlを作りましょう.
mkdir main/templates touch main/index.html
次にさきほどviewで渡した内容を表示してあげるようなhtmlをつくりましょう. 今回は見かけは拘らず,Django-DateTime-Fieldに必要なものだけでつくりました.
前半のscriptやcss,{{ form.media }}などの分は全て必要なのでとりあえず記述しておきましょう.
formの部分では作ったフォームを呼んできています.
{% load static from staticfiles %}<!DOCTYPE HTML> <html> <head> <title></title> <link href="{% static "bootstrap/css/bootstrap.min.css" %}" rel="stylesheet" type="text/css"/> <script src="{% static "bootstrap/js/bootstrap.js" %}"></script> <script src="{% static "jquery/jquery.min.js" %}"></script> {{ form.media }} </head> <body> <form action="" method="post"> {% csrf_token %} {{ form.as_table }} <input type="submit" value="Tweet" /> </form> {% for blog in blogs %} <h3>日付</h3> {{ blog.date }} <h3>つぶやき</h3> {{ blog.message }} {% endfor %} </body> </html>
urls.pyの設定
dtwidgetsample/urls.pyを設定しましょう
from django.conf.urls import patterns, url from main.views import index urlpatterns = patterns('', url(r'^', index), )
最後の仕上げ
ここまででひとまず全体構成を見てみましょう
. ├── db.sqlite3 ├── dtwidgetsample │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-34.pyc │ │ ├── settings.cpython-34.pyc │ │ ├── urls.cpython-34.pyc │ │ └── wsgi.cpython-34.pyc │ ├── settings.py │ ├── urls.py │ └── wsgi.py ├── main │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-34.pyc │ │ ├── admin.cpython-34.pyc │ │ ├── forms.cpython-34.pyc │ │ ├── models.cpython-34.pyc │ │ └── views.cpython-34.pyc │ ├── admin.py │ ├── forms.py │ ├── migrations │ │ ├── 0001_initial.py │ │ ├── __init__.py │ │ └── __pycache__ │ │ ├── 0001_initial.cpython-34.pyc │ │ └── __init__.cpython-34.pyc │ ├── models.py │ ├── static │ │ ├── bootstrap │ │ │ ├── css │ │ │ │ ├── bootstrap-theme.css │ │ │ │ ├── bootstrap-theme.css.map │ │ │ │ ├── bootstrap-theme.min.css │ │ │ │ ├── bootstrap.css │ │ │ │ ├── bootstrap.css.map │ │ │ │ └── bootstrap.min.css │ │ │ ├── fonts │ │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ │ └── glyphicons-halflings-regular.woff │ │ │ └── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ └── npm.js │ │ └── jquery │ │ ├── jquery.js │ │ ├── jquery.min.js │ │ └── jquery.min.map │ ├── templates │ │ └── index.html │ ├── tests.py │ └── views.py └── manage.py
こんな感じになっていればOKです.
makemigrationsやmigrateをして,起動しましょう
python manage.py makemigrations python manage.py migrate python manage.py runserver
ひっかかったところ
- ValidationでFalseになる
- YYYY-yy-dd hh:mm:ssという形式であれば無事動きましたが,USの形式などではValidationチェックで引っ掛かることがありました.
まとめ
StowをつかってRustインストールしてみた
はじめに
RustというMozillaが開発しているプログラミング言語があります.
http://www.rust-lang.org/index.html
先日,ついにこの言語の1.0アルファ版が出ました.0.11以来使ってなかったので改めてインストールすることにしました.
インストール方法
インストール自体は,ここに記載されているインストールスクリプト(rustup.sh)を叩くのが楽そうです. http://www.rust-lang.org/install.html
しかし,単純にこのまま叩いてしまうと/usr/local以下にインストールされてしまい,アンインストールが面倒だという問題があります.
そこでGnu Stowをつかってインストールを管理する方法を選択しました.
Gnu Stow
Stowはtarballからインストールするときに管理してくれるツールです.
使い方は簡単で,/usr/local/stowというディレクトリをつくって,その中にインストールするパッケージディレクトリを設置するだけです.
やってみる
Gnu Stowのインストール
OSXの人は
brew install stow mkdir /usr/local/stow
homebrewでstowをインストール,stowで管理するディレクトリをつくるだけです. 作ったディレクトリのなかにtarballでビルドしたパッケージを設置します.
Rustのインストール
stowでrustを管理するためにディレクトリをつくってあげます.
mkdir /usr/local/stow/rust-1.0nightly
僕はrust-1.0nightlyという名前にしました.
つぎにrustup.shをダウンロードします.
wget https://static.rust-lang.org/rustup.sh
ダウンロードしたrustup.shを開いて,286行目の一文を次のように修正します.
valopt prefix "/usr/local/stow/rust-1.0nightly" "set installation prefix"
先程作ったディレクトリを指定するだけです.
あとは
sh ./rustup.sh
これでインストールします.
最後にstowをつかって,/usr/local/binなどで扱えるように設定します.
cd /usr/local/stow stow -v rust-1.0nightly
これだけです.
こうするとシンボリックリンクが適切な箇所に貼られると思います.
もしrustをアンインストールしたければ
stow -D rust-1.0nightly
とやるだけでシンボリックリンクが削除されて環境を汚すことなくセットアップができます.
まとめ
stowをつかってRustをインストールした.
はてなブログに投稿するスクリプトhapomaをつくってみた
はじめに
このはてぶ自動で2getツールの記事を読んで,はてなAPIを使いたくなりました.
運用厳禁:はてブ自動2getツールを作ってみた - 今日学んだこと
ネタを色々と悩んでいたのですが,今回ははてなブログに投稿したり更新することができるスクリプトをつくってみました.コードの話題は今回はあまりありません(つくってみた自慢ですねw).
HAYASAKA-Ryosuke/hapoma · GitHub
hapomaと言います.HAtenaPOstMAnというつもりでつけました.
setup.pyもまだ作ってないような,途中ですが,基本的な機能は完成したので暖い目で見てください(笑)
内容
まずはざっくりと行ないたいことを決定.
- 手元にあるmarkdownファイルをはてなブログに投稿したい
- でも,いきなり投稿するのは怖いので下書きとして投稿したい
- 投稿したブログは手元にあるファイルを修正して送信すれば勝手に上書きされるようにしたい.
と,ざっくりこんな感じです.
なので,これらを満たす機能としては,
- はてなブログに手元の記事を下書きとして投稿する機能
- 一度投稿したブログか新規で書いたかを判別して,上書きか新規投稿か自動で検出する機能
があれば良いと重います.
今回使用したツールとライブラリを以下に示します.
- ツールやライブラリ
LevelDBは投稿した直後やDBファイルが無いときにはてなブログの記事IDと記事タイトルを取得して貯めるためのものです. このときタイトルをKey,記事IDをValueにしてます. こうすることで編集しているファイルのタイトルをlevedbに渡してIDが存在するかどうかで,新規投稿か上書きかを決定するようにしました.
requestsはurllib2を便利にしたライブラリで,これに関係するoauthライブラリも便利に使えそうなので今回採用しました.
OAuthのheaderを見る方法
oauthはキーやトークンを必要とするために,正しいフォーマットで送信できているのか不安になります.
その場合にどうデバッグしたかメモしておきます.
まずはOAuthのフォーマットをチェック
oauth = OAuth1Session(oauth_consumer_key, oauth_consumer_secret, access_token, access_token_secret) print(oauth.headers)
まとめ
hapomaというはてなブログに投稿するスクリプトを作った話を書いた
このブログはhapomaをつかって送信している.
謝辞
OAuth周りではTwitter上で@nakazyeさんにアドバイス頂きました.
ありがとうございました!
JavaScript勉強しました
はじめに
Django,Flaskなどのウェブフレームワークを使う上で,実情ではJavaScriptの存在は欠かすことができません.
僕はJavaScriptの知識が殆どないため,そこがネックでした.
なので,ここ2日ほど合間を縫って勉強してみました.
今日はそのメモを載せておきます.
参考にしたページ
JavaScript ガイド - JavaScript | MDN
まずはこのページを読んで勉強しました.1番から9番ほどまで手を動かしつつ進めました. このページのおかげで,JavaScript独特のスコープの考え方,オブジェクト指向をある程度把握することができます.
最近の行儀のよい JavaScript の書き方 - Qiita
JSは本当に多用な書き方ができます.それにゆえに,質の悪いコードを作りがちです. このページではJSを書く上で綺麗に書くための方法が示されており,個人的には非常に助かりました.
JavaScript勉強中のメモ
主に以上の二つのページを参考にして勉強しました. この中で個人的にひっかかった部分をメモしておこうと思います.
弱い型
JSは弱い型付き動的言語として知られています. 弱い型とは文字列と整数の評価が曖昧なことです.
例えばPythonでは
print(1=='1') # false
リテラルの違いによりfalseが表示されます. JSでは
console.log(1=='1'); // true
とすると評価が曖昧なのでtrueが返ってきます.
ただし,
console.log(1==='1'); // false
のようにイコールを3つ並べると厳密な判定をするようになるので,falseが返ってくるようになります. ですので,こちらのイコールを3つ並べるような使い方のほうがバグは起きにくいと思います.
ちなみに
1+'1'
では11という結果が返ってきます.文字列を優先的に識別しているみたいですね(型変換しなくて良いので楽かも).
ホイスティング
JSでは変数を定義した位置関係なく呼び出せるような仕組みがあります. これをホイスティングと呼びます.
実際にホイスティングの例を示します.
まずは変数が無いとエラーを吐くコードを書いてみます.
console.log(foo); // error
このコードはxが定義されていないので当然エラーが出ますね.
では次のように書いた場合ですと
console.log(foo); // undefined var foo;
undefinedと表示されます つまりfooという変数が評価される文の後に定義した場合でもホイスティングによって
var foo;
console.log(foo);
foo;
と同じコードを意味するようになります. つまり,うっかり変数を比較などする部分を変数宣言の前に書いてしまうと エラーを吐かないということでちょっと怖いですね.
綺麗なJSコードまとめ
先程,紹介したリンクのうちの「最近の行儀のよいJavaScriptの書き方」でもわかりやすくまとまっているのですが,初心者にとっては理解が難しい箇所があったのでそこを補足する形になりますがメモしておきます.
無名関数の書き方の意味
まず以下のようにして書く無名関数が呪文にしか見えませんでした.
(function() { //処理 })();
これをわかりやすく理解するためにメモしておきます.
まず
foo = function(){ //処理 } foo();
これはfooに無名関数を代入してますね. foo()で実行してますね. でもfooに代入しないで自身で実行までするようにコードを書いてみます.
function(){ //処理 }();
最後に()をつけることで実行しようとしているのですが,こうするとエラーがでちゃいます. そこでfunction全体を小括弧で括ってから実行してみますと,自然と次のような書き方になります.
(function(){ //処理 })();
これで無名関数がなぜこのように書くのかについて把握できたかなと思います.
あとは記事を読めばわかりやすいかなとは思います.
個人的に気になったのはメンバ変数にどうやって外部からアクセスするかです. それ以外の詳細は本記事で参考にしたブログを読んでもらえればと思います.
たとえば,fooという変数をpublicなメンバ変数として扱いたい場合とします. ただし,hamという変数はprivateにしたいとします.
その場合は,publicなメンバ変数をfooコンストラクタの中にthisをつけてfooを書けば良いです. pribateな場合はthisをつける必要はありません.
(function(global){ "use strict"; var ham = null; function MyClass(b){ this.foo = null; ham = b; } MyClass.prototype.hello = MyClass_hello; function MyClass_hello(name){ console.log("Hello "+ name); console.log("foo "+ this.foo); console.log("ham "+ ham); } global.MyClass = MyClass; })((this || e).self || global); mycl = new MyClass("hi"); // ham = "hi", this.foo = null mycl.foo = "foo"; // ham = "hi", this.foo = "foo" mycl.ham = "egg" // hamにeggは代入されない(Errorは特に出ないけど) mycl.hello("kuroneko");
出力
"Hello kuroneko" "foo foo" "ham hi"
です.
まとめ
JavaScriptで詰ったところについてまとめました.
勉強するにあたり,Twitter上で@mkamimuraさんには御助言を頂く機会があり,助かりました. ありがとうございました!
Guardをつかってみた
はじめに
Guardというファイル変更を検出して動作するRuby製のツールがあります. Guardは編集して保存するだけで勝手に何かバックでコマンドを走らせることができるツールです.
これをtexのコンパイルなどに使うと非常に便利でしたのでメモしておきます.
Guardのインストール
gem install guard gem install gurad-shell
guard-shellをつかうことでシェル上からGuardを常駐させたり,Guardの設定ファイルを簡単に生成できるようになります.
Guardの簡単な使い方
ここではtest.texというファイルを書くことを想定した例で説明していきます.
普通の文章でも構いませんが,ここでは例なので次のような文を書いておきます
test.tex
\documentclass[a4j]{jarticle} \begin{document} テスト \end{document}
これでGuardを導入するまでの下準備ができました.
では本題に移りましょう.
Guardの初期化をまずはしましょう
guard init
こうすることで Guardfileと呼ばれるものが生成されるはずです. 中身はrubyで記述することができます. コメントアウトがたくさん書かれてますが,必要部分はここだけです. Guardfile
guard :shell do watch(/(.*).txt/) {|m| `tail #{m[0]}` } end
Rubyを知らない方にとっては意味不明かもしれませんが,ざっくり説明すると, 現在のディレクトリ以下に存在するどれかのtxtファイルが変更されたらtailコマンドをつかって変更されたファイルの末尾を出力するというものです.
なお,m[0]にはファイル名が出力されます.
ごちゃごちゃ書いても仕方ないので例をおみせしましょう. まずはGuardfileのtxtの部分をtexに変更してください
guard :shell do watch(/(.*).tex/) {|m| `tail #{m[0]}` } end
これでtexファイルが変更されたら,そのtexファイルをtailで実行するというものになりました.
ではさっそくつぎのようにしてGuardを走らせましょう.
Guardの起動は簡単です.shell上で次のようにタイプしましょう.
guard
こうするとバックで動くので別なウィンドウで先程つくったtest.texを上書きしてみてください.何も編集しないで,保存だけすると次のような形でtexファイルをtailした結果がでるはずです.
\documentclass[a4j]{jarticle} \begin{document} テスト \end{document} [1] guard(main)>
基本的な使い方はこれだけです. これでtexを保存するたびにコンパイルする方法は察しはついたかと思います. ようするに「tail m[0]」の箇所をコンパイルするときのコマンドに書き換えてあげればいいのです.
Guardをつかってコンパイルしてみる
ここではplatexをつかってtexをコンパイルしてdviファイルを生成,dvipdfmxをつかってpdfを出力させてみます.
guard :shell do watch(/(.*).tex/) {|m| `platex test.tex && dvipdfmx test.dvi` } end
これだけです.
あとは先程のようにGuardを実行しておけば保存するたびにコンパイルされるはずです.
ただ,僕自身癖なのか,つい上書き保存を何度もしてしまうらしくて,何もファイルが変更されてないときに保存してしまって,そのたびにコンパイルがバックで動くという面倒なことをよくやってしまいます.人によってはある条件のときだけコンパイルさせたいとかそういったこともあるとは思います.
次はそのようなときにどうするかについてメモしておきます.
特定の条件のときだけアクションを起こしたい
ここでは,ファイルに何ら変更がないときにはコンパイルをしないというような設定にしてみます.
やりかたは様々あるとは思いますが,簡単に思いついた方法があったのでそれに沿って設定してみました.
では実際にやってみましょう
まずはtest.texをコピーしてbuf.texというファイルをつくります
cp test.tex buf.tex
つぎに差分をとって変化を検出するような設定をしましょう.先程つくったGuardfileを次のように編集すればokです.
Guardfile
guard :shell do watch(/(.*).tex/) {|m| s = `diff readme.tex buf.tex` if s.length > 0 then `cp readme.tex buf.tex` `platex readme.tex && dvipdfmx readme.dvi` end } end
簡単に紹介しますと,
s = `diff readme.tex buf.tex`
でreadme.texとbuf.texの差分を出力してます.その結果がsという変数に代入されます.
次のif文ではs変数に代入された文字列1文字以上あればbuf.texを更新したあとtexのコンパイルをするというものです.
このようにGuardfileはRubyが走るので様々な条件などで試せますね.
まとめ
Guardをtexをつかうときに便利な例をメモした.
ただファイルの変更を検出して動作させるためのものではなく,Rubyを使った自由な表現が可能なので使い方の幅が広がります.
django始めました
はじめに
PythonにはDjangoというフルスタックウェブフレームワークがあります. これまでここのブログではマイクロウェブフレームワークであるflaskの記事が多かったのですが, 最近,Djangoを使う機会を得たことで,学ぶ機会ができ,使ってみることにしました.
なお,本記事で扱う環境は以下の通りです
- Python:3.4.2
- Django1.7
学ぶにあたって,まずはここを見て一通り動かしてみました.
解説がよくまとまっており内容もわかりやすいのですが、自分でどんなアプリを作るか決めないまま進めたこともあってか曖昧模糊だったので、シンプルなブログを作って練習してみました。
今回は以下のような仕様のブログの作成しました.
作成するブログ
- 機能
- 記事投稿
- タイトル
- 本文
- 日付
- 記事表示
- 記事投稿
これだけです. 見た目についてもbootstrapなどを使えば簡単にかっこいいウェブアプリがつくれると思いますが,djangoに必要な部分以外外すことで、よりシンプルにして理解しやすくしました..
作成
作成にあたり,まずはdjangoの基本的な使い方を説明します.
djangoのプロジェクト(kuronekoblogとする)をスタートするには
django-admin startproject kuronekoblog
です.
これで基本的なディレクトリが勝手に生成されます.
kuronekoblog/ manage.py kuronekoblog/ __init__.py settings.py urls.py wsgi.py
それぞれのファイルについて説明しましょう.
kuronekoblog/manage.py これはdjangoのアプリを新規作成したり,データベースを扱う,サーバを立ち上げるなどの役割を持つファイルです.
kuronekoblog/kuronekoblog/settings.py 外部ライブラリや日本語ロケールの設定などを行なうファイルです
kuronekoblog/kuronekoblog/urls.py ユーザのアクセスURLによってviews.pyで定義した関数のどれに渡すかを決めるファイル
これらを、まとめると、開発の流れとしては、
settings.pyで日本語ロケール設定をする。
models.pyでデータベースの設計をする。
views.pyにリクエストに応じた関数を書く。
urls.pyにリクエストを受ける時のURLを設定する。
という感じです。
運用の流れとしては
ユーザからリクエストが来たらurls.pyでリクエストの内容に応じてviews.pyのなかに書かれている関数に投げる。
urls.pyよりきたリクエストにしたがってviews.pyでmodels.pyで定義したデータベースを操作したり、templatesで定義したhtmlファイルを呼び出して、ユーザに送信する。
という流れです。
実装
プログラムを組んでいきましょう。
まずは,プロジェクト内にウェブアプリを生成しましょう.
python manage.py startapp blog
これでkuronekoblog/blogというディレクトリが生成されるので全体として次のようになるはずです
kuronekoblog/ manage.py blog/ __init__.py settings.py urls.py wsgi.py kuronekoblog/ __init__.py settings.py urls.py wsgi.py
まずはsettings.pyで日本語設定やblogを扱うように登録をします. 次のように編集してください.
kuronekoblog/settings.py
・・・ INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', ) ・・・ LANGUAGE_CODE = 'ja' TIME_ZONE = 'Asia/Tokyo' ・・・
ここまでいったら,次はadminページを作ります
まずは次のコマンドを実行してください
python manage.py createsuperuser
実行したら
ユーザID メールアドレス パスワード
が聞かれるので,それぞれ設定してください
次にAdminページで表示させるものについて設定を次のように行なってください.
blog/admin.py
from django.contrib import admin from blog.models import blogdata # Register your models here. class blogdataAdmin(admin.ModelAdmin): list_display = ('id', 'title', 'date',) list_display_links = ('id', 'title',) admin.site.register(blogdata, blogdataAdmin)
次にmodels.pyにてブログのデーターベースを定義します. 今回は,シンプルなブログを作るので次のような情報が扱えるようにしましょう.
- ブログタイトル
- ブログ本文
- ブログの生成日時
では実際に定義していきます.
blog/models.py
from django.db import models from datetime import datetime class blogdata(models.Model): title = models.CharField(max_length=512) text = models.TextField() date = models.DateTimeField(default=datetime.now)
- タイトル(title)はCharFieldで最大512文字まで扱えるようにしました
- 本文(text)はテキストフィールドで好きなように記述できるようにしました
- 投稿日時(date)はDatetimeで現在の日時を渡すようにしました 面白いのはここでは一切SQLを書いてないことです. SQLを書かなくてもこのように直感的な書き方でデータベースが扱えるなんて凄いですね.
では次は,データベースの生成を行ないます
まずは,kuronekoblog自体のデータベースを作りましょう
python manage.py migrate
これで直下にsqliteのファイルが生成されます 次にmodelで定義したblogアプリのデータベースを作ります
python manage.py makemigrations blog
そして反映
python manage.py migrate
ここで一旦ウェブアプリを立ち上げてみましょう
python manage.py runserver
これでlocalhost:8000に立ち上がります. 以下のページにアクセスしてください
先程,定義したAdmin.pyの内容に従って表示されるはずです.
ではviews.pyに処理を書いていきましょう. まずはviews.pyとurls.py動作を確かめるために次のようにしましょう. urls.pyはblog以下に無いはずなので生成してください.
blog/views.py
from django.shortcuts import render from django.http import HttpResponse # Create your views here. def edit(request): return HttpResponse('編集') def show(request): return HttpResponse('読む')
blog/urls.py
#!coding:utf-8 from django.conf.urls import patterns, url from blog import views urlpatterns = patterns('', url(r'^$', views.show, name='show'), url(r'^edit/$', views.edit, name='edit'), )
kuronekoblog/urls.py
from django.conf.urls import patterns, include, url from django.contrib import admin urlpatterns = patterns('', url(r'^admin/', include(admin.site.urls)), url(r'^blog/', include('blog.urls', namespace='blog')), )
これでサーバを立ち上げて以下のURLにアクセスしてください
python manage.py runserver
http://localhost:8000/blog/edit
localhost:8000/blogのほうでは「読む」という文字列だけが返ってくるはずです.
localhost:8000/blog/editのほうでは「編集」という文字列だけが返ってくるはずです.
簡単にurls.pyとviews.pyの関係を説明しますと, まずはblog/views.pyの関数では
- edit
- show
の二つの関数をつくりました
次にこれらの関数にリクエストを投げるためにblog/urls.pyに正規表現をつかってリンクさせております.
url(r'^$', views.show, name='show'),
url関数の第一引数がURLのパラメータです.第二引数ではviews.showと書くことで,views.pyの中にあるshow関数にリクエストを投げること. という指定をしてます.第三引数は名前を持たせているだけです(たぶん...).
次にblog/urls.pyをkuronekoblog自体に伝えるために kuronekoblog/urls.pyにblog/urls.pyを登録したわけです.
これで紐付けは完了です.
次はテンプレートまわりを実装しましょう.
テンプレートはjinja2のフォーマットが対応しており,flaskでhtmlを使ったことがある人は馴染み深いはずです.
まずはblog以下にtemplatesを作りましょう.
mkdir blog/templates
この中にbase.htmlというflaskでいうところのlayout.htmlにあたる,各ページ共通部分のヘッダなどを作ります.
touch blog/templates/base.html
base.htmlを編集しましょう.
blog/templates/base.html
<!DOCTYPE html> <html lang="{{ LANGUAGE_CODE|default:"en-us" }}"> <head> <meta charset="UTF-8"> <title>{% block title %}BlogPage{% endblock %}</title> </head> <body> {% block content %} {{ content }} {% endblock %} </body> </html>
次にshow関数で呼ばれるテンプレートを書きます.そのためにディレクトリを次のように追加してください
mkdir blog/templates/blog
ここにテンプレートを作ります.ここではblogshow.htmlというファイルにしましょう.
touch blog/templates/blog/blogshow.html
この中にbase.htmlを継承してブログを表示する部分を書きます. blog/templates/blog/blogshow.html
{% extends "base.html" %} {% block title %}ブログ内容{% endblock title %} {% block content %} {% for blog in blogs %} <h3>日付</h3> {{ blog.date }} <h3>タイトル</h3> {{ blog.title }} <h4>本文</h4> {{ blog.text }} {% endfor %} {% endblock content %}
かなりシンプルですね.日付,タイトル,本文という順で表示されるように想定してます.
では,今つくったtemplatesをviewsに書きましょう. 先程つくったviewsの中身を次のように改造してください
blog/views.py
from django.shortcuts import render_to_response from django.http import HttpResponse from django.template import RequestContext from blog.models import blogdata # Create your views here. def edit(request): return HttpResponse('編集') def show(request): blogs = blogdata.objects.all() return render_to_response('blog/blogshow.html', {'blogs': blogs}, context_instance=RequestContext(request))
flaskではテンプレートを呼ぶときはrender_templatesをつかいましたが,djangoではrender_to_responseを使います. blogsというので,データベースのオブジェクトを受けとって,辞書でテンプレートのhtmlに渡してます.
では実際にAdminを弄ってデータが入ることを確認しましょう. 次のURLにアクセスしてテキトーなブログを作りましょう.
http://localhost:8000/admin/blog/blogdata/
blogdataに追加という箇所をクリックすると編集画面が現われるので書いてみてください.
データベースを管理画面から直感的な操作で弄れるので便利ですね.
追加したら以下のURLにアクセスしてshowがデータベースの内容をひっぱってブログを表示していることを確認してください.
見れたでしょうか.
次は投稿機能を実装します.
基本的にshowを実装した流れは同じなのですが,投稿フォームはdjangoがもともと持っているものを使います. このあたりはさすがフルスタックフレームワークといったところです.
views.pyを開いて次のように編集してください
blog/views.py
#!coding:utf-8 from django.shortcuts import render_to_response from django.http import HttpResponse from django.template import RequestContext from blog.models import blogdata from django.forms import ModelForm class blogform(ModelForm): class Meta: model = blogdata fields = ('title', 'text', 'date', ) def edit(request): blogs = blogdata() form = None if request.method == 'POST': pass else: form = blogform(instance=blogs) return render_to_response('blog/blogedit.html', {'form': form}, context_instance=RequestContext(request)) def show(request): blogs = blogdata.objects.all() return render_to_response('blog/blogshow.html', {'blogs': blogs}, context_instance=RequestContext(request))
さっきと違うのはformの処理とeditの内容を追加したことですね. blogformというクラスでは,modelでは編集するデータベースを指定,fieldsでは投稿画面で編集する内容を記載します.
editの中ではblogdataのインスタンスをblogsで受けとって,それをblogformのクラスに渡したあと,formで受けとっています. そのformをrender_to_responseで処理しているわけです.まずはGET部分の処理だけを書きました.
次はtemplatesです.showと同様にblogedit.htmlをtemplates/blogの中に作って編集します.
blog/templates/blog/blogedit.html
{% extends "base.html" %} {% block title %}投稿{% endblock title %} {% block content %} <form action="{% url 'blog:edit' %}" method="post"> {% csrf_token %} {{ form }} <button type="submit">投稿</button> </form> {% endblock content %}
formアクションの
{% url 'blog:edit' %}
ではblog内のviewsに定義されているeditのformを呼んでいることを示しています.
もう一つ
{% csrf_token %}
というのはこれがないと強制的なリダイレクトとdjangoが誤認識をしてしまうので,その対策に書いてます.
あとは
{{ form }}
でformの内容を呼んでいます.
それでは以下のURLにアクセスして,投稿画面が動いていることを確認してください. レイアウトなどはまったく弄ってないので汚ないと思います(笑)
http://localhost:8000/blog/edit
確認したら,次はviews.pyにpostの処理を追加しましょう.
blog/views.py
#!coding:utf-8 from django.shortcuts import render_to_response, redirect from django.http import HttpResponse from django.template import RequestContext from blog.models import blogdata from django.forms import ModelForm class blogform(ModelForm): class Meta: model = blogdata fields = ('title', 'text', 'date', ) # Create your views here. def edit(request): blogs = blogdata() form = None if request.method == 'POST': form = blogform(request.POST, instance=blogs) if form.is_valid(): blog = form.save(commit=False) blog.save() return redirect('blog:show') pass else: form = blogform(instance=blogs) return render_to_response('blog/blogedit.html', {'form': form}, context_instance=RequestContext(request)) def show(request): blogs = blogdata.objects.all() return render_to_response('blog/blogshow.html', {'blogs': blogs}, context_instance=RequestContext(request))
POSTで受けとった内容をblogformを経由してformで受けとってます.
form.is_valid()
というのは形式が正しいかを判断する部分らしく,バリデーションと呼ばれるようです(知らなかった...).
バリデーションが正しければその投稿内容を保存します.
保存したらredirectでshow関数を呼びだしてブログ内容を表示するようにします.
これでだいたいの処理は書き終わりましたが,
から編集画面のリンクを張りわすれていたので張っておきましょう.
blog/templates/blog/blogedit.html
{% extends "base.html" %} {% block title %}ブログ内容{% endblock title %} {% block content %} <a href="{% url 'blog:edit' %}">投稿画面</a> {% for blog in blogs %} <h3>日付</h3> {{ blog.date }} <h3>タイトル</h3> {{ blog.title }} <h4>本文</h4> {{ blog.text }} {% endfor %} {% endblock content %}
これで完成です.
まとめ
非常に簡易なブログをquitaの記事を参考にしながら作成した.