Entonces, tengo un formulario donde un usuario puede publicar un título, un cuerpo y cargar una imagen. Tomé esa imagen del formulario y la guardé como "Blob" en mi base de datos de Postgres.
Pero tengo un problema, estoy confundido sobre cómo consultar los datos de blob de imágenes y decodificarlos y mostrárselos al usuario.
Estas son mis tablas:
class User(db.Model, UserMixin): id = db.Column(db.Integer, primary_key=True) email = db.Column(db.String(120), unique=True, nullable=False) username = db.Column(db.String(30), unique=True, nullable=False) password = db.Column(db.String(120), nullable=False) date_joined = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) posts = db.relationship('Post', backref='author', lazy=True, passive_deletes=True) class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) body = db.Column(db.Text, nullable=False) link = db.Column(db.LargeBinary) date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow) user_id = db.Column(db.Integer, db.ForeignKey( 'user.id', ondelete='CASCADE'), nullable=False)Esta es la ruta que guarda el POST y la IMAGEN en mi base de datos y directorio de carpetas estáticas:
@app.route('/create/post', methods=['GET', 'POST']) def create_post(): # Image upload and validation if request.method == 'POST': if request.files: if allowed_image_size(request.cookies.get('filesize')): flash('Image exceeds the maximum size limit of 5 MB!', 'danger') return redirect(request.url) image = request.files['uploadImg'] if image.filename == '': flash('No image detected or file name is empty!', 'danger') return redirect(request.url) if not allowed_images(image.filename): flash('Invalid image extension!', 'danger') return redirect(request.url) else: filename = secure_filename(image.filename) image.save(os.path.join(app.config['IMAGE_UPLOADS'], image.filename)) # Regular Posts form = PostForm() if form.validate_on_submit(): post = Post(title=form.title.data, body=form.body.data, link=image.read(), user_id=current_user.id) db.session.add(post) db.session.commit() flash('Post submitted', 'success') return redirect(url_for('home')) return render_template('create_post.html', title='Create Post', form=form) Además, cuando consulto la publicación para ver si puedo recuperar los datos, uso algo como posts = Post.query.all() y uso print(posts.link.read()) . Recibo un error que dice AttributeError: 'list' object has no attribute 'link'
@app.route('/') @app.route('/home') def home(): posts = Post.query.all() print(posts.link.read()) return render_template('home.html', title='Home', posts=posts)Creo que debe almacenar la imagen como un nombre de ruta en su tabla de publicaciones, no como un blob.
cambie esto en su base de datos a:
link = db.Column(db.String(30))Luego, al agregar la publicación a la base de datos, pase la cadena de la ruta del nombre del archivo de imagen a la publicación
También es una buena práctica cambiar el nombre del archivo con una cadena aleatoria, ya que muchos usuarios pueden cargar myCatPicture.jpg , lo que provocaría que se sobrescriba el archivo.
Algo como esto haría
def get_random_string(length): # Random string with the combination of lower and upper case letters = string.ascii_letters return ''.join(random.choice(letters) for i in range(length))Luego, al guardar la imagen, guarde el nuevo nombre de archivo
if not allowed_images(image.filename): flash('Invalid image extension!', 'danger') return redirect(request.url) else: ext = os.path.splitext(file_name)[1] # get the file extension new_filename = get_random_string(20) # create a random string image.save(os.path.join(app.config['IMAGE_UPLOADS'], new_filename+ext)) # save with the new pathY en la creación de publicaciones, use la nueva cadena.
post = Post(title=form.title.data, body=form.body.data, link=os.path.join(app.config['IMAGE_UPLOADS'], new_filename+ext) , user_id=current_user.id) #here we are substituting the old blod with the new stored image path stringNota:
No importa el nombre del archivo siempre que tenga la ruta almacenada en la base de datos. Siempre puede buscarlo para obtener la imagen/ruta.
...
Luego, en su plantilla (como ya tiene TODAS las publicaciones) puede iniciar un ciclo for
{% for post in range(len(posts)) %} <h1> {{ post.title }} </h1> <img src= {{post.link }} > <p> {{ post.body }} </p> {% endfor %}Esto debería iterar a través de cada título de publicación, imagen y contenido, etc.
De nuevo, estoy un poco confuso en esto. Pero creo que eso lo cubre bastante.