Flask / MongoDB 搭建简易图片服务器
前期准备 通过 pip 或 easy_install 安装了 pymongo 之后, 就能通过 Python 调教 mongodb 了. 接着安装个 flask 用来当 web 服务器. 当然 mongo 也是得安装的. 对于 Ubuntu 用户, 特别是使用 Server 12.04 的同学, 安装最新版要略费些周折, 具体说是 sudoapt
前期准备
通过 pip 或 easy_install 安装了 pymongo 之后, 就能通过 Python 调教 mongodb 了.接着安装个 flask 用来当 web 服务器.
当然 mongo 也是得安装的. 对于 Ubuntu 用户, 特别是使用 Server 12.04 的同学, 安装最新版要略费些周折, 具体说是
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10<br>echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list<br>sudo apt-get update<br>sudo apt-get install mongodb-10gen<br>
pip install Pillow<br>
easy_install Pillow<br>
正片
Flask 文件上传
Flask 官网上那个例子居然分了两截让人无从吐槽. 这里先弄个最简单的, 无论什么文件都先弄上来import flask<br><br>app = flask.Flask(__name__)<br>app.debug = True<br><br>@app.route('/upload', methods=['POST'])<br>def upload():<br> f = flask.request.files['uploaded_file']<br> print f.read()<br> return flask.redirect('/')<br><br>@app.route('/')<br>def index():<br> return '''<br> nbsp;html><br> <br> <br> <form>
<br> <input><br> <input><br> </form>
<br> '''<br><br>if __name__ == '__main__':<br> app.run(port=7777)<br>
- 注: 在
upload
函数中, 使用flask.request.files[KEY]
获取上传文件对象, KEY 为页面 form 中 input 的 name 值
保存到 mongodb
如果不那么讲究的话, 最快速基本的存储方案里只需要import pymongo<br>import bson.binary<br>from cStringIO import StringIO<br><br>app = flask.Flask(__name__)<br>app.debug = True<br><strong class="ntstrong">db = pymongo.MongoClient('localhost', 27017).test</strong><br><br>def save_file(f):<br> content = StringIO(f.read())<br> db.files.save(dict(<br> content=<strong class="ntstrong">bson.binary.Binary(content.getvalue())</strong>,<br> ))<br><br>@app.route('/upload', methods=['POST'])<br>def upload():<br> f = flask.request.files['uploaded_file']<br> <strong class="ntstrong">save_file(f)</strong><br> return flask.redirect('/')<br>
bson.binary.Binary
对象, 再把它扔进 mongodb 就可以了.现在试试再上传个什么文件, 在 mongo shell 中通过
db.files.find()<br>
content
这个域几乎肉眼无法分辨出什么东西, 即使是纯文本文件, mongo 也会显示为 Base64 编码.提供文件访问
给定存进数据库的文件的 ID (作为 URI 的一部分), 返回给浏览器其文件内容, 如下def save_file(f):<br> content = StringIO(f.read())<br> <strong class="ntstrong">c = dict(content=bson.binary.Binary(content.getvalue()))</strong><br> <strong class="ntstrong">db.files.save(c)</strong><br> <strong class="ntstrong">return c['_id']</strong><br><br>@app.route('/f/<fid>')<br><strong class="ntstrong">def serve_file(fid):</strong><br> f = db.files.find_one(bson.objectid.ObjectId(fid))<br> return f['content']<br><br>@app.route('/upload', methods=['POST'])<br>def upload():<br> f = flask.request.files['uploaded_file']<br> fid = save_file(f)<br> return flask.redirect(<strong class="ntstrong">'/f/' + str(fid)</strong>)<br></fid>
upload
函数会跳转到对应的文件浏览页. 这样一来, 文本文件内容就可以正常预览了, 如果不是那么挑剔换行符跟连续空格都被浏览器吃掉的话.当找不到文件时
有两种情况, 其一, 数据库 ID 格式就不对, 这时 pymongo 会抛异常bson.errors.InvalidId
; 其二, 找不到对象 (!), 这时 pymongo 会返回 None
.简单起见就这样处理了
@app.route('/f/<fid>')<br>def serve_file(fid):<br> import bson.errors<br> try:<br> f = db.files.find_one(bson.objectid.ObjectId(fid))<br> if f is None:<br> raise bson.errors.InvalidId()<br> return f['content']<br> except bson.errors.InvalidId:<br> flask.abort(404)<br></fid>
正确的 MIME
从现在开始要对上传的文件严格把关了, 文本文件, 狗与剪刀等皆不能上传.判断图片文件之前说了我们动真格用 Pillow
from PIL import Image<br><br>allow_formats = set(['jpeg', 'png', 'gif'])<br><br>def save_file(f):<br> content = StringIO(f.read())<br> try:<br> mime = <strong class="ntstrong">Image.open(content).format.lower()</strong><br> if mime not in allow_formats:<br> raise IOError()<br> except IOError:<br> flask.abort(400)<br> c = dict(content=bson.binary.Binary(content.getvalue()))<br> db.files.save(c)<br> return c['_id']<br>
要解决这个问题, 得把 MIME 一并存到数据库里面去; 并且, 在给出文件时也正确地传输 mimetype
def save_file(f):<br> content = StringIO(f.read())<br> try:<br> mime = Image.open(content).format.lower()<br> if mime not in allow_formats:<br> raise IOError()<br> except IOError:<br> flask.abort(400)<br> c = dict(content=bson.binary.Binary(content.getvalue()), mime=mime)<br> db.files.save(c)<br> return c['_id']<br><br>@app.route('/f/<fid>')<br>def serve_file(fid):<br> try:<br> f = db.files.find_one(bson.objectid.ObjectId(fid))<br> if f is None:<br> raise bson.errors.InvalidId()<br> return <strong class="ntstrong">flask.Response(f['content'], mimetype='image/' + f['mime'])</strong><br> except bson.errors.InvalidId:<br> flask.abort(404)<br></fid>
db.files.drop()
清掉原来的数据.根据上传时间给出 NOT MODIFIED
利用 HTTP 304 NOT MODIFIED 可以尽可能压榨与利用浏览器缓存和节省带宽. 这需要三个操作- 记录文件最后上传的时间
- 当浏览器请求这个文件时, 向请求头里塞一个时间戳字符串
- 当浏览器请求文件时, 从请求头中尝试获取这个时间戳, 如果与文件的时间戳一致, 就直接 304
import datetime<br><br>def save_file(f):<br> content = StringIO(f.read())<br> try:<br> mime = Image.open(content).format.lower()<br> if mime not in allow_formats:<br> raise IOError()<br> except IOError:<br> flask.abort(400)<br> c = dict(<br> content=bson.binary.Binary(content.getvalue()),<br> mime=mime,<br> <strong class="ntstrong">time=datetime.datetime.utcnow()</strong>,<br> )<br> db.files.save(c)<br> return c['_id']<br><br>@app.route('/f/<fid>')<br>def serve_file(fid):<br> try:<br> f = db.files.find_one(bson.objectid.ObjectId(fid))<br> if f is None:<br> raise bson.errors.InvalidId()<br> if <strong class="ntstrong">flask.request.headers.get('If-Modified-Since') == f['time'].ctime()</strong>:<br> return <strong class="ntstrong">flask.Response(status=304)</strong><br> resp = flask.Response(f['content'], mimetype='image/' + f['mime'])<br> <strong class="ntstrong">resp.headers['Last-Modified'] = f['time'].ctime()</strong><br> return resp<br> except bson.errors.InvalidId:<br> flask.abort(404)<br></fid>
顺带吐个槽, 其实 NoSQL DB 在这种环境下根本体现不出任何优势, 用起来跟 RDB 几乎没两样.
利用 SHA-1 排重
与冰箱里的可乐不同, 大部分情况下你肯定不希望数据库里面出现一大波完全一样的图片. 图片, 连同其 EXIFF 之类的数据信息, 在数据库中应该是惟一的, 这时使用略强一点的散列技术来检测是再合适不过了.达到这个目的最简单的就是建立一个 SHA-1 惟一索引, 这样数据库就会阻止相同的东西被放进去.
在 MongoDB 中表中建立惟一索引, 执行 (Mongo 控制台中)
db.files.ensureIndex({sha1: 1}, {unique: true})<br>
解决方案有三个
- 删掉现在所有的数据 (一定是测试数据库才用这种不负责任的方式吧!)
- 建立一个 sparse 索引, 这个索引不要求幽灵属性惟一, 不过出现多个 null 值还是会判定重复 (不管现有数据的话可以这么搞)
- 写个脚本跑一次数据库, 把所有已经存入的数据翻出来, 重新计算 SHA-1, 再存进去
import hashlib<br><br>def save_file(f):<br> content = StringIO(f.read())<br> try:<br> mime = Image.open(content).format.lower()<br> if mime not in allow_formats:<br> raise IOError()<br> except IOError:<br> flask.abort(400)<br><br> <strong class="ntstrong">sha1 = hashlib.sha1(content.getvalue()).hexdigest()</strong><br> c = dict(<br> content=bson.binary.Binary(content.getvalue()),<br> mime=mime,<br> time=datetime.datetime.utcnow(),<br> <strong class="ntstrong">sha1=sha1</strong>,<br> )<br> <strong class="ntstrong">try:</strong><br> db.files.save(c)<br> <strong class="ntstrong">except pymongo.errors.DuplicateKeyError:</strong><br> pass<br> return c['_id']<br>
c['_id']
将会是一个不存在的数据 ID. 修正这个问题, 最好是返回 sha1
, 另外, 在访问文件时, 相应地修改为用文件 SHA-1 访问, 而不是用 ID.最后修改的结果及本篇完整源代码如下
import hashlib<br>import datetime<br>import flask<br>import pymongo<br>import bson.binary<br>import bson.objectid<br>import bson.errors<br>from cStringIO import StringIO<br>from PIL import Image<br><br>app = flask.Flask(__name__)<br>app.debug = True<br>db = pymongo.MongoClient('localhost', 27017).test<br>allow_formats = set(['jpeg', 'png', 'gif'])<br><br>def save_file(f):<br> content = StringIO(f.read())<br> try:<br> mime = Image.open(content).format.lower()<br> if mime not in allow_formats:<br> raise IOError()<br> except IOError:<br> flask.abort(400)<br><br> sha1 = hashlib.sha1(content.getvalue()).hexdigest()<br> c = dict(<br> content=bson.binary.Binary(content.getvalue()),<br> mime=mime,<br> time=datetime.datetime.utcnow(),<br> sha1=sha1,<br> )<br> try:<br> db.files.save(c)<br> except pymongo.errors.DuplicateKeyError:<br> pass<br> return sha1<br><br>@app.route('/f/<sha1>')<br>def serve_file(sha1):<br> try:<br> f = db.files.find_one({'sha1': sha1})<br> if f is None:<br> raise bson.errors.InvalidId()<br> if flask.request.headers.get('If-Modified-Since') == f['time'].ctime():<br> return flask.Response(status=304)<br> resp = flask.Response(f['content'], mimetype='image/' + f['mime'])<br> resp.headers['Last-Modified'] = f['time'].ctime()<br> return resp<br> except bson.errors.InvalidId:<br> flask.abort(404)<br><br>@app.route('/upload', methods=['POST'])<br>def upload():<br> f = flask.request.files['uploaded_file']<br> sha1 = save_file(f)<br> return flask.redirect('/f/' + str(sha1))<br><br>@app.route('/')<br>def index():<br> return '''<br> nbsp;html><br> <br> <br> <form>
<br> <input><br> <input><br> </form>
<br> '''<br><br>if __name__ == '__main__':<br> app.run(port=7777)<br></sha1>
原文地址:Flask / MongoDB 搭建简易图片服务器, 感谢原作者分享。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

