iT邦幫忙

2024 iThome 鐵人賽

DAY 14
0
Python

Python自修系列 第 14

DAY14:優化用戶體驗

  • 分享至 

  • xImage
  •  

安裝matplotlib

pip install matplotlib
from flask import Flask, render_template, request, redirect, url_for, flash, send_file, session
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from flask_paginate import Pagination, get_page_parameter
import pandas as pd
import os
import io
import matplotlib.pyplot as plt
import base64

app = Flask(__name__)
app.config['SECRET_KEY'] = 'your_secret_key'
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['UPLOAD_FOLDER'] = 'uploads'

db = SQLAlchemy(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

# 用戶模型
class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(150), unique=True, nullable=False)
    password = db.Column(db.String(150), nullable=False)

# 上傳歷史模型
class UploadHistory(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    filename = db.Column(db.String(150), nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    timestamp = db.Column(db.DateTime, nullable=False)

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 在應用上下文內創建數據庫
with app.app_context():
    db.create_all()

# 根路由,處理上傳和顯示
@app.route('/', methods=['GET', 'POST'])
@login_required
def index():
    # 預設情況下,pagination 未定義
    pagination = None

    if request.method == 'POST':
        if 'file' not in request.files:
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            return redirect(request.url)
        if file:
            filepath = os.path.join(app.config['UPLOAD_FOLDER'], file.filename)
            file.save(filepath)
            
            # 保存上傳歷史記錄
            new_upload = UploadHistory(filename=file.filename, user_id=current_user.id, timestamp=pd.Timestamp.now())
            db.session.add(new_upload)
            db.session.commit()

            # 保存文件路徑供分頁使用
            session['filepath'] = filepath

            return redirect(url_for('index'))

    # 如果已經上傳文件,載入數據並分頁顯示
    filepath = session.get('filepath')
    if filepath:
        df = pd.read_csv(filepath)
        page = request.args.get('page', type=int, default=1)
        per_page = 10
        offset = (page - 1) * per_page
        paginated_df = df[offset:offset + per_page]

        # 創建 Pagination 對象
        pagination = Pagination(page=page, total=len(df), per_page=per_page, css_framework='bootstrap4')

        # 生成圖表
        img = io.BytesIO()
        plt.figure(figsize=(10, 6))
        plt.hist(df['image_count'], bins=20, color='blue', edgecolor='black')
        plt.title('數據分佈')
        plt.xlabel('值')
        plt.ylabel('頻率')
        plt.grid(True)
        plt.savefig(img, format='png')
        img.seek(0)
        plot_url = base64.b64encode(img.getvalue()).decode('utf8')

        return render_template('index.html', tables=[paginated_df.to_html(classes='data')], pagination=pagination, plot_url=plot_url)

    # 顯示上傳歷史記錄
    history = UploadHistory.query.filter_by(user_id=current_user.id).order_by(UploadHistory.timestamp.desc()).all()
    return render_template('index.html', history=history, pagination=pagination)

# 添加下載路由
@app.route('/download')
@login_required
def download():
    filepath = session.get('filepath')
    if filepath:
        return send_file(filepath, as_attachment=True)
    return redirect(url_for('index'))

if __name__ == '__main__':
    app.run(debug=True)


index.html

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PTT 文章分析結果</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
    <div class="container">
        <h1>PTT 文章數據分析結果</h1>

        <form action="/" method="post" enctype="multipart/form-data">
            <label for="file">上傳CSV文件:</label>
            <input type="file" name="file" id="file">
            <button type="submit">上傳並分析</button>
        </form>

        {% if tables %}
            <h2>分析結果</h2>
            {% for table in tables %}
                <div>{{ table|safe }}</div>
            {% endfor %}

            <h2>數據分佈圖</h2>
            <img src="data:image/png;base64,{{ plot_url }}" alt="數據分佈圖">

            <div>
                {{ pagination.links }}
            </div>
        {% endif %}

        {% if history %}
            <h2>上傳歷史</h2>
            <ul>
                {% for record in history %}
                    <li>{{ record.timestamp }} - {{ record.filename }}</li>
                {% endfor %}
            </ul>
        {% endif %}
    </div>
</body>
</html>


上一篇
DAY13:實現數據分頁
下一篇
DAY15:權限控制
系列文
Python自修30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言