学習目的で、Python + Flaskを使用してサイトを作成しています。データベースから画像を復元して画面に表示したい。しかし、一度に一歩ずつ。
そもそもデータベースに画像を保存する方法がわかりません。私の検索では、データベースでbytea
タイプを使用する必要があることが明らかになりました。次に、画像を取得し、どういうわけか(??)それをバイトの配列(bytea ==バイトの配列?)に変換し、どういうわけか(??)この配列を挿入コマンドで使用します。
Java( ここ )とC#( ここ )でそれを行う方法を(多分)発見することができましたが、私は本当に少なくとも今のところ、Pythonを使うのが好きです。
誰かが私を助けることができますか?
このサイトにはこの種の質問がたくさんあります。しかし、それらのほとんど(85%以上)は「データベースに画像を保存するべきではありません。それらはfsに属します」と回答され、質問に答えることができません。残りは私の問題を完全には解決しません。したがって、重複にこの種の回答がある場合は、これを重複としてマークしないでください。
私は通常、人々のために完全なサンプルプログラムを作成しませんが、あなたはそれを要求せず、それは非常に単純なものなので、ここに行きます:
#!/usr/bin/env python3
import os
import sys
import psycopg2
import argparse
db_conn_str = "dbname=regress user=craig"
create_table_stm = """
CREATE TABLE files (
id serial primary key,
orig_filename text not null,
file_data bytea not null
)
"""
def main(argv):
parser = argparse.ArgumentParser()
parser_action = parser.add_mutually_exclusive_group(required=True)
parser_action.add_argument("--store", action='store_const', const=True, help="Load an image from the named file and save it in the DB")
parser_action.add_argument("--fetch", type=int, help="Fetch an image from the DB and store it in the named file, overwriting it if it exists. Takes the database file identifier as an argument.", metavar='42')
parser.add_argument("filename", help="Name of file to write to / fetch from")
args = parser.parse_args(argv[1:])
conn = psycopg2.connect(db_conn_str)
curs = conn.cursor()
# Ensure DB structure is present
curs.execute("SELECT 1 FROM information_schema.tables WHERE table_schema = %s AND table_name = %s", ('public','files'))
result = curs.fetchall()
if len(result) == 0:
curs.execute(create_table_stm)
# and run the command
if args.store:
# Reads the whole file into memory. If you want to avoid that,
# use large object storage instead of bytea; see the psycopg2
# and postgresql documentation.
f = open(args.filename,'rb')
# The following code works as-is in Python 3.
#
# In Python 2, you can't just pass a 'str' directly, as psycopg2
# will think it's an encoded text string, not raw bytes. You must
# either use psycopg2.Binary to wrap it, or load the data into a
# "bytearray" object.
#
# so either:
#
# filedata = psycopg2.Binary( f.read() )
#
# or
#
# filedata = buffer( f.read() )
#
filedata = f.read()
curs.execute("INSERT INTO files(id, orig_filename, file_data) VALUES (DEFAULT,%s,%s) RETURNING id", (args.filename, filedata))
returned_id = curs.fetchone()[0]
f.close()
conn.commit()
print("Stored {0} into DB record {1}".format(args.filename, returned_id))
Elif args.fetch is not None:
# Fetches the file from the DB into memory then writes it out.
# Same as for store, to avoid that use a large object.
f = open(args.filename,'wb')
curs.execute("SELECT file_data, orig_filename FROM files WHERE id = %s", (int(args.fetch),))
(file_data, orig_filename) = curs.fetchone()
# In Python 3 this code works as-is.
# In Python 2, you must get the str from the returned buffer object.
f.write(file_data)
f.close()
print("Fetched {0} into file {1}; original filename was {2}".format(args.fetch, args.filename, orig_filename))
conn.close()
if __name__ == '__main__':
main(sys.argv)
Python 3.3で記述。Python 2.7を使用するには、ファイルを読み取ってbuffer
オブジェクトに変換するか、ラージオブジェクト関数を使用する必要があります。 Python 2.6以前に変換するには、argparseのインストール、おそらく他の変更が必要です。
データベース接続文字列をテスト実行する場合は、システムに適した文字列に変更することをお勧めします。
大きな画像で作業している場合は、bytea
の代わりに psycopg2のラージオブジェクトサポート を使用することを検討してください-特に、ストアの場合はlo_import
、直接書き込む場合はlo_export
ファイル、および画像の小さなチャンクを一度に読み取るためのラージオブジェクト読み取り関数。
import psycopg2
import sys
def readImage():
try:
fin = open("woman.jpg", "rb")
img = fin.read()
return img
except IOError, e:
print "Error %d: %s" % (e.args[0],e.args[1])
sys.exit(1)
finally:
if fin:
fin.close()
try:
con = psycopg2.connect(database="testdb", user="abc")
cur = con.cursor()
data = readImage()
binary = psycopg2.Binary(data)
cur.execute("INSERT INTO images(id, data) VALUES (1, %s)", (binary,) )
con.commit()
except psycopg2.DatabaseError, e:
if con:
con.rollback()
print 'Error %s' % e
sys.exit(1)
finally:
if con:
con.close()
それが私の解決策です、それは私のウェブサイトで働くことができます:
@main.route('/upload', methods=['GET', 'POST'])
def upload_avatar():
if request.method == 'POST':
file = request.files['file']
if file and allowed_file(file.filename):
current_user.avatar_local = file.read()
db.session.add(current_user)
db.session.commit()
return redirect(url_for('main.user_page', username=current_user.username))
return render_template('upload_avatar.html', user=current_user)
flask、Flask-Alchemyを使用してデータベースを処理します。
{% block edit_avatar %}
<form action="" method=post enctype=multipart/form-data>
<p><input type=file name=file>
<input type=submit value=Upload>
</form>
{% endblock %}
それはhtmlファイルです。あなたはそれをあなたのhtmlに埋め込むことができます。
Pythonの base64 を使用して、任意のバイナリ文字列をテキスト文字列にエンコードおよびデコードできます。