Video Face Swap
完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック











この記事では、自動拡張を実現するためにDebianシステムでMongodbを構成する方法を紹介します。主な手順には、Mongodbレプリカセットとディスクスペース監視のセットアップが含まれます。 1。MongoDBのインストール最初に、MongoDBがDebianシステムにインストールされていることを確認してください。次のコマンドを使用してインストールします。sudoaptupdatesudoaptinstinstall-yymongodb-org2。mongodbレプリカセットMongodbレプリカセットの構成により、自動容量拡張を達成するための基礎となる高可用性とデータ冗長性が保証されます。 Mongodbサービスを開始:Sudosystemctlstartmongodsudosys

eコマースのWebサイトを開発するとき、私は困難な問題に遭遇しました。ユーザーにパーソナライズされた製品の推奨事項を提供する方法です。当初、私はいくつかの簡単な推奨アルゴリズムを試しましたが、結果は理想的ではなく、ユーザーの満足度も影響を受けました。推奨システムの精度と効率を改善するために、より専門的なソリューションを採用することにしました。最後に、Andres-Montanez/Adcumentations Bundleを介してAndres-Montanez/Bundleをインストールしました。これは、問題を解決しただけでなく、推奨システムのパフォーマンスを大幅に改善しました。次の住所から作曲家を学ぶことができます。

