くろねこ日記

ソフトウェアに関する技術メモが多いです.

テストデータ作成に便利な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チェックで引っ掛かることがありました.

まとめ

Django-Datetime-Widgetの使い方を紹介した.

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ファイルをはてなブログに投稿したい
  • でも,いきなり投稿するのは怖いので下書きとして投稿したい
  • 投稿したブログは手元にあるファイルを修正して送信すれば勝手に上書きされるようにしたい.

と,ざっくりこんな感じです.

なので,これらを満たす機能としては,

  • はてなブログに手元の記事を下書きとして投稿する機能
  • 一度投稿したブログか新規で書いたかを判別して,上書きか新規投稿か自動で検出する機能

があれば良いと重います.

今回使用したツールとライブラリを以下に示します.

  • ツールやライブラリ
    • Python・・・今回使用する言語
    • LevelDB・・・Google製のKVS
    • plyvel・・・pythonからLevelDBを操作するライブラリ
    • requests・・・urllib2よりも賢いライブラリ
    • requests-oauth・・・requestsからoauth認証を弄るためのライブラリ

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は編集して保存するだけで勝手に何かバックでコマンドを走らせることができるツールです.

guard/guard · GitHub

これを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というファイルをつくります.

  • コピーしたファイルとtest.texの差分をとって,もし何らかの文字列がでてきたら,変更と見做してコンパイルを実行,何も文字列がでてこなければ変更されてないとしてコンパイルせずに無視します.

では実際にやってみましょう

まずは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 Django入門 (1) - Qiita

解説がよくまとまっており内容もわかりやすいのですが、自分でどんなアプリを作るか決めないまま進めたこともあってか曖昧模糊だったので、シンプルなブログを作って練習してみました。

今回は以下のような仕様のブログの作成しました.

作成するブログ

  • 機能
    • 記事投稿
      • タイトル
      • 本文
      • 日付
    • 記事表示

これだけです. 見た目についても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に立ち上がります. 以下のページにアクセスしてください

http://localhost:8000/admin/

先程,定義した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

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に追加という箇所をクリックすると編集画面が現われるので書いてみてください.

f:id:kuroneko0208:20141112203354p:plain

データベースを管理画面から直感的な操作で弄れるので便利ですね.

追加したら以下のURLにアクセスしてshowがデータベースの内容をひっぱってブログを表示していることを確認してください.

http://localhost:8000/blog/

見れたでしょうか.

次は投稿機能を実装します.

基本的に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関数を呼びだしてブログ内容を表示するようにします.

これでだいたいの処理は書き終わりましたが,

http://localhost:8000/blog

から編集画面のリンクを張りわすれていたので張っておきましょう.

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の記事を参考にしながら作成した.