<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當(dāng)前位置: 首頁 - 科技 - 知識(shí)百科 - 正文

        Flask/MongoDB搭建簡(jiǎn)易圖片服務(wù)器

        來源:懂視網(wǎng) 責(zé)編:小采 時(shí)間:2020-11-09 13:18:46
        文檔

        Flask/MongoDB搭建簡(jiǎn)易圖片服務(wù)器

        Flask/MongoDB搭建簡(jiǎn)易圖片服務(wù)器:前期準(zhǔn)備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調(diào)教 mongodb 了. 接著安裝個(gè) flask 用來當(dāng) web 服務(wù)器. 當(dāng)然 mongo 也是得安裝的. 對(duì)于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學(xué), 安裝最新版要略費(fèi)些周折
        推薦度:
        導(dǎo)讀Flask/MongoDB搭建簡(jiǎn)易圖片服務(wù)器:前期準(zhǔn)備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調(diào)教 mongodb 了. 接著安裝個(gè) flask 用來當(dāng) web 服務(wù)器. 當(dāng)然 mongo 也是得安裝的. 對(duì)于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學(xué), 安裝最新版要略費(fèi)些周折

        前期準(zhǔn)備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調(diào)教 mongodb 了. 接著安裝個(gè) flask 用來當(dāng) web 服務(wù)器. 當(dāng)然 mongo 也是得安裝的. 對(duì)于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學(xué), 安裝最新版要略費(fèi)些周折, 具體說是 sudoapt

        前期準(zhǔn)備

        通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調(diào)教 mongodb 了.
        接著安裝個(gè) flask 用來當(dāng) web 服務(wù)器.
        當(dāng)然 mongo 也是得安裝的. 對(duì)于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學(xué), 安裝最新版要略費(fèi)些周折, 具體說是

        sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
        echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen' | sudo tee /etc/apt/sources.list.d/mongodb.list
        sudo apt-get update
        sudo apt-get install mongodb-10gen

        如果你跟我一樣覺得讓通過上傳文件名的后綴判別用戶上傳的什么文件完全是捏著山藥當(dāng)小黃瓜一樣欺騙自己, 那么最好還準(zhǔn)備個(gè) Pillow 庫

        pip install Pillow

        或 (更適合 Windows 用戶)

        easy_install Pillow

        正片

        Flask 文件上傳

        Flask 官網(wǎng)上那個(gè)例子居然分了兩截讓人無從吐槽. 這里先弄個(gè)最簡(jiǎn)單的, 無論什么文件都先弄上來

        import flask

        app = flask.Flask(__name__)
        app.debug = True

        @app.route('/upload', methods=['POST'])
        def upload():
        f = flask.request.files['uploaded_file']
        print f.read()
        return flask.redirect('/')

        @app.route('/')
        def index():
        return '''




        '''

        if __name__ == '__main__':
        app.run(port=7777)

      1. 注: 在 upload 函數(shù)中, 使用 flask.request.files[KEY] 獲取上傳文件對(duì)象, KEY 為頁面 form 中 input 的 name 值
      2. 因?yàn)槭窃诤笈_(tái)輸出內(nèi)容, 所以測(cè)試最好拿純文本文件來測(cè).

        保存到 mongodb

        如果不那么講究的話, 最快速基本的存儲(chǔ)方案里只需要

        import pymongo
        import bson.binary
        from cStringIO import StringIO

        app = flask.Flask(__name__)
        app.debug = True
        db = pymongo.MongoClient('localhost', 27017).test

        def save_file(f):
        content = StringIO(f.read())
        db.files.save(dict(
        content=bson.binary.Binary(content.getvalue()),
        ))

        @app.route('/upload', methods=['POST'])
        def upload():
        f = flask.request.files['uploaded_file']
        save_file(f)
        return flask.redirect('/')

        把內(nèi)容塞進(jìn)一個(gè) bson.binary.Binary 對(duì)象, 再把它扔進(jìn) mongodb 就可以了.
        現(xiàn)在試試再上傳個(gè)什么文件, 在 mongo shell 中通過

        db.files.find()

        就能看到了. 不過 content 這個(gè)域幾乎肉眼無法分辨出什么東西, 即使是純文本文件, mongo 也會(huì)顯示為 Base64 編碼.

        提供文件訪問

        給定存進(jìn)數(shù)據(jù)庫的文件的 ID (作為 URI 的一部分), 返回給瀏覽器其文件內(nèi)容, 如下

        def save_file(f):
        content = StringIO(f.read())
        c = dict(content=bson.binary.Binary(content.getvalue()))
        db.files.save(c)
        return c['_id']

        @app.route('/f/')
        def serve_file(fid):
        f = db.files.find_one(bson.objectid.ObjectId(fid))
        return f['content']

        @app.route('/upload', methods=['POST'])
        def upload():
        f = flask.request.files['uploaded_file']
        fid = save_file(f)
        return flask.redirect('/f/' + str(fid))

        上傳文件之后, upload 函數(shù)會(huì)跳轉(zhuǎn)到對(duì)應(yīng)的文件瀏覽頁. 這樣一來, 文本文件內(nèi)容就可以正常預(yù)覽了, 如果不是那么挑剔換行符跟連續(xù)空格都被瀏覽器吃掉的話.

        當(dāng)找不到文件時(shí)

        有兩種情況, 其一, 數(shù)據(jù)庫 ID 格式就不對(duì), 這時(shí) pymongo 會(huì)拋異常 bson.errors.InvalidId; 其二, 找不到對(duì)象 (!), 這時(shí) pymongo 會(huì)返回 None.
        簡(jiǎn)單起見就這樣處理了

        @app.route('/f/')
        def serve_file(fid):
        import bson.errors
        try:
        f = db.files.find_one(bson.objectid.ObjectId(fid))
        if f is None:
        raise bson.errors.InvalidId()
        return f['content']
        except bson.errors.InvalidId:
        flask.abort(404)

        正確的 MIME

        從現(xiàn)在開始要對(duì)上傳的文件嚴(yán)格把關(guān)了, 文本文件, 狗與剪刀等皆不能上傳.
        判斷圖片文件之前說了我們動(dòng)真格用 Pillow

        from PIL import Image

        allow_formats = set(['jpeg', 'png', 'gif'])

        def save_file(f):
        content = StringIO(f.read())
        try:
        mime = Image.open(content).format.lower()
        if mime not in allow_formats:
        raise IOError()
        except IOError:
        flask.abort(400)
        c = dict(content=bson.binary.Binary(content.getvalue()))
        db.files.save(c)
        return c['_id']

        然后試試上傳文本文件肯定虛, 傳圖片文件才能正常進(jìn)行. 不對(duì), 也不正常, 因?yàn)閭魍晏D(zhuǎn)之后, 服務(wù)器并沒有給出正確的 mimetype, 所以仍然以預(yù)覽文本的方式預(yù)覽了一坨二進(jìn)制亂碼.
        要解決這個(gè)問題, 得把 MIME 一并存到數(shù)據(jù)庫里面去; 并且, 在給出文件時(shí)也正確地傳輸 mimetype

        def save_file(f):
        content = StringIO(f.read())
        try:
        mime = Image.open(content).format.lower()
        if mime not in allow_formats:
        raise IOError()
        except IOError:
        flask.abort(400)
        c = dict(content=bson.binary.Binary(content.getvalue()), mime=mime)
        db.files.save(c)
        return c['_id']

        @app.route('/f/')
        def serve_file(fid):
        try:
        f = db.files.find_one(bson.objectid.ObjectId(fid))
        if f is None:
        raise bson.errors.InvalidId()
        return flask.Response(f['content'], mimetype='image/' + f['mime'])
        except bson.errors.InvalidId:
        flask.abort(404)

        當(dāng)然這樣的話原來存進(jìn)去的東西可沒有 mime 這個(gè)屬性, 所以最好先去 mongo shell 用 db.files.drop() 清掉原來的數(shù)據(jù).

        根據(jù)上傳時(shí)間給出 NOT MODIFIED

        利用 HTTP 304 NOT MODIFIED 可以盡可能壓榨與利用瀏覽器緩存和節(jié)省帶寬. 這需要三個(gè)操作
      3. 記錄文件最后上傳的時(shí)間
      4. 當(dāng)瀏覽器請(qǐng)求這個(gè)文件時(shí), 向請(qǐng)求頭里塞一個(gè)時(shí)間戳字符串
      5. 當(dāng)瀏覽器請(qǐng)求文件時(shí), 從請(qǐng)求頭中嘗試獲取這個(gè)時(shí)間戳, 如果與文件的時(shí)間戳一致, 就直接 304
      6. 體現(xiàn)為代碼是

        import datetime

        def save_file(f):
        content = StringIO(f.read())
        try:
        mime = Image.open(content).format.lower()
        if mime not in allow_formats:
        raise IOError()
        except IOError:
        flask.abort(400)
        c = dict(
        content=bson.binary.Binary(content.getvalue()),
        mime=mime,
        time=datetime.datetime.utcnow(),
        )
        db.files.save(c)
        return c['_id']

        @app.route('/f/')
        def serve_file(fid):
        try:
        f = db.files.find_one(bson.objectid.ObjectId(fid))
        if f is None:
        raise bson.errors.InvalidId()
        if flask.request.headers.get('If-Modified-Since') == f['time'].ctime():
        return flask.Response(status=304)
        resp = flask.Response(f['content'], mimetype='image/' + f['mime'])
        resp.headers['Last-Modified'] = f['time'].ctime()
        return resp
        except bson.errors.InvalidId:
        flask.abort(404)

        然后, 得弄個(gè)腳本把數(shù)據(jù)庫里面已經(jīng)有的圖片給加上時(shí)間戳.
        順帶吐個(gè)槽, 其實(shí) NoSQL DB 在這種環(huán)境下根本體現(xiàn)不出任何優(yōu)勢(shì), 用起來跟 RDB 幾乎沒兩樣.

        利用 SHA-1 排重

        與冰箱里的可樂不同, 大部分情況下你肯定不希望數(shù)據(jù)庫里面出現(xiàn)一大波完全一樣的圖片. 圖片, 連同其 EXIFF 之類的數(shù)據(jù)信息, 在數(shù)據(jù)庫中應(yīng)該是惟一的, 這時(shí)使用略強(qiáng)一點(diǎn)的散列技術(shù)來檢測(cè)是再合適不過了.
        達(dá)到這個(gè)目的最簡(jiǎn)單的就是建立一個(gè) SHA-1 惟一索引, 這樣數(shù)據(jù)庫就會(huì)阻止相同的東西被放進(jìn)去.
        在 MongoDB 中表中建立惟一索引, 執(zhí)行 (Mongo 控制臺(tái)中)

        db.files.ensureIndex({sha1: 1}, {unique: true})

        如果你的庫中有多條記錄的話, MongoDB 會(huì)給報(bào)個(gè)錯(cuò). 這看起來很和諧無害的索引操作被告知數(shù)據(jù)庫中有重復(fù)的取值 null (實(shí)際上目前數(shù)據(jù)庫里已有的條目根本沒有這個(gè)屬性). 與一般的 RDB 不同的是, MongoDB 規(guī)定 null, 或不存在的屬性值也是一種相同的屬性值, 所以這些幽靈屬性會(huì)導(dǎo)致惟一索引無法建立.
        解決方案有三個(gè)
      7. 刪掉現(xiàn)在所有的數(shù)據(jù) (一定是測(cè)試數(shù)據(jù)庫才用這種不負(fù)責(zé)任的方式吧!)
      8. 建立一個(gè) sparse 索引, 這個(gè)索引不要求幽靈屬性惟一, 不過出現(xiàn)多個(gè) null 值還是會(huì)判定重復(fù) (不管現(xiàn)有數(shù)據(jù)的話可以這么搞)
      9. 寫個(gè)腳本跑一次數(shù)據(jù)庫, 把所有已經(jīng)存入的數(shù)據(jù)翻出來, 重新計(jì)算 SHA-1, 再存進(jìn)去
      10. 具體做法隨意. 假定現(xiàn)在這個(gè)問題已經(jīng)搞定了, 索引也弄好了, 那么剩是 Python 代碼的事情了.

        import hashlib

        def save_file(f):
        content = StringIO(f.read())
        try:
        mime = Image.open(content).format.lower()
        if mime not in allow_formats:
        raise IOError()
        except IOError:
        flask.abort(400)

        sha1 = hashlib.sha1(content.getvalue()).hexdigest()
        c = dict(
        content=bson.binary.Binary(content.getvalue()),
        mime=mime,
        time=datetime.datetime.utcnow(),
        sha1=sha1,
        )
        try:
        db.files.save(c)
        except pymongo.errors.DuplicateKeyError:
        pass
        return c['_id']

        在上傳文件這一環(huán)就沒問題了. 不過, 按照上面這個(gè)邏輯, 如果上傳了一個(gè)已經(jīng)存在的文件, 返回 c['_id'] 將會(huì)是一個(gè)不存在的數(shù)據(jù) ID. 修正這個(gè)問題, 最好是返回 sha1, 另外, 在訪問文件時(shí), 相應(yīng)地修改為用文件 SHA-1 訪問, 而不是用 ID.
        最后修改的結(jié)果及本篇完整源代碼如下

        import hashlib
        import datetime
        import flask
        import pymongo
        import bson.binary
        import bson.objectid
        import bson.errors
        from cStringIO import StringIO
        from PIL import Image

        app = flask.Flask(__name__)
        app.debug = True
        db = pymongo.MongoClient('localhost', 27017).test
        allow_formats = set(['jpeg', 'png', 'gif'])

        def save_file(f):
        content = StringIO(f.read())
        try:
        mime = Image.open(content).format.lower()
        if mime not in allow_formats:
        raise IOError()
        except IOError:
        flask.abort(400)

        sha1 = hashlib.sha1(content.getvalue()).hexdigest()
        c = dict(
        content=bson.binary.Binary(content.getvalue()),
        mime=mime,
        time=datetime.datetime.utcnow(),
        sha1=sha1,
        )
        try:
        db.files.save(c)
        except pymongo.errors.DuplicateKeyError:
        pass
        return sha1

        @app.route('/f/')
        def serve_file(sha1):
        try:
        f = db.files.find_one({'sha1': sha1})
        if f is None:
        raise bson.errors.InvalidId()
        if flask.request.headers.get('If-Modified-Since') == f['time'].ctime():
        return flask.Response(status=304)
        resp = flask.Response(f['content'], mimetype='image/' + f['mime'])
        resp.headers['Last-Modified'] = f['time'].ctime()
        return resp
        except bson.errors.InvalidId:
        flask.abort(404)

        @app.route('/upload', methods=['POST'])
        def upload():
        f = flask.request.files['uploaded_file']
        sha1 = save_file(f)
        return flask.redirect('/f/' + str(sha1))

        @app.route('/')
        def index():
        return '''




        '''

        if __name__ == '__main__':
        app.run(port=7777)

        聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

        Flask/MongoDB搭建簡(jiǎn)易圖片服務(wù)器

        Flask/MongoDB搭建簡(jiǎn)易圖片服務(wù)器:前期準(zhǔn)備 通過 pip 或 easy_install 安裝了 pymongo 之后, 就能通過 Python 調(diào)教 mongodb 了. 接著安裝個(gè) flask 用來當(dāng) web 服務(wù)器. 當(dāng)然 mongo 也是得安裝的. 對(duì)于 Ubuntu 用戶, 特別是使用 Server 12.04 的同學(xué), 安裝最新版要略費(fèi)些周折
        推薦度:
        • 熱門焦點(diǎn)

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 亚洲日韩国产AV无码无码精品| 亚洲国产精品综合久久20| 在线精品自拍亚洲第一区| 在线看片无码永久免费视频| 亚洲精品在线不卡| 亚在线观看免费视频入口| 久久青草亚洲AV无码麻豆| 99热免费在线观看| 91免费国产自产地址入| 国产成人免费一区二区三区| 国产精品亚洲片在线观看不卡| 精品多毛少妇人妻AV免费久久| 成人免费福利视频| 亚洲同性男gay网站在线观看| 色多多www视频在线观看免费| 四虎影在线永久免费四虎地址8848aa| 亚洲精品色在线网站| 免费大黄网站在线观| 亚洲六月丁香六月婷婷蜜芽| 台湾一级毛片永久免费| 亚洲精品狼友在线播放| 99久久免费观看| 亚洲欧美日韩综合俺去了| 免费国产高清视频| 国产在线观a免费观看| 国产亚洲自拍一区| 18女人腿打开无遮掩免费| 国产在线观看xxxx免费| 成年男女男精品免费视频网站| 国产亚洲一区二区手机在线观看| 美女黄色免费网站| 牛牛在线精品观看免费正| 狠狠久久永久免费观看| 国产一区二区免费在线| 老子影院午夜伦不卡亚洲| 永久中文字幕免费视频网站| 亚洲av综合av一区二区三区| 四虎成人精品一区二区免费网站| 亚洲va精品中文字幕| 国产99精品一区二区三区免费| 亚洲熟妇无码另类久久久|