学んだことをメモする日記

主にpythonについて自分が学んだことについてのメモ帳。理解が深まればいいんだけれども・・・

MongoDBをWindows 7にインストールする

MongoDBをWindows 7のサービスとして登録するときに躓いたのでメモ。

全く同じ状況の人がいたので、それを参照。
Installing MongoDB on Windows 7 - Scott Blaine

そのまま解決。フルパスで入力するのと管理者権限のcmd.exe起動がキモっぽい。
でも、logみると終了してるよ?って感じだったけど、コンパネの管理ツールで起動したらオッケーだった。多分、再起動時から起動になってたのかな?

Flash-AssetsでClosure Compilerを使用する

Flash-AssetsでClosure Compilerを使用した際に躓いた箇所をメモ。

使い方などはFlask-Assets — Flask-Assets 0.8.dev documentationを参照のこと。


Windows環境でClosureを使用しようとすると、なんかエラーがでて正常に動作しない。なんだこれは!とおもって調べてみると環境変数とFlask-Assetsのファイル自体に原因があるみたい。解決策として、環境変数JAVA_HOMEにjava.exeのあるbinフォルダつまり、JAVA_HOME/bin/java.exeとなるように設定を行い、(pythonをインストールしたフォルダ)/Libsite-packages/webassets/filter/__init__.pyの322行目辺り(ver0.7)を

        proc = subprocess.Popen(
            [self.java, '-jar', self.jar] + args,
            # we cannot use the in/out streams directly, as they might be
            # StringIO objects (which are not supported by subprocess)
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            stderr=subprocess.PIPE, shell=True)

とすれば良い。なんか、shell=Trueを追加しないとエラーが出るみたいね。

すごい雑だけど以上。

LiveValidationでID重複チェックを使う

タイトルの通り、LiveValidation - Validation as you typeでユーザーIDの重複チェックを行えるようにしてみた。

理想はTwitterの登録画面で、LiveValidationはフォームの隣にシンプルに結果を表示しているので採用した。

基本的な使い方は、

var user_id = new LiveValidation('id', {validMessage: "valid", wait: 200});
  user_id.add(Validate.Presence, {failureMessage: "invalid"});

みたいな感じで、自分で作った関数を組み込むには

  user_id.add(Validate.Custom, {failureMessage: "invalid", against: function(){return result}});

みたいにValidate.Customで行う。

ここから、ユーザーIDの重複機能を組み込むとなると組み込む関数の返り値が、ブール値のため確認中のメッセージを表示できないと思って一旦ドツボにはまる。解決策として、組み込む関数中にValidate.Errorで例外を投げることで対応できた。結局、グローバルな変数を使うなど下手な感じだけど完成。以下にコード。

  var jqxhr = null;
  var old_value = null;
  var result = false;
  var error_message = 'ユーザーIDの重複をチェックしています。';
  var is_duplicate = function(value, args){
    if(value != old_value){
      old_value = value;
      if(jqxhr)jqxhr.abort();
      jqxhr = $.ajax({
        type: "POST",
        url: '/check',
        data: {user_id: value},
        success: function(data){
          result = data == 'true';
          args.obj.is_check = false;
          args.obj.validate();
        }
      });
      args.obj.is_check = true;
      throw new Validate.Error(error_message);
    }
    if(args.obj.is_check) throw new Validate.Error(error_message);
    return result;
  }

また、これだけだと、確認中のメッセージなどに気に入らない点があったので、LiveValidationのコードをいじるために以下を追加。

  LiveValidation.prototype.is_check = false;
  LiveValidation.prototype.doOnFocus = function(e){
    this.focused = true;
  }
  LiveValidation.prototype.insertMessage = function(elementToInsert){
    this.removeMessage();
    if( (this.displayMessageWhenEmpty && (this.elementType == LiveValidation.CHECKBOX || this.element.value == '')) || this.element.value != '' ){
      var className = this.validationFailed ? this.invalidClass : this.validClass;
      if(this.is_check)elementToInsert.className += ' ' + this.messageClass;
      else elementToInsert.className += ' ' + this.messageClass + ' ' + className;
      if(this.insertAfterWhatNode.nextSibling){
        this.insertAfterWhatNode.parentNode.insertBefore(elementToInsert, this.insertAfterWhatNode.nextSibling);
      }else{
        this.insertAfterWhatNode.parentNode.appendChild(elementToInsert);
      }
    }
  }

そして、スタイルシートを下記のようにいじって終了。

.LV_validation_message{
  color: #666666;
}
.LV_valid {
  color: #009900;
}
.LV_invalid {
  color: #CC0000;
}

なんとか、フルスクラッチで作らずにすんだ・・・

WTFormsを学ぶ その3

前回の続き。

今回はフォームバリデーションについて。
WTForms Documentationの内容について勉強。

まぁ、特に変なことをしようと思ってないので、そのままドキュメント通りに書けば書いたように実装ができた。WTFormsのフォームバリデーションには正規表現によるチェックもできるので、大抵のことはできると思う。ちなみに半角英数字のチェックだと、

validators.Regexp("^[a-zA-Z0-9]+$")

でできる。

あとは、作るとしてもユーザーIDの重複チェックとかかな?
まぁ、それはおいおいということで今回はこれだけ。

WTFormsを学ぶ その2

前回の続き。

WTFormsではフォームフィールドを最初から幾つか用意してある。自分でも作れるみたいだけど、今回はそこまでのものはいらないので、TextFieldを利用。ここで、躓いたのが属性値の追加はどうすればいいか。

前回のをそのまま利用するとおそらく、

