flask file upload working
This commit is contained in:
parent
71815a6533
commit
f11dd091f1
4
backend/.env
Normal file
4
backend/.env
Normal file
@ -0,0 +1,4 @@
|
||||
SECRET_KEY=MVPhXY*yNXPE2MbXDdpxXk
|
||||
REDIS_PASSWORD=eYVX7EwVmmxKPCDmwMtyKVge8oLd2t81
|
||||
POSTGRESQL_DATABASE_URL='postgresql+psycopg2://arufa:Plop2099@localhost:5432/arufalab'
|
||||
# POSTGRESQL_DATABASE_URL => 'postgresql+psycopg2://arufa:password@host:port/database'
|
||||
BIN
backend/__pycache__/config.cpython-312.pyc
Normal file
BIN
backend/__pycache__/config.cpython-312.pyc
Normal file
Binary file not shown.
BIN
backend/__pycache__/models.cpython-312.pyc
Normal file
BIN
backend/__pycache__/models.cpython-312.pyc
Normal file
Binary file not shown.
@ -21,8 +21,16 @@ app.config["SESSION_TYPE"] = 'redis'
|
||||
app.config["SESSION_PERMANENT"] = False
|
||||
app.config["SESSION_USE_SIGNER"] = True
|
||||
app.config["SESSION_REDIS"] = redis.from_url("redis://192.168.50.107:6379")
|
||||
# upload directory
|
||||
app.config["UPLOAD_DIRECTORY"] = 'uploads/'
|
||||
# app.config["REDIS_PASSWORD"] = os.environ["REDIS_PASSWORD"]
|
||||
|
||||
# File value limit
|
||||
app.config["MAX_CONTENT_LENGTH"] = 16 * 1024 * 1024 # 16MB
|
||||
|
||||
# List of allowed file extensions
|
||||
app.config['ALLOWED_EXTENSIONS'] = ['.jpg', '.jpeg', '.png', '.gif']
|
||||
|
||||
db = SQLAlchemy(app)
|
||||
|
||||
server_session = Session(app)
|
||||
|
||||
BIN
backend/instance/mydatabase.db
Normal file
BIN
backend/instance/mydatabase.db
Normal file
Binary file not shown.
@ -1,16 +1,45 @@
|
||||
from flask import Flask, render_template, request
|
||||
from flask import Flask, render_template, request, redirect, send_from_directory
|
||||
from config import app, db, bcrypt
|
||||
from models import Contact, User
|
||||
from werkzeug.utils import secure_filename
|
||||
from werkzeug.exceptions import RequestEntityTooLarge
|
||||
import os
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
files = os.listdir(app.config['UPLOAD_DIRECTORY'])
|
||||
images = []
|
||||
|
||||
@app.route('/api/upload', methods=['POST'])
|
||||
for file in files:
|
||||
if os.path.splitext(file)[1].lower() in app.config['ALLOWED_EXTENSIONS']:
|
||||
images.append(file)
|
||||
return render_template('index.html', images=images)
|
||||
|
||||
@app.route('/upload', methods=["POST"])
|
||||
def upload():
|
||||
file = request.files['file']
|
||||
try:
|
||||
file = request.files['file']
|
||||
file_extension = os.path.splitext(file.filename)[1] # [0] is the filename
|
||||
|
||||
# save the file if it exists
|
||||
if file:
|
||||
if file_extension not in app.config['ALLOWED_EXTENSIONS']:
|
||||
return 'File is not an image'
|
||||
file.save(os.path.join(
|
||||
app.config['UPLOAD_DIRECTORY'],
|
||||
secure_filename(file.filename)
|
||||
))
|
||||
except RequestEntityTooLarge: # except Exception would catch all errors instead of specified
|
||||
return 'File is larger than the limit of 16mb.'
|
||||
|
||||
return redirect('/')
|
||||
|
||||
# Handle Images
|
||||
@app.route('/serve-image/<filename>', methods=['GET'])
|
||||
def serve_image(filename):
|
||||
return send_from_directory(app.config['UPLOAD_DIRECTORY'], filename)
|
||||
|
||||
# save the file
|
||||
file.save(f'uploads/{file.filename}')
|
||||
|
||||
# Main
|
||||
if __name__ == "__main__":
|
||||
|
||||
34
backend/models.py
Normal file
34
backend/models.py
Normal file
@ -0,0 +1,34 @@
|
||||
from config import db
|
||||
from uuid import uuid4
|
||||
|
||||
class Contact(db.Model):
|
||||
id = db.Column(db.Integer, primary_key=True)
|
||||
first_name = db.Column(db.String(80), unique=False, nullable=False)
|
||||
last_name = db.Column(db.String(80), unique=False, nullable=False)
|
||||
email = db.Column(db.String(120), unique=False, nullable=False)
|
||||
|
||||
def to_json(self):
|
||||
return {
|
||||
"id": self.id,
|
||||
"firstName":self.first_name,
|
||||
"lastName":self.last_name,
|
||||
"email": self.email,
|
||||
}
|
||||
|
||||
|
||||
def get_uuid():
|
||||
return uuid4().hex
|
||||
|
||||
class User(db.Model):
|
||||
__tablename__ = "users"
|
||||
id = db.Column(db.String(32), primary_key=True, unique=True, default=get_uuid)
|
||||
email = db.Column(db.String(345), unique=True)
|
||||
password = db.Column(db.Text, nullable=False)
|
||||
|
||||
# class Category(db.Model):
|
||||
# __tablename__ = "categories"
|
||||
# id = db.Column(db.String(32), primary_key=True, unique=True, default=get_uuid)
|
||||
# name = db.Column(db.String(345), default='New Shirt')
|
||||
# number = db.Column(db.Integer)
|
||||
# sale = db.Column(db.Boolean, default=False)
|
||||
|
||||
@ -5,3 +5,6 @@ flask-cors
|
||||
python-dotenv
|
||||
flask-session
|
||||
redis
|
||||
Flask-Migrate
|
||||
flask_validator
|
||||
psycopg2-binary
|
||||
130
backend/static/styles.css
Normal file
130
backend/static/styles.css
Normal file
@ -0,0 +1,130 @@
|
||||
:root {
|
||||
--black: #000000;
|
||||
--almost-black: #080708;
|
||||
--blue: #3772FF;
|
||||
--blue-light: #3787ff;
|
||||
--red: #DF2935;
|
||||
--yellow: #FDCA40;
|
||||
--light: #E6E8E6;
|
||||
--white: #FFFFFF;
|
||||
}
|
||||
|
||||
* {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
font-size: 22px;
|
||||
line-height: 1.5;
|
||||
color: var(--white);
|
||||
background: var(--black);
|
||||
background-image: linear-gradient(to bottom right, var(--almost-black), var(--black));
|
||||
}
|
||||
|
||||
.app {
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding: 15px 0 0 15px;
|
||||
width: 25%;
|
||||
color: var(--light);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.images-section {
|
||||
padding: 15px 0 0 15px;
|
||||
width: 75%;
|
||||
height: 100vh;
|
||||
align-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.images-section a {
|
||||
margin: 0 15px 15px 0;
|
||||
padding-bottom: 20%;
|
||||
content: '';
|
||||
width: calc(33.33% - 15px);
|
||||
height: 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.images-section img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 4px;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 1200px) {
|
||||
|
||||
.app {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.form-section {
|
||||
padding-right: 15px;
|
||||
padding-bottom: 15px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.images-section {
|
||||
padding-top: 0;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px) {
|
||||
|
||||
.images-section a {
|
||||
padding-bottom: 60%;
|
||||
width: calc(100% - 15px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
form {
|
||||
width: 100%;
|
||||
flex-direction: column;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
input[type='file'] {
|
||||
margin: 0 0 12px;
|
||||
padding: 10px 10px;
|
||||
border-radius: 4px;
|
||||
font-size: 22px;
|
||||
color: var(--almost-black);
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
input[type='submit'],
|
||||
button[type='button'] {
|
||||
padding: 13px 20px;
|
||||
font-size: 22px;
|
||||
font-weight: bold;
|
||||
color: var(--white);
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
background: var(--blue);
|
||||
background-image: linear-gradient(to bottom, var(--blue-light), var(--blue));
|
||||
transition: box-shadow .2s ease;
|
||||
}
|
||||
|
||||
input[type='submit']:hover,
|
||||
button[type='button']:hover {
|
||||
box-shadow: inset 0 -25px 25px var(--blue-light);
|
||||
}
|
||||
@ -11,20 +11,20 @@
|
||||
<div class="app">
|
||||
|
||||
<div class="form-section">
|
||||
<form aciton="/api/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="file">
|
||||
<input type="submit" name="Upload">
|
||||
|
||||
</form>
|
||||
|
||||
<!-- Form will go here -->
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="file">
|
||||
<input type="submit" value="Upload">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="images-section">
|
||||
|
||||
<!-- Images will go here -->
|
||||
|
||||
{% for image in images %}
|
||||
<a href="{{ url_for('serve_image', filename=image) }}" target="_blank">
|
||||
<img src="{{ url_for('serve_image', filename=image) }}"/>
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user