この記事では、Debianシステムで非常に利用可能なMongoDBデータベースを構築する方法について説明します。データのセキュリティとサービスが引き続き動作し続けるようにするための複数の方法を探ります。キー戦略:レプリカセット:レプリカセット:レプリカセットを使用して、データの冗長性と自動フェールオーバーを実現します。マスターノードが失敗すると、レプリカセットが自動的に新しいマスターノードを選択して、サービスの継続的な可用性を確保します。データのバックアップと回復:MongoDumpコマンドを定期的に使用してデータベースをバックアップし、データ損失のリスクに対処するために効果的な回復戦略を策定します。監視とアラーム:監視ツール(プロメテウス、グラファナなど)を展開して、MongoDBの実行ステータスをリアルタイムで監視し、

Hash値として保存されているため、Navicatを介してMongoDBパスワードを直接表示することは不可能です。紛失したパスワードを取得する方法:1。パスワードのリセット。 2。構成ファイルを確認します(ハッシュ値が含まれる場合があります)。 3.コードを確認します(パスワードをハードコードできます)。

MongoDB効率的なバックアップ戦略の詳細な説明CENTOSシステムでは、この記事では、データセキュリティとビジネスの継続性を確保するために、CENTOSシステムにMongoDBバックアップを実装するためのさまざまな戦略を詳細に紹介します。 Dockerコンテナ環境でのマニュアルバックアップ、タイミング付きバックアップ、自動スクリプトバックアップ、バックアップメソッドをカバーし、バックアップファイル管理のベストプラクティスを提供します。マニュアルバックアップ:MongoDumpコマンドを使用して、マニュアルフルバックアップを実行します。たとえば、Mongodump-Hlocalhost:27017-U Username-P Password-Dデータベース名-O/バックアップディレクトリこのコマンドは、指定されたデータベースのデータとメタデータを指定されたバックアップディレクトリにエクスポートします。

