Flask-SQLAlchemyのモデルでのリレーションシップ

一昨日のアプリを作る段階で、Flask-SQLAlchemy のモデルでのリレーションシップの作り方を調べたのでメモ。↓ここに書いてある。

 cf. One-to-Many Relationships – Flask SQLAlchemy

簡単に言うと、主キーを持つテーブルにリレーションシップを作成して、外部キーを持つテーブルに db.ForeignKey を設定してやる。
次の例では Category と Format が Book に対して1対多リレーションになっている。つまり、Category と Format が主キーを持っていて、Book が外部キーを持っている。

class Book(db.Model):
    __tablename__ = 'books'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String)
    volume = db.Column(db.String)
    series = db.Column(db.String)
    series_volume = db.Column(db.String)
    author = db.Column(db.String)
    translator = db.Column(db.String)
    publisher = db.Column(db.String)
    category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
    format_id = db.Column(db.Integer, db.ForeignKey('formats.id'))
    isbn = db.Column(db.String)
    published_on = db.Column(db.String)
    original_title = db.Column(db.String)
    note = db.Column(db.String)
    keyword = db.Column(db.String)
    disk = db.Column(db.String)
    disposed = db.Column(db.Boolean, default=False)

class Category(db.Model):
    __tablename__ = 'categories'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    books = db.relationship('Book', backref='category', lazy='dynamic')

class Format(db.Model):
    __tablename__ = 'formats'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String)
    books = db.relationship('Book', backref='format', lazy='dynamic')

はじめ、ForeignKey を db.ForeignKey(‘category.id’) とやったらダメだった。モデル名 (category) じゃなくてテーブル名 (categories) でないといけないのね。

Flaskで書籍管理アプリを作った

作った、というか作り始めた。とりあえず基本的な機能として、新規追加と編集はできるようになった。削除はまだ。Flask で DELETE メソッドってどうやって発行するんだ?

メインの画面はこんな感じ。

bruschetta-index

デザインもまだなんにもしてない。スタイルシートはこれからだな。
書籍の詳細画面。

bruschetta-book-detail

参考にしたのは、先週のエントリで挙げたサイトのほかにこのあたり。

 cf. http://a2c.bitbucket.org/flask/quickstart.html
 cf. FlaskSQLAlchemy

Flaskにさわってみた

Flask は Python の軽量 Web ワークフレーム。Ruby の Sinatra に影響を受けてるらしい。
さわった、といってもほんのちょっとだけ。↓のページの 1 〜 4 をやってみた。

 cf. Pythonで学ぶwebアプリケーションの作り方by Flask

結果出来たのがこの Flaskr という小さなブログみたいなアプリケーション。login 機能がついてて、記事をポストできる。

flaskr

基本的に、上のページのチュートリアルのとおりにやればできたんだけど、ひとつだけ、アプリケーションを起動するときに Warning が発生する(アプリケーション自体は動く)。

(env)takatoh@nightschool $ python manage.py runserver
/home/takatoh/w/handson/env/local/lib/python2.7/site-packages/flask_sqlalchemy/__init__.py:800: UserWarning: SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.
  warnings.warn('SQLALCHEMY_TRACK_MODIFICATIONS adds significant overhead and will be disabled by default in the future.  Set it to True to suppress this warning.')
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

メッセージにあるとおり、この警告を抑制するには config.py の中で SQLALCHEMY_TRACK_MODIFICATIONS に True をセットしてやればいい。

SQLALCHEMY_DATABASE_URI = 'sqlite:///flaskr.db'
SECRET_KEY = '\xce\xa3/\x97\xf60\xc1\x9c\x10J\xa2)t\r\xfd\xa9.\xdf\x8d\xe3\xfc\xfd\xb4\x9a'
SQLALCHEMY_TRACK_MODIFICATIONS = True

というわけで、今日はここまで。もう少しさわってみたらなにか作ってみるかな。

文字列を指定した文字数ごとに分割する

今日は Windows マシンから更新。

 cf. ruby 文字列を指定数で分割する – それマグで!

Haskell でやってみた。

module Main where

slices :: Int -> [a] -> [[a]]
slices _ [] = []
slices n xs = h : slices n d
  where
    (h, d) = splitAt n xs

main :: IO ()
main = print $ slices 3 "abcdefghijklmnopqrstuvwxyz"
^o^ > runhaskell stringSlices.hs
["abc","def","ghi","jkl","mno","pqr","stu","vwx","yz"]

Scheme だとこう。

(define slices
  (lambda (lis n)
    (if (< (length lis) n)
      (list lis)
      (cons (take lis n) (slices (drop lis n) n)))))

