MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

Przechowywanie pliku PDF w DB za pomocą Flask-admin

Poniżej znajduje się samodzielny przykład przechowywania plików bezpośrednio w polu blob za pośrednictwem Flask-Admin. Kontrola błędów jest minimalna, ale powinna pomóc Ci iść we właściwym kierunku.

Ważne części kodu:

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 definiuje, jakie pola są przechowywane wraz z danymi obiektu blob, często przydatne jest noszenie dodatkowych informacji, takich jak rozmiar pliku, typ MIME i nazwa oryginalnego przesłanego pliku.

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 jest tabelą bazy danych, która przechowuje obiekt blob (poprzez BlobMixin). W tym przypadku każdemu obrazowi nadajemy unikalną nazwę, która jest niezależna od nazwy przesłanego pliku.

Klasa BlobUploadField(fields.StringField) jest prawie kopią klasy FileUploadField z Flask-Admin . Jest jednak kilka ważnych różnic - musimy wiedzieć, jakich pól używamy do przechowywania rozmiaru pliku, typu MIME i oryginalnej nazwy pliku. Są one przekazywane przez konstruktor i używane w def populate_obj(self, obj, name) metoda.

Klasa ImageView(ModelView) to prosty widok Flask-Admin. Zwróć uwagę, jak pole blob jest zdefiniowane w form_extra_fields . Konstruujemy BlobUploadField i przekazywanie na liście dozwolonych rozszerzeń plików, nazwy pola rozmiaru, nazwy pola nazwy pliku i nazwy pola typu MIME. Nazwy pól (rozmiar, nazwa pliku i typ MIME) są pobierane bezpośrednio z BlobMixin nazwy pól klas.

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'
)}

Dodałem kolumnę linku pobierania do widoku listy z odpowiednim formaterem kolumn, dzięki czemu można kliknąć link i pobrać plik.

Poniższy kod przetestowany przy użyciu Pythona 2.7.9, Flask 0.10.0, Flask-Admin 1.1.0 i Flask-SQLAlchemy 2.0. Używa bazy danych SQLite w pamięci, więc dane zostaną utracone po zamknięciu aplikacji kolby.

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. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Aktualizuj wiele, jeśli istnieje , w przeciwnym razie utwórz nowy dokument dla każdego LeadId, który nie istnieje

  2. MongoDB + aplikacja internetowa:baza danych na użytkownika

  3. Czy ktoś zna działający przykład indeksu 2dsphere w pymongo?

  4. Najlepszy sposób na przechowywanie daty/godziny w mongodb

  5. sortuj tablicę w zapytaniu i wyświetlaj wszystkie pola