DebianシステムでMongoDBデータベースを暗号化するには、次の手順に従う必要があります。ステップ1:MongoDBのインストール最初に、DebianシステムがMongoDBをインストールしていることを確認してください。そうでない場合は、インストールについては公式のMongoDBドキュメントを参照してください:https://docs.mongodb.com/manual/tutorial/install-mongodb-onedbian/-step 2:暗号化キーファイルを作成し、暗号化キーを含むファイルを作成し、正しい許可を設定します。

gitlabデータベース展開ガイドcentosシステム適切なデータベースの選択は、gitlabを正常に展開するための重要なステップです。 GitLabは、MySQL、PostgreSQL、MongoDBなど、さまざまなデータベースと互換性があります。この記事では、これらのデータベースを選択して構成する方法を詳細に説明します。データベース選択の推奨MYSQL:広く使用されているリレーショナルデータベース管理システム(RDBMS)。安定したパフォーマンスを備えており、ほとんどのGitLab展開シナリオに適しています。 POSTGRESQL:強力なオープンソースRDBMSは、大規模なデータセットの処理に適した複雑なクエリと高度な機能をサポートしています。 Mongodb:人気のNoSQLデータベース、海の扱いが上手です

MongoDBユーザーを設定するには、次の手順に従ってください。1。サーバーに接続し、管理者ユーザーを作成します。 2。ユーザーアクセスを許可するデータベースを作成します。 3. CreateUserコマンドを使用してユーザーを作成し、その役割とデータベースアクセス権を指定します。 4. Getusersコマンドを使用して、作成されたユーザーを確認します。 5.オプションで、特定のコレクションに他のアクセス許可または付与ユーザーの権限を設定します。
