I am trying to create a gallery.html which changes picture behaviour by image id e.g id="lightbox-1", id="lightbox-2", id="lightbox-3" and the gallery behaviour alters according to css, this works well using file paths as sample code highlight below:
<div id="gallery">
<div><img src="images/12.jpg"/><a href="#lightbox-1">512</a></div>
<div><img src="images/13.jpg"/><a href="#lightbox-2">513</a></div>
...
and
<div id="lightbox-1">
<div ><img src="images/12b.jpg"/>
<div >No. <b>512</b> from Picsum</div><a href="#gallery"></a>
</div>
</div>
However I am getting my images from sql-alchemy database and i am using this method to get images from DB, The images are getting pulled successfully but the arrangement is haphazard and i figured the id number is not increasing, hence I am trying to programatically increase the ID number. Here is my code:
<h5>Gallery</h5>
{% set n = 1 %}
{% for image in image_list %}
<div id="gallery">
<div>
<img src="data:;base64,{{ image }}"/>
<a href="#lightbox-{{n}}">{{n}}</a>
</div>
</div>
<div id="lightbox-{{n}}">
<div ><img src="data:;base64,{{ image }}"/>
</div>
</div>
{% set n = n 1 %}
{% endfor %}
In simple terms I want to mimic this behaviour and design using flask to serve the html and sql-alchemy for the images. At the moment, I can serve, and get the images, but cant get replicate the css behaviour Thanks in advance
CodePudding user response:
I think you're iterating in the wrong place and getting a different structure that doesn't match the style sheet.
To get the current index within the running iteration I recommend you to use loop.index
. Creating and incrementing your own variable is therefore unnecessary.
Flask (./app.py)
from flask import (
Flask,
current_app,
redirect,
render_template,
request,
url_for
)
from flask_sqlalchemy import SQLAlchemy
import base64
app = Flask(__name__)
app.config.from_mapping(
SQLALCHEMY_DATABASE_URI='sqlite:///example.db',
SQLALCHEMY_TRACK_MODIFICATIONS=False,
UPLOAD_EXTENSIONS=('jpg',)
)
db = SQLAlchemy(app)
class GalleryImage(db.Model):
id = db.Column(db.Integer, primary_key=True)
mime = db.Column(db.String, nullable=False)
data = db.Column(db.LargeBinary(), nullable=False)
@property
def b64encoded(self):
return base64.b64encode(self.data).decode('ascii')
with app.app_context():
db.create_all()
@app.route('/')
def index():
images = GalleryImage.query.all()
return render_template('index.html', **locals())
def allowed_file(filename):
allowed_extensions = current_app.config.get('UPLOAD_EXTENSIONS', [])
return '.' in filename and \
filename.rsplit('.', 1)[1].lower() in allowed_extensions
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
files = request.files.getlist('file[]')
for file in files:
if file.filename != '' and allowed_file(file.filename):
image = GalleryImage(
mime=file.mimetype,
data=file.read()
)
db.session.add(image)
try:
db.session.commit()
except:
db.session.rollback()
return redirect(url_for('.index'))
return render_template('upload.html')
HTML Template (./templates/upload.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Upload</title>
</head>
<body>
<form method="post" enctype="multipart/form-data">
<input type="file" name="file[]" accept="image/jpeg" multiple />
<button type="submit">Upload</button>
</form>
</body>
</html>
HTML Template (./templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Index</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/main.css') }}">
</head>
<body>
<h5>Gallery</h5>
<div id="gallery">
{% for img in images -%}
<div id="gallery-thumb-{{loop.index}}">
<img src="data:;base64,{{ img.b64encoded }}" />
<a href="#lightbox-{{ loop.index }}">{{ loop.index }}</a>
</div>
{% endfor -%}
</div>
{% for img in images -%}
<div id="lightbox-{{ loop.index }}">
<div >
<img src="data:;base64,{{ img.b64encoded }}" />
<a href="#gallery-thumb-{{loop.index}}"></a>
</div>
</div>
{% endfor -%}
</body>
</html>
CSS (./static/css/main.css)
* {
box-sizing: border-box;
}
body {
margin: 5px;
position: relative;
}
#gallery {
display: grid;
/* height: calc(100vh - 10px);*/ /* !!! */
grid-template: repeat(6, 1fr) / repeat(6, 1fr);
grid-gap: 0.5em;
}
@media (max-width: 800px) {
#gallery {
display: flex;
align-items: flex-start;
flex-wrap: wrap;
justify-content: center;
}
#gallery > div {
width: 48%;
margin: 1%;
}
}
@media (max-width: 800px) and (max-width: 350px) {
#gallery > div {
width: 98%;
}
}
#gallery > div:nth-child(6n 1) {
grid-column: span 2;
grid-row: span 2;
}
#gallery > div:nth-child(2) {
grid-column: span 3;
grid-row: span 3;
}
#gallery > div:nth-child(4) {
grid-column: span 1;
grid-row: span 2;
}
#gallery > div > a {
opacity: 0;
position: absolute;
color: #000;
background-color: #000;
font: bold 4em "Helvetica";
text-shadow: 0 -1px 5px #fff, -1px 0px 5px #fff, 0 1px 5px #fff, 1px 0px 5px #fff;
padding: 2rem;
mix-blend-mode: difference;
width: 100%;
height: 100%;
transition: all ease 1s;
}
#gallery > div > img {
width: 100%;
min-height: 100%;
transition: all ease 1s;
object-fit: cover; /* !!! */
}
#gallery > div:hover img {
filter: blur(4px);
}
#gallery > div:hover a {
opacity: 1;
}
#gallery > div {
overflow: hidden;
position: relative;
box-shadow: 0 2px 8px 0 rgba(0, 0, 0, 0.2), 0 3px 20px 0 rgba(0, 0, 0, 0.19);
}
#gallery div, #gallery a {
display: flex;
justify-content: center;
align-items: center;
text-decoration: none;
}
[id^="lightbox-"] {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
opacity: 0;
transition: opacity 450ms ease-in-out;
align-items: center;
justify-content: center;
pointer-events: none;
}
[id^="lightbox-"]:target {
opacity: 1;
pointer-events: inherit;
}
[id^="lightbox-"]:target img {
filter: blur(0);
}
[id^="lightbox-"] .content {
max-width: 90%;
position: relative;
color: #fff;
}
[id^="lightbox-"] .content:hover > a.close {
opacity: 1;
transform: scale(1, 1);
}
[id^="lightbox-"] .content:hover > .title {
opacity: 1;
transform: translateY(-3px);
}
[id^="lightbox-"] .content:hover > .title::after {
opacity: 1;
}
[id^="lightbox-"] .content > * {
transition: all 450ms ease-in-out;
}
[id^="lightbox-"] .title {
display: block;
margin: 0;
padding: 1em;
position: absolute;
bottom: 0;
width: 100%;
transform: translateY(50%);
font-size: 1.5em;
opacity: 0;
}
[id^="lightbox-"] .title::after {
content: ' ';
background-color: rgba(0, 0, 0, 0.4);
bottom: 0;
left: 0;
height: 100%;
width: 100%;
position: absolute;
transition: all 350ms ease-in-out 250ms;
opacity: 0;
transform-origin: bottom;
mix-blend-mode: soft-light;
}
[id^="lightbox-"] img {
max-height: 90vh;
max-width: 100%;
margin: 0;
padding: 0;
filter: blur(50px);
}
[id^="lightbox-"] a.close {
width: 2em;
height: 2em;
position: absolute;
right: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
transform: scale(0, 0);
opacity: 0;
transform-origin: right top;
text-decoration: none;
color: #fff;
}
[id^="lightbox-"] a.close::after {
content: "×";
}