<input id="email" name="email" type="text" value="">

みたいな感じになってると思う。
それで、WTForms Documentationを読んでみると、

form.field(class_="text_blob")

上記を記述すると、

<input type="text" name="field_name" value="blah" class="text_blob" id="field_name" />

こうなって、無事にclass="text_blob"が追加されるぜハハッ!って書いてあったので、試してみたけどうまく行かなかった。何がイケないというか勘違いしてたかというと、python内のプログラムをいじってたからでした。
実際にどういう勘違いかというと、

@app.route('/register', methods=['GET', 'POST'])
def register():
    form = Registration(request.form)
    if request.method == 'POST' and form.validate():
        user = User(form.username.data, form.email.data,
                    form.password.data)
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

のところに追記すればいいと思っていて、うまく行かず・・・
実際には、

{% from "_formhelpers.html" import render_field %}
<form method=post action="/register">
  <dl>
    {{ render_field(form.username) }}
    {{ render_field(form.email) }}
    {{ render_field(form.password) }}
    {{ render_field(form.confirm) }}
    {{ render_field(form.accept_tos) }}
  </dl>
  <p><input type=submit value=Register>
</form>

の部分で、

render_field(form.username, class_="name")

と書かないといけないようでした。また、マクロを介さずに、

form.username(class_="name")

とテンプレートに書いても大丈夫みたい。

大した事ではないけど、躓いたのでメモ。

続く。
WTFormsを学ぶ その3 - 学んだことをメモする日記

Sublime Text2のインデントに関して

現在、pythonでなにか書くときに使っているSublime Text 2で、テンプレート用のhtmlを書かなければいけない時があり、インデントのサイズをスペース2個分にしたかったのでメモ。

結論から言えばIndentation Settingsを見れば分かるんだけど説明すると、<syntax>.sublime-settings(<syntax>部分はファイルの種類)というファイルを作成し、内容を

{
"tab_size": 2,
"translate_tabs_to_spaces": true,
"detect_indentation": true,
"use_tab_stops": true
}

とすれば良い。

ちなみに保存するフォルダはwindows 7では、
C:\Users\ユーザー名\AppData\Roaming\Sublime Text 2\Packages\User
でいいはず。
なので、上記フォルダにHTML.sublime-settingsというファイルを作れば、後はソフト側が勝手に認識してやってくれる。

WTFormsを学ぶ その1

PythonのWebアプリケーションフレームワークであるFlaskで遊んでみたいと思い、いじってる途中でフォームについても何かあるかなと思い調べたら、WTFormsという拡張機能があるみたいなので調べてみた。
Form Validation with WTForms — Flask 0.9-dev documentation

インストールに関しては

pip install Flask-WTF

とすれば出来る。

また、自分はDotcloudの環境で利用しようとしてたので、requirements.txtに

Flask-WTF

と追記したらインストールしてくれた。ちなみにバージョンは2012/5/15現在は1.0?。

簡単な例

上記リンク先のドキュメントの例

フォームの設定
from wtforms import Form, BooleanField, PasswordField, TextField, validators

class Registration(Form):
	username = TextField('Username', [validators.Length(min=4, max=25)])
	email = TextField('Email Address', [validators.Length(min=6, max=35)])
	password = PasswordField('New Password', [
		validators.Required(),
		validators.EqualTo('confirm', message='Passwords must match')
	])
	confirm = PasswordField('Repeat Password')
	accept_tos = BooleanField('I accept the TOS', [validators.Required()])

コードから分かる通り、文字数や入力の有無、また、入力値の再入力チェックが簡単に設定できるっぽい。

ルーティングの設定
@app.route('/register', methods=['GET', 'POST'])
def register():
    form = Registration(request.form)
    if request.method == 'POST' and form.validate():
        user = User(form.username.data, form.email.data,
                    form.password.data)
        return redirect(url_for('login'))
    return render_template('register.html', form=form)

ここではPOSTリクエストを受け取ったときの処理を書いてある。form.validate()は上記のフォームの設定で行なった条件を満たしていればTrueとなる。また、受け取ったフォームの情報はform.username.dataで受け取れるみたい。

フォームのテンプレート

最初にフォーム用のフィールドとラベルの表示用のマクロを作る。ドキュメントでは_formhelpers.htmlって名前で作ってある。

{% macro render_field(field) %}
  <dt>{{ field.label }}
  <dd>{{ field(**kwargs)|safe }}
  {% if field.errors %}
    <ul class=errors>
    {% for error in field.errors %}
      <li>{{ error }}</li>
    {% endfor %}
    </ul>
  {% endif %}
  </dd>
{% endmacro %}
>|html|
このマクロを設定することによって、フォームや入力不備時の表示のされ方のデザインを決めることが出来る。ドキュメントには色々書いてあるけど、読むのメンドーだから放置。で、次にフォーム自体のテンプレートをregister.htmlという名前で作成する。
>||
{% from "_formhelpers.html" import render_field %}
<form method=post action="/register">
  <dl>
    {{ render_field(form.username) }}
    {{ render_field(form.email) }}
    {{ render_field(form.password) }}
    {{ render_field(form.confirm) }}
    {{ render_field(form.accept_tos) }}
  </dl>
  <p><input type=submit value=Register>
</form>

これのrender_fieldの部分が上記のマクロで設定したレイアウトで挿入される。
とりあえず基本的なことはこれでできるのかな?

もっと複雑なことをしたい場合はWTForms Documentationを参照。

続く。
WTFormsを学ぶ その2 - 学んだことをメモする日記