Python Pylons 一覧系アプリケーションを作る



ある程度材料がそろってきたので、よくある一覧系
(一覧表示、新規登録、編集、削除)のアプリケーションを
作ってみます。

前回作成したモジュールを修正していきます。



コントローラーのpage.pyをこんな感じにしてみました。


#■controllers/hello.py
# -*- coding:utf-8 -*-
import logging
from helloworld.lib.base import *
from helloworld.model import Page

log = logging.getLogger(__name__)

class PageController(BaseController):

  def index(self):
    """
    登録されているコメント一覧を表示
    """
    c.pages = Session.query(Page).all()
    return render('/list.mako')
  
  
  def new(self):
    """
    新規登録
    """
    return render('/new.mako')
  
  def edit(self, id):
    """
    編集
    """
    page_q = Session.query(Page)
    page = page_q.filter_by(id=id).first()
    c.page = page
    return render('/edit.mako')
    
    
  def save(self, id):
    """
    保存
    """
    page_q = Session.query(Page)
    page = page_q.filter_by(id=id).first()
    
    #データが取得できないときは、新規登録
    if not page:
      dummy = page_q.from_statement("SELECT coalesce(max(id) + 1,1) id FROM pages").first()
      page = Page()
      #登録されているidの最大値を設定
      page.id = dummy.id
      Session.clear()
    
    page.title = request.params.get('title','')
    page.content = request.params.get('content','')
    
    #トランザクション開始
    Session.begin()
    #データ編集
    Session.add(page)
    #トランザクション終了
    Session.commit()
    
    redirect_to(action='index')
    
  def destroy(self, id):
    """
    データ削除処理
    """
    page_q = Session.query(Page)
    #ページデータを取得
    page = page_q.filter_by(id=id).first()
    
    #トランザクション開始
    Session.begin()
    #データ削除
    Session.delete(page)
    #トランザクション終了
    Session.commit()
    
    redirect_to(action='index')


saveメソッドのidの最大値を取得するロジックですが、
こんな感じのソースコードにすると・・・


if not page:
  page = page_q.from_statement("SELECT coalesce(max(id) + 1,1) id FROM pages").first()


エラー発生!

sqlalchemy.orm.exc.ConcurrentModificationError:
Updated rowcount 0 does not match number of objects updated 1



じゃあ、こんな感じのソースコードにすると・・・


if not page:
  dummy = page_q.from_statement("SELECT coalesce(max(id) + 1,1) id FROM pages").first()
  page = Page()
  page.id = dummy.id


エラー発生!

sqlalchemy.orm.exc.FlushError:
New instance <Page at 0x19bf190> with identity key (<class 'helloworld.model.Page'>, (5,)) conflicts with persistent instance <Page at 0x19bf2b0>


http://d.hatena.ne.jp/perezvon/20080415/1208239112
http://groups.google.com/group/sqlalchemy/browse_thread/thread/ffc34438770dcef2/a0421db34d637b2b
このへんを参考に、Sessionが怪しいのでは?とあたりをつけ


if not page:
  page = page_q.from_statement("SELECT coalesce(max(id) + 1,1) id FROM pages").first()
  page = Page()
  page.id = dummy.id
  #とりあえずセッションをクリアしてみる
  Session.clear()


これで動いてくれました。
※原理はわかってません。

うーん。どうするのが正解なんだろ?




後はテンプレートたちです。

#■templates/list.mako
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>コメント一覧</title>
</head>
<body>
${h.link_to(u'新規作成', h.url(action="new"))}
<br/>
% for page in c.pages:
<li>
${page.title}
${h.link_to(u'編集', h.url(action="edit", id=page.id))}
${h.link_to(u'削除', h.url(action="destroy", id=page.id), confirm=u'削除してよろしいですか?')}
</li>
% endfor
<br/>
</body>
</html>



#■templates/new.mako

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>新規登録</title>
</head>
<body>

${h.form(h.url(action='save'), method='post')}

タイトル: ${h.text_field('title')}
<br/>
本文:${h.text_area(name='content', rows=7, cols=40)} <br />

${h.submit(u'登録')}
${h.end_form()}
</body>
</html>



#■templates/edit.mako

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>${c.page.title}編集</title>
</head>
<body>

${h.form(h.url(action='save', id=c.page.id), method='post')}

タイトル: ${h.text_field('title', value=c.page.title or '')}
<br/>
本文:${h.text_area(name='content', rows=7, cols=40, content=c.page.content or '')} <br />

${h.submit(u'更新')}
${h.end_form()}
</body>
</html>



動作画面はこんな感じです。

■一覧画面


■新規登録画面


■編集画面


■削除







もどる