(define string-slices
  (lambda (str n)
    (map list->string (slices (string->list str) n))))

(print (string-slices "abcdefghijklmnopqrstuvwxyz" 3))
^o^ > gosh string-slices.scm
(abc def ghi jkl mno pqr stu vwx yz)

最後に JavaScript。

function stringSlices(n, str) {
  var l = str.length;
  var result = [];
  for (var i = 0; i < l; i += n) {
    result.push(str.slice(i, i + n));
  }
  return result;
}

console.log(stringSlices(3, "abcdefghijklmnopqrstuvwxyz"));
^o^ > node stringSlices.js
[ 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz' ]

これ、もうちょっとスマートにいかないかな。

[追記]

JavaScript 版、Haskell 版や Scheme 版と同じように考えてみた。少しはスマートになったかな。そうでもないか?

function stringSlices(n, str) {
  if (str.length == 0) {
    return [];
  } else {
    var l = stringSlices(n, str.slice(n))
    l.unshift(str.slice(0, n))
    return l
  }
}

console.log(stringSlices(3, "abcdefghijklmnopqrstuvwxyz"));
^o^ > node stringSlices2.js
[ 'abc', 'def', 'ghi', 'jkl', 'mno', 'pqr', 'stu', 'vwx', 'yz' ]

短縮URLを展開する

ネットを見ていたら、古い記事だけどこんなのを見つけた。

 cf. 短縮URLを1行で展開する@Python – shibuya blog

スクリプトにするんなら1行にすることないだろ、とも思ったけどそれはそれとして、わざわざ短縮元の URL にアクセスしなくても、短縮 URL に HEAD メソッドでアクセスしてヘッダーだけ取ってきて Location を見ればいい、というのをどこかで読んだ覚えがある。
というわけで、Python で書いてみた。

import httplib
import urlparse
import sys

url = sys.argv[1]
o = urlparse.urlparse(url)
conn = httplib.HTTPConnection(o.netloc)
conn.request("HEAD", url)
res = conn.getresponse()
print res.getheader("Location")

今回調べたわかったけど、urllib じゃ HEAD メソッド使えないらしい。で、より低レベルの httplib を使ってる。

実行結果:

takatoh@nightschool $ python expandurl.py http://bit.ly/1axxIi4
https://blog.panicblanket.com/

filestorageとfilestorage-s3の0.1.0をリリースした

以前作って rubygems.org に登録した gem、filestorage を filestorage と filestorage-s3 に分割してリリースした。どっちもバージョン0.1.0。

機能的には直前のバージョン0.0.6と変わったところはないけど、ローカルファイルシステム用の filestorage と Amazon S3 用の filestorage-s3 に分けた。これでローカルファイルシステムしか使わないのに、aws-sdk とかがインストールされることもなくなった。
良かったら使ってください。

ソースコードはこちら:

Cでランダムな文字列を得る

前にも Ruby や Python でやったネタだけども。

#include
#include
#include
#include

int main(int argc, char *argv[])
{
    int i;
    char strpool[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    int lenpool = strlen(strpool);
    int l, r;

    l = atoi(argv[1]);
    char strrand[l + 1];

    srand((unsigned) time(NULL));

    for (i = 0; i < l; i++) {
        r = rand() % lenpool;
        strrand[i] = strpool[r];
     }
    strrand[l] = '\0';
    printf("%s\n", strrand); return 0;
}
takatoh@nightschool $ gcc -Wall -o strrand strrand.c
takatoh@nightschool $ ./strrand 20
hiVKZhO2rwtlDPUJmdo7

フィボナッチ数列を100項まで計算しようとするとunsigned long longでもたりないらしい

タイトルのとおり。

#include
#include

int main(int argc, char *argv[])
{
    unsigned long long int a, b, tmp;
    int n, i;

    n = atoi(argv[1]);
    a = 1;
    b = 1;
    for (i = 1; i <= n; i++) {
        printf("%lld\n", a);
        tmp = a + b;
        a = b;
        b = tmp;
    }

    return 0;
 }

実行結果:

takatoh@nightschool $ ./fib 100
1
1
2
3
5
8
13
21
34

(中略)

4660046610375530309
7540113804746346429
12200160415121876738
1293530146158671551
13493690561280548289
14787220707439219840
9834167195010216513
6174643828739884737
16008811023750101250
3736710778780434371

最後のほうで桁が少なくなったり、明らかにおかしな数値になってしまう。

試しに Ruby でやってみた。

def fib(n)
  a = b = 1
  1.upto(n) do |i|
    puts a
    a, b = b, a + b
  end
end

fib(ARGV[0].to_i)
takatoh@nightschool $ ruby fib.rb 100
1
1
2
3
5
8
13
21
34

(中略)

4660046610375530309
7540113804746346429
12200160415121876738
19740274219868223167
31940434634990099905
51680708854858323072
83621143489848422977
135301852344706746049
218922995834555169026
354224848179261915075

ちゃんと計算できてる! Ruby すげー!

Popでエラーを知らせるにはどうする?

気がつけば1か月もあいだが開いてしまった。

さて、その1か月前のコードを眺めていて気がついたんだけど、スタックから Pop しようとしたとき、スタックが空だったらエラーになってほしい。けど、どうやったら呼び出し側にエラーを伝えられるんだろう?
Pop() の返り値でエラーを伝えることは出来ない。返り値は int 型のどんな値でも有効だから。
調べてみると errno というグローバル変数(?) に値を設定しておく、というやり方があって errno の値(整数値)でどんなエラーかを知らせるようだけど、Pop() のエラーに対応するような errno の値がない。勝手に作ってもいいもんだろうか。

スタック

先週書いた連結リストのコードをライブラリにして、スタックを実装してみた。

#include
#include

#include "linkedlist.h"

#define Stack Cell

Stack *Push(Stack *stack, int x);
int Pop(Stack **stack);

int main(void)
{
    Stack *stack;
    int n;

    stack = NULL;

    stack = Push(stack, 1);
    stack = Push(stack, 3);
    stack = Push(stack, 5);

    DisplayList(stack);

    n = Pop(&stack);
    printf("%d <- ", n);
    DisplayList(stack);
    FreeList(stack);

    return 0;
}

Stack *Push(Stack *stack, int x)
{
    Stack *list;
    list = Cons(x, stack);
    return list;
}

int Pop(Stack **stack)
{
    int x;
    x = Head(stack);
    return x;
}
typedef struct cell Cell;

Cell *NewCell(int val);
Cell *Cons(int val, Cell *list);
Cell *Insert(Cell *list, int pos, int val);
Cell *Delete(Cell *list, int pos);
int Head(Cell **list);
void DisplayList(Cell *list);
void FreeList(Cell *list);
#include

#include "linkedlist.h"

typedef struct cell {
    int value;
    struct cell *next;
} Cell;

Cell *NewCell(int val)
{
    Cell *data;

    data = (Cell *)malloc(sizeof(Cell));
    data->value = val;
    data->next = NULL;

    return data;
}

Cell *Cons(int val, Cell *list)
{
    Cell *data;

    data = NewCell(val);
    data->next = list;

    return data;
}

Cell *Insert(Cell *list, int pos, int val)
{
    Cell *cell1, *cell2;
    int i = 1;

    if (pos == 0) {
        list = Cons(val, list);
    } else {
        cell1 = list;
        while (i < pos) {
            cell1 = cell1->next;
            i++;
        }
        cell2 = NewCell(val);
        cell2->next = cell1->next;
        cell1->next = cell2;
    }

    return list;
}

Cell *Delete(Cell *list, int pos)
{
    Cell *cell1, *cell2;
    int i = 1;

    if (pos == 0) {
        cell2 = list;
        list = cell2->next;
        free(cell2);
    } else {
        cell1 = list;
        cell2 = cell1->next;
        while (i < pos) {
            cell1 = cell2;
            cell2 = cell1->next;
            i++;
        }
        cell1->next = cell2->next;
        free(cell2);
    }

     return list;
}

int Head(Cell **list)
{
    int val;

    val = (*list)->value;
    *list = Delete(*list, 0);

    return val;
}

void DisplayList(Cell *list)
{
    printf("%d", list->value);
    if (list->next == NULL) {
        printf("\n");
    } else {
        printf(", ");
        DisplayList(list->next);
    }
}

void FreeList(Cell *list)
{
    Cell *next = list->next;

    free(list);
    if (next != NULL) {
        FreeList(next);
    }
}

linkedlist.h で

typedef struct cell Cell;

とあるのは、構造体の中身を隠蔽して、その存在だけを公開する書き方。こうすることで、ライブラリを利用する側からは構造体を直接操作することはできなくなる(操作用の関数を使って操作する)。

実行結果:

takatoh@nightschool $ gcc -Wall main.c -c
takatoh@nightschool $ gcc -Wall linkedlist.c -c
takatoh@nightschool $ gcc -Wall main.o linkedlist.o -o stack
takatoh@nightschool $ ./stack
5, 3, 1
5 <- 3, 1

出力の1行目は値(整数)を3つ push したあとのスタックの状態。2行目の <- の左側は pop して取出した値で、右側がそのあとのスタックの状態。 期待通りに動いてるようだ。