むずかしいことはわかりません

いろいろ書いてるみたいな

その8 - データストアからデータを削除

前回google側にアップロードしたものは投稿の際にエラーになるというお恥ずかしい状態でした。すいません。
今回はその辺りは、動作確認を徹底したので投稿することもできるようになっています。

そんなわけで、今回は削除処理を追加しました。
(ただし、ローカルのdev_appserverのログインで管理者アカウントとしてログインするチェックボックスにチェックしてログインした場合の動作しか確認していません)

class Article(db.Model):
	author = db.StringProperty(multiline=False)
	title = db.StringProperty(multiline=False)
	body = db.StringProperty(multiline=True)
	date = db.DateTimeProperty(auto_now_add=True)
	akey = db.StringProperty(multiline=False)

前回は、authorの部分がUserPropertyになっていて、ここが問題になっていました。
その部分を現在は文字列で処理するように変更しました。

そして、akey として記事ごとのキー文字列を追加しました。
記事1つに付き1つのキーになります。
ただし、時間を文字列に直した物をMD5化して使っているのでかぶるときもあるかもしれません。

delact = self.request.get('delete').strip()

elif delact != "":
	dellist = self.request.get_all('delkey')
	dlsiz = len(dellist)

	for dkey in dellist:
		query = db.GqlQuery ( "SELECT * FROM Article WHERE akey = :1", dkey )
		if query.count() >= 1:
			for article in query:
				article.delete()

変数 delact には、テンプレート側にある 削除 ボタンを押したときに delete という名前のリクエスト内容が代入されます。(この場合は"削除"の文字列)
削除 ボタンが押されてないときは文字列は空になります。

GQLでは DELETE というクエリはないので1つずつ SELECT してからそのデータを delete() する処理で代用しています。
query.count()がGqlQuery()の結果がいくつあるのかを返します。

ifやforの文末の : がないと、syntax errorになるので注意しましょう。
どうもまだまだ慣れていないので、これを忘れて動かないなんてことが何度かありました。

akey = hashlib.md5(time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))).hexdigest()

articles = db.GqlQuery ( "SELECT * FROM Article ORDER BY date " + str(article_order) + " LIMIT " + str(article_start) + "," + str(article_limit) )

MD5化するのには、hashlib を使っています。

md5(文字列).hexdigest()

で、MD5した結果の16進数文字列が取得できます。

time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))
time.strftime("フォーマット文字列", 時間) を使うことでphpのDate関数のように時間を文字列で取得することができます。

GQLでもLIMITはオフセットと開始位置を取るので、今回は後々の事を考えてそのフォーマットで書いています。
article_start が開始位置
article_limit が取得したい数
になります。この開始位置を変更することで、改ページ処理にも対応できるようになります。

{{ article.title|default:"(無題)" }} / 投稿者 : {{ article.author }}<br />
{{ article.date|date:"Y/m/d H:i:s" }}

テンプレートの中のdefaultやdateなどのフィルタも使ってみました。
article.title|default:"(無題)" は、article.title の文字列が空だった場合に (無題) と表示します。

article.date|date:"Y/m/d H:i:s" は、article.date の内容を後に続くフォーマット文字列に整形して表示します。
これによって、リストをそのままテンプレートエンジンに渡したときに日付の形式を見慣れたものにすることができました。

今回のソース

今回変更された main.py と main.html です。

main.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import wsgiref.handlers
import os
import time
import cgi
import datetime
import re
import urllib
import hashlib

from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import template

article_limit = 10	#
article_order = 'DESC'	# 'ASC' 'DESC'
article_start = 0

class Article(db.Model):
	author = db.StringProperty(multiline=False)
	title = db.StringProperty(multiline=False)
	body = db.StringProperty(multiline=True)
	date = db.DateTimeProperty(auto_now_add=True)
	akey = db.StringProperty(multiline=False)

class PostHandler(webapp.RequestHandler):
	def post(self):
		article = Article()
		article.body = self.request.get('body').strip()
		delact = self.request.get('delete').strip()

		if article.body != "":
			article.body = re.sub("\n","<br />", article.body)
			article.author = self.request.get('author')
			article.akey = self.request.get('akey')
			if self.request.get('title').strip() != "":
				article.title = self.request.get('title').strip()
			else:
				article.title = ''

			article.put()

			self.response.out.write("redir")
		elif delact != "":
			dellist = self.request.get_all('delkey')
			dlsiz = len(dellist)

			for dkey in dellist:
				query = db.GqlQuery ( "SELECT * FROM Article WHERE akey = :1", dkey )
				if query.count() >= 1:
					for article in query:
						article.delete()

		self.redirect('/')

class MainHandler(webapp.RequestHandler):
	def get(self):
		if users.get_current_user():
			articles = db.GqlQuery ( "SELECT * FROM Article ORDER BY date " + str(article_order) + " LIMIT " + str(article_start) + "," + str(article_limit) )

			akey = hashlib.md5(time.strftime("%Y%m%d%H%M%S", time.localtime(time.time()))).hexdigest()
			url = users.create_logout_url(self.request.uri)
			username = users.get_current_user().nickname()

			if users.is_current_user_admin() == True :
				administrator = True 
			else:
				administrator = False

			template_values = {
				'articles': articles,
				'author': username,
				'akey' : akey,
				'administrator' : administrator,
				'url': url
			}

			path = os.path.join(os.path.dirname(__file__), 'main.html')
			self.response.out.write(template.render(path, template_values))
		else:
			url = users.create_login_url(self.request.uri)

			template_values = {
				'url': url
			}

			path = os.path.join(os.path.dirname(__file__), 'notlogin.html')
			self.response.out.write(template.render(path, template_values))

def main():
	application = webapp.WSGIApplication([('/', MainHandler),
					      ('/post', PostHandler)
					     ],
                                       debug=True)
	wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja-JP" lang="ja-JP">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<!-- link rel="stylesheet" type="text/css" href="/css/main.css" / -->
</head>

<body>
<a href="{{ url }}">ログアウト</a>{% if administrator %} / 管理者モード {% endif %}
<hr />
<form method="POST" action="/post">
{% for article in articles %}
	{% if article.body %}
{{ article.title|default:"(無題)" }} / 投稿者 : {{ article.author }}<br />
{{ article.date|date:"Y/m/d H:i:s" }}  {% if administrator %}/ <input type="checkbox" name="delkey" value="{{article.akey}}">削除{% endif %}<br />
{{ article.body }}<br />
<hr />
	{% endif %}
{% endfor %}
タイトル:<input type="text" name="title"><br />
名前:{{ author }}<br />
本文:<br />
<textarea name="body" cols="50" rows="5"></textarea><br />
<input type="hidden" value="{{author}}" name="author">
<input type="hidden" value="{{akey}}" name="akey">
<input type="submit" value="投稿/reload" name="post">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="reset" value="書き直し">
{% if administrator %}
<hr />
<input type="password" name="dpasswd"><input type="submit" value="削除" name="delete">
{% endif %}
</form>

</body>

</html>