sql >> データベース >  >> NoSQL >> MongoDB

Flask-adminを使用してPDFファイルをDBに保存する

    以下は、Flask-Adminを介してblobフィールドにファイルを直接保存する自己完結型の例です。エラーチェックは最小限ですが、正しい方向に進むはずです。

    コードの重要な部分:

    class BlobMixin(object):
        mimetype = db.Column(db.Unicode(length=255), nullable=False)
        filename = db.Column(db.Unicode(length=255), nullable=False)
        blob = db.Column(db.LargeBinary(), nullable=False)
        size = db.Column(db.Integer, nullable=False)
    

    BlobMixin classは、blobデータとともに保存されるフィールドを定義します。多くの場合、ファイルサイズ、mimeタイプ、元のアップロードされたファイルのファイル名などの追加情報を保持すると便利です。

    class Image(db.Model, BlobMixin):
        __tablename__ = 'images'
    
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.Unicode(length=255), nullable=False, unique=True)
    
        def __unicode__(self):
            return u"name : {name}; filename : {filename})".format(name=self.name, filename=self.filename)
    

    Image classは、(BlobMixinを介して)blobを格納するデータベーステーブルです。この例では、アップロードされたファイル名とは関係なく、各画像に一意の名前を付けています。

    クラスBlobUploadField(fields.StringField) Flask-Admin のFileUploadFieldクラスのほぼコピーです。 。ただし、いくつかの重要な違いがあります。ファイルサイズ、mimeタイプ、および元のファイル名を格納するために使用しているフィールドを知る必要があります。これらはコンストラクターを介して渡され、def populate_obj(self, obj, name)で使用されます。 メソッド。

    クラスImageView(ModelView) 単純なFlask-Adminビューです。 form_extra_fieldsでblobフィールドがどのように定義されているかに注意してください。 。 BlobUploadFieldを作成しています 許可されたファイル拡張子リスト、サイズフィールド名、ファイル名フィールド名、およびmimeタイプフィールド名を渡します。フィールドの名前(サイズ、ファイル名、およびmimetype)は、BlobMixinから直接取得されます。 クラスのフィールド名。

    form_extra_fields = {'blob': BlobUploadField(
        label='File',
        allowed_extensions=['pdf', 'doc', 'docx', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif'],
        size_field='size',
        filename_field='filename',
        mimetype_field='mimetype'
    )}
    

    リンクをクリックしてファイルをダウンロードできるように、適切な列フォーマッタを使用してダウンロードリンク列をリストビューに追加しました。

    以下のコードは、Python 2.7.9、Flask 0.10.0、Flask-Admin 1.1.0、およびFlask-SQLAlchemy2.0を使用してテストされています。 SQLiteインメモリデータベースを使用しているため、フラスコアプリケーションを閉じるとデータが失われます。

    import io
    from gettext import gettext
    from flask import Flask, send_file
    from flask.ext.admin import Admin
    from flask.ext.admin.contrib.sqla import ModelView
    from flask.ext.sqlalchemy import SQLAlchemy
    from markupsafe import Markup
    from werkzeug.datastructures import FileStorage
    from wtforms import ValidationError, fields
    from wtforms.validators import required
    from wtforms.widgets import HTMLString, html_params, FileInput
    
    try:
        from wtforms.fields.core import _unset_value as unset_value
    except ImportError:
        from wtforms.utils import unset_value
    
    app = Flask(__name__)
    app.config['DEBUG'] = True
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
    app.config['SQLALCHEMY_ECHO'] = True
    db = SQLAlchemy(app)
    
    
    def build_db():
        db.drop_all()
        db.create_all()
    
    
    class BlobMixin(object):
        mimetype = db.Column(db.Unicode(length=255), nullable=False)
        filename = db.Column(db.Unicode(length=255), nullable=False)
        blob = db.Column(db.LargeBinary(), nullable=False)
        size = db.Column(db.Integer, nullable=False)
    
    
    class Image(db.Model, BlobMixin):
        __tablename__ = 'images'
    
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.Unicode(length=255), nullable=False, unique=True)
    
        def __unicode__(self):
            return u"name : {name}; filename : {filename})".format(name=self.name, filename=self.filename)
    
    
    class BlobUploadField(fields.StringField):
    
        widget = FileInput()
    
        def __init__(self, label=None, allowed_extensions=None, size_field=None, filename_field=None, mimetype_field=None, **kwargs):
    
            self.allowed_extensions = allowed_extensions
            self.size_field = size_field
            self.filename_field = filename_field
            self.mimetype_field = mimetype_field
            validators = [required()]
    
            super(BlobUploadField, self).__init__(label, validators, **kwargs)
    
        def is_file_allowed(self, filename):
            """
                Check if file extension is allowed.
    
                :param filename:
                    File name to check
            """
            if not self.allowed_extensions:
                return True
    
            return ('.' in filename and
                    filename.rsplit('.', 1)[1].lower() in
                    map(lambda x: x.lower(), self.allowed_extensions))
    
        def _is_uploaded_file(self, data):
            return (data and isinstance(data, FileStorage) and data.filename)
    
        def pre_validate(self, form):
            super(BlobUploadField, self).pre_validate(form)
            if self._is_uploaded_file(self.data) and not self.is_file_allowed(self.data.filename):
                raise ValidationError(gettext('Invalid file extension'))
    
        def process_formdata(self, valuelist):
            if valuelist:
                data = valuelist[0]
                self.data = data
    
        def populate_obj(self, obj, name):
    
            if self._is_uploaded_file(self.data):
    
                _blob = self.data.read()
    
                setattr(obj, name, _blob)
    
                if self.size_field:
                    setattr(obj, self.size_field, len(_blob))
    
                if self.filename_field:
                    setattr(obj, self.filename_field, self.data.filename)
    
                if self.mimetype_field:
                    setattr(obj, self.mimetype_field, self.data.content_type)
    
    
    class ImageView(ModelView):
    
        column_list = ('name', 'size', 'filename', 'mimetype', 'download')
        form_columns = ('name', 'blob')
    
        form_extra_fields = {'blob': BlobUploadField(
            label='File',
            allowed_extensions=['pdf', 'doc', 'docx', 'xls', 'xlsx', 'png', 'jpg', 'jpeg', 'gif'],
            size_field='size',
            filename_field='filename',
            mimetype_field='mimetype'
        )}
    
        def _download_formatter(self, context, model, name):
            return Markup("<a href='{url}' target='_blank'>Download</a>".format(url=self.get_url('download_blob', id=model.id)))
    
        column_formatters = {
            'download': _download_formatter,
        }
    
    
    # download route
    
    @app.route("/download/<int:id>", methods=['GET'])
    def download_blob(id):
        _image = Image.query.get_or_404(id)
        return send_file(
            io.BytesIO(_image.blob),
            attachment_filename=_image.filename,
            mimetype=_image.mimetype
        )
    
    # Create admin
    admin = Admin(app, name='Admin', url='/')
    admin.add_view(ImageView(model=Image, session=db.session, category='Database', name='Images'))
    
    
    @app.before_first_request
    def first_request():
        build_db()
    
    if __name__ == '__main__':
        app.run(debug=True, port=7777)
    


    1. mongodbのメモリが不足するとどうなりますか?

    2. GridFを使用したmongoDBからの画像の読み取りと表示

    3. mongodbは複数の配列アイテムで検索します

    4. ネストされた配列を更新するための位置`$`演算子の複数の使用