I am making a site where you can send your game with multiple additional images. I upload images and they are send to API. Then when you open the game page there is a request to API and it returns the image. The problem is that when I try to upload multiple images only last one uploads. This is my html form
<code>{% extends "base.html" %}
<form id="chloroform" action="/senddata" method="post" enctype=multipart/form-data >
<legend>Основные данные</legend>
<label for="title">Название игры:</label>
<input type="text" name="title" id="title" maxlength="24" required>
<div class="container col-md-6" style="float:right; position: relative; top: -100px; left: 20px">
<p style="outline:2px solid #555; border-radius:5px; width: 300px; height: 300px;">
<img id="frame" src="" class="img-fluid" style="max-width: 300px; max-height: 300px; " />
<input class="form-control" name="prev" type="file" id="formFile" onchange="preview()" accept="image/png" required>
function checkImage(file) {
return new Promise((resolve, reject) => {
if (file.type === 'image/png') {
if (img.width === img.height) {
reject(new Error('Изображение должно быть квадратным!'));
img.src = URL.createObjectURL(file);
reject(new Error('Изображение должно быть в формате PNG!'));
const file = event.target.files[0];
const frame = document.getElementById('frame');
frame.src = URL.createObjectURL(file);
frame.style.display = 'block';
document.getElementById('formFile').value = null;
const frame = document.getElementById('frame');
frame.style.display = 'none';
<!-- THIS IS IMAGES WHERE I GET THE PROBLEM-->
<legend>Additional data</legend>
<textarea name="desc" placeholder="Brief description" id="desc" style="width: 312px; height: 150px;" required></textarea>
<legend for="file" class="form-label">Zip file </legend>
<input class="form-control form-control-lg" name="file" id="file" type="file" accept=".zip" required>
document.getElementById('file').onchange = function(e) {
if(!e.target.files[0].name.match(/.(zip)$/)) {
<legend for='files'>Select additional images: </legend>
<input id='files' type='file' class="btn btn-outline-info" name="files" accept="image/png" multiple>
<button type="submit">Submit</button>
<code>{% extends "base.html" %}
{% block body %}
<form id="chloroform" action="/senddata" method="post" enctype=multipart/form-data >
<h2>Загрузить игру</h2>
<fieldset>
<legend>Основные данные</legend>
<label for="title">Название игры:</label>
<input type="text" name="title" id="title" maxlength="24" required>
</fieldset>
<div class="container col-md-6" style="float:right; position: relative; top: -100px; left: 20px">
<p style="outline:2px solid #555; border-radius:5px; width: 300px; height: 300px;">
<img id="frame" src="" class="img-fluid" style="max-width: 300px; max-height: 300px; " />
</p>
<div class="mb-5">
<input class="form-control" name="prev" type="file" id="formFile" onchange="preview()" accept="image/png" required>
</div>
</div>
<script>
function checkImage(file) {
return new Promise((resolve, reject) => {
if (file.type === 'image/png') {
const img = new Image();
img.onload = () => {
if (img.width === img.height) {
resolve();
} else {
reject(new Error('Изображение должно быть квадратным!'));
}
};
img.src = URL.createObjectURL(file);
} else {
reject(new Error('Изображение должно быть в формате PNG!'));
}
});
}
function preview() {
const file = event.target.files[0];
checkImage(file)
.then(() => {
const frame = document.getElementById('frame');
frame.src = URL.createObjectURL(file);
frame.style.display = 'block';
})
.catch(error => {
alert(error.message);
document.getElementById('formFile').value = null;
const frame = document.getElementById('frame');
frame.src = '';
frame.style.display = 'none';
});
}
</script>
<!-- THIS IS IMAGES WHERE I GET THE PROBLEM-->
<fieldset>
<legend>Additional data</legend>
<div>
<textarea name="desc" placeholder="Brief description" id="desc" style="width: 312px; height: 150px;" required></textarea>
</div>
<div>
</div>
</fieldset>
<fieldset>
<div>
<legend for="file" class="form-label">Zip file </legend>
<input class="form-control form-control-lg" name="file" id="file" type="file" accept=".zip" required>
<script>
document.getElementById('file').onchange = function(e) {
if(!e.target.files[0].name.match(/.(zip)$/)) {
alert('Only .zip!');
e.target.value = '';
}
};
</script>
</div>
<div>
<legend for='files'>Select additional images: </legend>
<label>Only png!</label>
<input id='files' type='file' class="btn btn-outline-info" name="files" accept="image/png" multiple>
</div>
</fieldset>
<div>
<button type="submit">Submit</button>
</div>
</form>
{% endblock %}
</code>
{% extends "base.html" %}
{% block body %}
<form id="chloroform" action="/senddata" method="post" enctype=multipart/form-data >
<h2>Загрузить игру</h2>
<fieldset>
<legend>Основные данные</legend>
<label for="title">Название игры:</label>
<input type="text" name="title" id="title" maxlength="24" required>
</fieldset>
<div class="container col-md-6" style="float:right; position: relative; top: -100px; left: 20px">
<p style="outline:2px solid #555; border-radius:5px; width: 300px; height: 300px;">
<img id="frame" src="" class="img-fluid" style="max-width: 300px; max-height: 300px; " />
</p>
<div class="mb-5">
<input class="form-control" name="prev" type="file" id="formFile" onchange="preview()" accept="image/png" required>
</div>
</div>
<script>
function checkImage(file) {
return new Promise((resolve, reject) => {
if (file.type === 'image/png') {
const img = new Image();
img.onload = () => {
if (img.width === img.height) {
resolve();
} else {
reject(new Error('Изображение должно быть квадратным!'));
}
};
img.src = URL.createObjectURL(file);
} else {
reject(new Error('Изображение должно быть в формате PNG!'));
}
});
}
function preview() {
const file = event.target.files[0];
checkImage(file)
.then(() => {
const frame = document.getElementById('frame');
frame.src = URL.createObjectURL(file);
frame.style.display = 'block';
})
.catch(error => {
alert(error.message);
document.getElementById('formFile').value = null;
const frame = document.getElementById('frame');
frame.src = '';
frame.style.display = 'none';
});
}
</script>
<!-- THIS IS IMAGES WHERE I GET THE PROBLEM-->
<fieldset>
<legend>Additional data</legend>
<div>
<textarea name="desc" placeholder="Brief description" id="desc" style="width: 312px; height: 150px;" required></textarea>
</div>
<div>
</div>
</fieldset>
<fieldset>
<div>
<legend for="file" class="form-label">Zip file </legend>
<input class="form-control form-control-lg" name="file" id="file" type="file" accept=".zip" required>
<script>
document.getElementById('file').onchange = function(e) {
if(!e.target.files[0].name.match(/.(zip)$/)) {
alert('Only .zip!');
e.target.value = '';
}
};
</script>
</div>
<div>
<legend for='files'>Select additional images: </legend>
<label>Only png!</label>
<input id='files' type='file' class="btn btn-outline-info" name="files" accept="image/png" multiple>
</div>
</fieldset>
<div>
<button type="submit">Submit</button>
</div>
</form>
{% endblock %}
And here i try to retrieve the data
<code>@app.route('/senddata', methods=['POST', 'GET'])
if request.method == 'POST':
title = request.form.get('title')
desc = request.form.get('desc', '')
author = int(current_user.get_id())
prev_file = request.files['prev']
zip_file = request.files['file']
files = request.files.getlist('files')
if not prev_file.filename.endswith('.png'):
prev_file = open('url_for(static, filename=images/default.png)', 'rb')
if file.filename.lower().endswith('.png'):
images.append(("png", file.read()))
"prev": ("png", prev_file.read()),
"file": ("zip", zip_file.read()),
requests.post(url, data=pickle.dumps(data)).json()
return redirect('/index')
<code>@app.route('/senddata', methods=['POST', 'GET'])
def senddata():
url = f"{api_url}/games"
if request.method == 'POST':
title = request.form.get('title')
desc = request.form.get('desc', '')
author = int(current_user.get_id())
prev_file = request.files['prev']
zip_file = request.files['file']
files = request.files.getlist('files')
if not prev_file.filename.endswith('.png'):
prev_file = open('url_for(static, filename=images/default.png)', 'rb')
images = []
for file in files:
if file.filename.lower().endswith('.png'):
images.append(("png", file.read()))
print('Check')
data = {
"title": title,
"desc": desc,
"author": author,
"prev": ("png", prev_file.read()),
"file": ("zip", zip_file.read()),
"images": images
}
requests.post(url, data=pickle.dumps(data)).json()
return redirect('/index')
</code>
@app.route('/senddata', methods=['POST', 'GET'])
def senddata():
url = f"{api_url}/games"
if request.method == 'POST':
title = request.form.get('title')
desc = request.form.get('desc', '')
author = int(current_user.get_id())
prev_file = request.files['prev']
zip_file = request.files['file']
files = request.files.getlist('files')
if not prev_file.filename.endswith('.png'):
prev_file = open('url_for(static, filename=images/default.png)', 'rb')
images = []
for file in files:
if file.filename.lower().endswith('.png'):
images.append(("png", file.read()))
print('Check')
data = {
"title": title,
"desc": desc,
"author": author,
"prev": ("png", prev_file.read()),
"file": ("zip", zip_file.read()),
"images": images
}
requests.post(url, data=pickle.dumps(data)).json()
return redirect('/index')
And here I try to use the data
<code><div id="info" style="width: 48vw">
<p id="infoframe" style="outline:2px solid #555; border-radius:5px; width: 100%; min-height: 15vw;">
<div id="imgframe" style="width: 100%">
<div id="images" class="carousel slide carousel-fade" data-bs-ride="carousel" style="width: max-content; margin: auto">
<div class="carousel-inner">
{% for image in game['images'] %}
<div class="carousel-item {% if loop.first %}active{% endif %}">
<img src="{{api_url}}/file?p={{image['img']}}" class="d-block w-100" style="max-width: 20vw;max-height: 20vw;">
<button class="carousel-control-prev" type="button" data-bs-target="#images" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Предыдущая</span>
<button class="carousel-control-next" type="button" data-bs-target="#images" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Следующая</span>
<code><div id="info" style="width: 48vw">
<p id="infoframe" style="outline:2px solid #555; border-radius:5px; width: 100%; min-height: 15vw;">
{{game['desc']}}
</p>
<div id="imgframe" style="width: 100%">
<div id="images" class="carousel slide carousel-fade" data-bs-ride="carousel" style="width: max-content; margin: auto">
<div class="carousel-inner">
{% for image in game['images'] %}
<div class="carousel-item {% if loop.first %}active{% endif %}">
<img src="{{api_url}}/file?p={{image['img']}}" class="d-block w-100" style="max-width: 20vw;max-height: 20vw;">
</div>
{% endfor %}
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#images" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Предыдущая</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#images" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Следующая</span>
</button>
</div>
</div>
</div>
</code>
<div id="info" style="width: 48vw">
<p id="infoframe" style="outline:2px solid #555; border-radius:5px; width: 100%; min-height: 15vw;">
{{game['desc']}}
</p>
<div id="imgframe" style="width: 100%">
<div id="images" class="carousel slide carousel-fade" data-bs-ride="carousel" style="width: max-content; margin: auto">
<div class="carousel-inner">
{% for image in game['images'] %}
<div class="carousel-item {% if loop.first %}active{% endif %}">
<img src="{{api_url}}/file?p={{image['img']}}" class="d-block w-100" style="max-width: 20vw;max-height: 20vw;">
</div>
{% endfor %}
</div>
<button class="carousel-control-prev" type="button" data-bs-target="#images" data-bs-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="visually-hidden">Предыдущая</span>
</button>
<button class="carousel-control-next" type="button" data-bs-target="#images" data-bs-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="visually-hidden">Следующая</span>
</button>
</div>
</div>
</div>
I am kind of a newbie to python and html so I kind of do not understand how this works and why it doesn’t work as inteded.
I have seen that I need multiple so I used it in
<code><input id='files' type='file' class="btn btn-outline-info" name="files" accept="image/png" multiple>
<code><input id='files' type='file' class="btn btn-outline-info" name="files" accept="image/png" multiple>
</code>
<input id='files' type='file' class="btn btn-outline-info" name="files" accept="image/png" multiple>
but it still sent only the last image