2

So, I have a form where a user can posts a title, body and upload an image. I took that image from the form and saved it as a "Blob" to my Postgres database.

But I have a problem, I am confused on how to query for that image blob data and decode and show it to the user.

These are my tables:

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)

This is the route that saves the POST and the IMAGE to my database and static folder directory:

@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)

Also, when I query the post to see if I can retrieve the data, using something like posts = Post.query.all() and use print(posts.link.read()). I get an error saying 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)
3
  • I believe its always best to store the image path rather than a blob into your database. Then you can pass that image path into the render_template call. I'm a bit fuzzy with flask as I haven't used it for a while but its easy enough to do this way. Commented Jul 29, 2020 at 18:53
  • Ahh Yes, I do have the image saved in my static directory, but the problem is, I have no idea how I would display the image to the user that posted it. So, User #1 creates two posts with images and I don't know how to connect those 2 images to the User #1 without using the database to do so. Commented Jul 29, 2020 at 18:57
  • Is the image blob in the posts table? When did you store it as a blob? The way i've done it before is store the path of the image in the posts table. Then as you are passing the POST object into the template you do something like <img src = {{posts.post_image_path }} > Commented Jul 29, 2020 at 19:10

1 Answer 1

2

I believe you should store the image as a path name into your posts table, not a blob.

change this in your database to :

 link = db.Column(db.String(30))

Then when adding to post to the database pass the string of the image filename path into the Post

Also its good practice to rename the file with a random string, because many users might upload myCatPicture.jpg which would cause it to overwrite the file.

Something like this would do

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

Then when saving the image save the new file name

    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 path

And in the post creation use the new string.

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 string

Note:

It doesn't matter the filename as long as you have the path stored in the database. You can always look it up to get the image/path.

...

Then in your template (as you already have ALL the posts) you can start a for loop

{% for post in range(len(posts)) %}
    <h1> {{ post.title }} </h1>
    <img src= {{post.link }} >
    <p> {{ post.body }} </p>
{% endfor %}

This should iterate through every post title, image and content etc.

Again i'm a little fuzzy on this. But think that pretty much covers it.

Sign up to request clarification or add additional context in comments.

2 Comments

No sweat :) glad it's helped.
I just followed Corey Schafer's flask tutorial a while back. Its well worth it. youtube.com/watch?v=MwZwr5Tvyxo

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.