0

I'm trying to create an image gallery related to parent model Article. I have two models, one to store uploaded files and another to store posted articles linked by image_shots.articles.id.

Here are my models:

class Media(db.Model):
    __tablename__ = 'media'
    id = db.Column(db.Integer, primary_key=True)
    caption = db.Column(db.String(500))
    article = db.Column(db.Integer, db.ForeignKey('articles.id'), index=True)
    posted_date = db.Column(db.DateTime)

    def __init__(self, **kwargs):
        super(Media, self).__init__(**kwargs)

class Article(db.Model):
    __tablename__ = 'articles'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(400))
    body = db.Column(db.Text)
    updated_on = db.Column(db.DateTime)
    view_count = db.Column(db.Integer)

    image_shots = db.relationship("Media", backref="articles")

    def __init__(self, **kwargs):
        super(Article, self).__init__(**kwargs)

Here is my form:

from flask_wtf import Form, validators
from wtforms import StringField, TextAreaField
from wtforms.validators import DataRequired, Length

class ArticleForm(Form):
    title = StringField('Title', validators=[DataRequired(), Length(1, 64), ])
    description = TextAreaField(u'Description', [validators.optional(), validators.length(max=200)])
    file = FileField()

Here is my view:

@articles.route('/new', methods=['GET', 'POST'])
def articles():
     form = ArticleForm()
     articles = [title for title, in db.session.query(Article)]
     if request.method == 'POST'and form.validate_on_submit():
         article = Article(title=form.name.data)
         db.session.add(article)
         db.session.commit()
         flash(message='Article successfully added')
         return redirect(url_for('articles.index'))
     elif request.method == 'GET':
         articles = [title for title, in db.session.query(Article)]
     return render_template('front/articles.html', articles=articles, form=form)

With this, I'm able to save the posted article, but I'm still confused on how to get the uploaded files and save then in their own model with articles.id as foreign key.

little detail, I needed to upload multiple files which form the image gallery in the same article form. How can they be linked?

dirn
  • 19,454
  • 5
  • 69
  • 74
alexander
  • 107
  • 9

1 Answers1

0

I have a similar problem on the project I am doing right now. It's a album website, user create a album and upload multiple files to this album.

Here is my solution.

Models:

# import ...
class Photo(db.Model):
    __tablename__ = 'photos'
    id = db.Column(db.Integer, primary_key=True)
    path = db.Column(db.Text)
    about = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    album_id = db.Column(db.Integer, db.ForeignKey('albums.id'))

class Album(db.Model):
    __tablename__ = 'albums'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.Text)
    about = db.Column(db.Text)
    cover = db.Column(db.Text)
    timestamp = db.Column(db.DateTime, index=True, default=datetime.utcnow)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    photos = db.relationship('Photo', backref='album', lazy='dynamic')

Forms:

# import ...
from flask_wtf.file import FileField, FileAllowed, FileRequired

class NewAlbumForm(Form):
    title = StringField('Title')
    about = TextAreaField('About')
    photo = FileField('Photo', validators=[
    FileRequired(),
    FileAllowed(photos, 'Image Only!')
])
    submit = SubmitField('Submit')

Views:

#import ...

@main.route('/new', methods=['GET', 'POST']) # create new album, like yours.
def create():
    from flask_uploads import UploadSet, configure_uploads, IMAGES
    app = current_app._get_current_object()
    photos = UploadSet('photos', IMAGES)
    form = NewAlbumForm()
    if form.validate_on_submit():
        if request.method == 'POST' and 'photo' in request.files:
            filename=[]
            for img in request.files.getlist('photo'): # upload multiple files.
                photos.save(img)
                url = photos.url(img.filename)
                filename.append(url)
        title = form.title.data
        about = form.about.data
        author = current_user._get_current_object()
        album = Album(title=title, about=about,
            cover=filename[0], # use first file as album cover
            author = current_user._get_current_object())
        db.session.add(album)

        for file in filename:
            photo = Photo(path=file, album=album) # save image path.
            db.session.add(photo)
        db.session.commit()
        return redirect(url_for('.album', id=album.id))
    return render_template('new.html', form=form)


@main.route('/user/<username>/albums') # show albums created by user
def albums(username):
    user = User.query.filter_by(username=username).first()
    if user is None:
        abort(404)
    albums = user.albums.order_by(Album.timestamp.desc()).all()
    album_count = len(albums)
    return render_template('albums.html', user=user, albums=albums, album_count=album_count)


@main.route('/album/<int:id>') # show photos in an album
def album(id):
    album = Album.query.get_or_404(id)
    photos = album.photos.order_by(Photo.timestamp.asc())
    return render_template('album.html', album=album, photos=photos)

In templates, I use for loop to generate image gallary. Like this:

/* route: /album/<int:id> */
<div class="container">
  <div class="row">
    {% for photo in photos %}
    <div class="item">     
      <a class="thumbnail" href="">
       <img class="img-responsive" src="{{ photo.path }}">
      </a>
    </div>
    {% endfor %}
  </div>
</div>

I use Flask-Uploads to upload multiple files, you can get a look at this answer. Besides, I use isotope to sort photos.
May be a bit of complex, you can ask whatever you want to ask :)

Community
  • 1
  • 1
Grey Li
  • 11,664
  • 4
  • 54
  • 64