【Flask】Flask项目结构初识

1.前提准备

  • Python版本

    # python 3.8.0
    # 查看Python版本
    python --version
  • 安装第三方 Flask

    pip install flask
    # 如果安装失败,可以使用 -i,指定使用国内镜像源
    # 清华镜像源:https://pypi.tuna.tsinghua.edu.cn/simple/

  • 检查 Flask 是否安装成功

    flask --version
  • Flask官网

    # 官网:https://flask.palletsprojects.com
    # 快速开始:https://flask.palletsprojects.com/en/3.0.x/quickstart/

2.一个简单的Flask程序

  1. 创建 Flask 项目目录。

    mkdir FlaskMarket

  2. 创建 app 文件。

    from flask import Flask
    ​
    app = Flask(__name__)
    ​
    @app.route("/")
    def hello_world():
        return "<p>Hello, World!</p>"

  3. 运行 Flask

    flask --app market run
    # 设置环境变量,也能够直接运行flask
    $env:FLASK_APP="market.py"
    flask run

    查看web页面

    Debug 模式

    # 运行flask项目时,在最后加--debug,以debug模式启动
    $env:FLASK_APP="market.py"
    flask run --debug

    以下是代码产生报错的截图

  4. 新增一个路由。

    # 路由传参username
    @app.route("/about/<username>")
    def about_page(username):
        return f"<h1>this is about {username} page</h1>"

    页面查询结果

3.Template模板文件

可以在Flask项目的目录下创建 templates 目录存放所会用的 html 文件,具体如下:

在Python代码中,直接返回 html 文件即可,不需要携带目录。

@app.route("/")
def hello_world():
    return render_template("hello.html")

页面访问如下

4.数据发送到template

Jinjia2 是一个仿照 Django 模板的 Python 模板语句,实现了后端与模板之间的交互。

  1. 一个简单的数据交互。

    后端 python 这样写:

    @app.route("/")
    def hello_world():
        return render_template("home.html", item_name="Phone")

    对应的前端 html 文件需要使用 jiajia2 的语法接收变量,代码如下:

    <p>{{item_name}}</p>

    页面效果如下:

  1. 列表数据交互。

    后端 python 这样写:

    @app.route("/")
    def hello_world():
        items = [
            {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
            {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
            {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
        ]
        return render_template("home.html", items=items)

    对应的前端 html 这样接收:

    <table class="table table-hover table-dark">
        <thead>
            <tr>
                <th scope="col">ID</th>
                <th scope="col">Name</th>
                <th scope="col">Barcode</th>
                <th scope="col">Price</th>
            </tr>
        </thead>
        <tbody>
            {% for item in items %}
            <tr>
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td>{{item.barcode}}</td>
                <td>{{item.price}}</td>
            </tr>
            {% endfor %}
        </tbody>
    </table>

    访问页面如下:

5.Template 继承

开发的网站可能涉及多个页面,需要抽取公共的内容,其余的 html 页面继承这些公共内容即可。

  1. 引入 base.html 文件。

    <!doctype html>
    <html lang="en">
       <head>
          <!-- Required meta tags -->
          <meta charset="utf-8">
          <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
          <!-- Bootstrap CSS -->
          <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
          <title>Base Title</title>
       </head>
       <body>
          <!-- Navbar here -->
          <nav class="navbar navbar-expand-md navbar-dark bg-dark">
          <a class="navbar-brand" href="#">EuanSu Coding Market</a>
          <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="*navbarNav">
            <span class="navbar-toggler-icon"></span>
          </button>
          <div class="collapse navbar-collapse" id="navbarNav">
            <ul class="navbar-nav mr-auto">
              <li class="nav-item active">
                <a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Market</a>
              </li>
            </ul>
            <ul class="navbar-nav">
              <li class="nav-item">
                <a class="nav-link" href="#">Login</a>
              </li>
              <li class="nav-item">
                <a class="nav-link" href="#">Register</a>
              </li>
            </ul>
          </div>
    ​
        </nav>
          <!-- Future Content here -->
    ​
    ​
    ​
    ​
          <!-- Optional JavaScript -->
          <!-- jQuery first, then Popper.js, then Bootstrap JS -->
          <script src='https://kit.fontawesome.com/a076d05399.js'></script>
          <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
          <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
          <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
       </body>
       <style>
          body {
          background-color: #212121;
          color: white
          }
       </style>
    </html>

  2. 清空 home.html 原文件,修改为如下内容:

    {% extends "base.html" %}

  3. 访问页面如下:

    这里有一个问题就是页面标题显示为 Base Title ,实际上每个页面的标题是不一样,这里可以通过 block 语句进行修改,代码如下:

    修改 base.html 文件 head 下的 title 标签为如下内容:

    <head>
        ...
        <title>
            {% block title%}
            {% endblock %}
        </title>
    </head>

    修改 home.html 为如下内容:

    {% extends "base.html" %}
    {% block title%}
    Home Page
    {% endblock %}

    再次刷新页面,title 的内容被替换。

  4. 替换 html 文件 body 下的内容:

    首先是修改 base.htmlbody 的内容,修改如下:

    {% block content%}
    {% endblock %}

    修改 market.html 为如下内容:

    {% extends "base.html" %}
    {% block title%}
    Market Page
    {% endblock %}
    {% block content%}
    <table class="table table-hover table-dark">
          <thead>
          <tr>
            <th scope="col">ID</th>
            <th scope="col">Name</th>
            <th scope="col">Barcode</th>
            <th scope="col">Price</th>
          </tr>
          </thead>
          <tbody>
            {% for item in items %}
              <tr>
                <td>{{item.id}}</td>
                <td>{{item.name}}</td>
                <td>{{item.barcode}}</td>
                <td>{{item.price}}</td>
                <td>
                  <button class="btn btn-outline btn-info">More Info</button>
                  <button class="btn btn-outline btn-success">Purchase this Item</button>
                </td>
              </tr>
            {% endfor %}
          </tbody>
        </table>
    {% endblock %}

    访问页面,能够正常对数据进行渲染。

  1. 页面跳转

    html 文件的 href 进行跳转,这里需要使用 jinjia2 的语法,而不能直接使用路由。

    <a class="nav-link" href="{{ url_for('home_page') }}">Home <span class="sr-only">(current)</span></a>
    <a class="nav-link" href="{{ url_for('market_page') }}">Market</a>

    其中的 market_page 是路由关联的函数,如下所示:

    @app.route("/")
    def home_page():
        items = [
            {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
            {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
            {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
        ]
        return render_template("home.html", items=items)
    ​
    ​
    @app.route("/market")
    def market_page():
        items = [
            {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
            {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
            {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
        ]
        return render_template("market.html", items=items)

    再次点击页面的按钮,能够正常进行路由跳转。

6.数据库模型

6.1 数据库模型的基本使用

安装 flask-sqlalchemy 第三方包。

pip install flask-sqlalchemy

python 文件导入 flask-sqlalchemy 库。

from flask_sqlalchemy import SQLAlchemy
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///market.sqlite'
db = SQLAlchemy(app)

编写模型类。

class Item(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(length=30),nullable=False, unique=True)
    price = db.Column(db.Integer(), nullable=True)
    barcode = db.Column(db.String(length=12), nullable=True, unique=True)
    description = db.Column(db.String(length=1024), nullable=True, unique=True)

需要在 Flaskapp 文件中,添加数据库初始化操作。

with app.app_context():
    db.create_all()

使用可视化工具查看 SQLite 本地数据库文件,出现初始化的 Item 表。

6.2 SQLAlchemy 的基本使用

新增数据库记录

item1 =  Item(name="OPPO Find X6 Pro",price=5000,barcode='123456789',description='OPPO Find X6 Pro')
with app.app_context():
    db.session.add(item1)
    db.session.commit()

执行如上语句后,数据库中出现一条手机记录。

查询数据库记录

# 全量查询
result = Item.query.all()
print(result)
for item in result:
    print(item.name)

# 根据条件过滤
result = Item.query.filter_by(name='OPPO Find X6 Pro')
print(result)
print('=============')
for item in result:
    print(item.name)

修改数据库记录

result = Item.query.filter_by(name='OPPO Find X6 Pro')
if result:
    item = result[0]
    item.price = 5999
    db.session.commit()

修改后,数据库中的记录发生了变化。

删除数据库记录

# 查询要删除的记录
record_to_delete = Item.query.filter_by(name="OnePlus 12").first()
# 如果记录存在,则删除
if record_to_delete:
    db.session.delete(record_to_delete)
    db.session.commit()

这里的数据库查询放到代码中,如下:

@app.route("/market")
def market_page():
    items = [
        {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
        {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
        {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
    ]
    items = Item.query.all()
    return render_template("market.html", items=items)

页面就能够直接展示数据库中的记录

7.项目重构

# 这里将项目移动至mark目录下,主目录下仅留项目的启动文件 run.py
D:\CODE\PYTHON\FLASKMARKET
├─instance
├─market
│  ├─templates
│  │  ├─css
│  │  ├─js
│  │  ├─base.html
│  │  ├─home.html
│  │  └─market.html
│  ├─__init__.py
│  ├─models.py
│  ├─routes.py
│  └─__pycache__
├─run.py
└─__pycache__

修改后的各文件一次如下所示:

__init__.py 模块初始化文件:

from flask import Flask, render_template
from flask_sqlalchemy import SQLAlchemy
​
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///market.sqlite'
db = SQLAlchemy(app)
​
from market import routes

models.py 模型文件:

from market import db
class Item(db.Model):
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(length=30),nullable=False, unique=True)
    price = db.Column(db.Integer(), nullable=True)
    barcode = db.Column(db.String(length=12), nullable=True, unique=True)
    description = db.Column(db.String(length=1024), nullable=True, unique=True)

routes.py 路由文件:

from market import app
from flask import render_template
from market.models import Item
@app.route("/")
@app.route("/home")
def home_page():
    items = [
        {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
        {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
        {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
    ]
    return render_template("home.html", items=items)
​
​
@app.route("/market")
def market_page():
    items = [
        {"id": 1, "name": "Phone", "barcode": 123456789, "price": 500},
        {"id": 2, "name": "Laptop", "barcode": 123654789, "price": 500},
        {"id": 3, "name": "keybord", "barcode": 123456987, "price": 150},
    ]
    items = Item.query.all()
    return render_template("market.html", items=items)

再次启动项目:

页面能够正常访问

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/477365.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络: 网络层

IP地址: 分为网络号和主机号. 用来标识主机 IP协议 IP协议报文 4位版本号(version): 指定IP协议的版本, 对于IPv4来说, 就是4.4位头部长度(header length): IP头部的长度是多少个32bit, 也就是 length * 4 的字节数. 4bit表示最大的数字是15, 因此IP头部最大长度是60字节. 8…

传输介质介绍,数据链路层,MAC地址的构成和作用

简单网络 1.网卡 2.物理介质 3.协议栈 双绞线&#xff1a; UTP 非屏蔽双绞线 屏蔽式双绞线 水晶头 串口电缆&#xff1a;连接运营商 广域网一个用户接入到广域网&#xff0c;早期来讲&#xff0c;光纤 物理层&#xff1a;本质是通信&#xff0c;数据传输&#xff0c;介质产…

数据结构02:线性表 链表习题01[C++]

考研笔记整理~&#x1f95d;&#x1f95d; 之前的博文链接在此&#xff1a;数据结构02&#xff1a;线性表[顺序表链表]_线性链表-CSDN博客~&#x1f95d;&#x1f95d; 本篇作为链表的代码补充&#xff0c;供小伙伴们参考~&#x1f95d;&#x1f95d; 第1版&#xff1a;王道…

3.21小题总结

第一题&#xff1a;生日蛋糕 题解&#xff1a;这题是蛋糕结构是一层一层的&#xff0c;估计很多人很快就能想到是dfs&#xff0c;但是这题的难想的点在于 你每层的状态该怎么去确定&#xff0c;你怎么来确定每层的半径和高度是多少&#xff0c;一开始我也不知很理解&#xff0…

计算结构体的大小(结构体的内存对齐)

一&#xff1a;问题 问题所在&#xff1a;两个结构体应该都是6个字节大小&#xff0c;为什么一个12&#xff0c;一个6&#xff1f;&#xff1f;&#xff1f; 二&#xff1a;如何正确的计算结构体大小&#xff1f; 首先得掌握结构体的对齐规则&#xff1a; 第一&#xff1a; 第一…

Leetcode 994. 腐烂的橘子

心路历程&#xff1a; 一开始以为和刚做过的岛屿问题很像&#xff0c;只不过是把岛屿问题换成BFS去做&#xff0c;然后再加上一些计数的规则。结果做完后发现只能通过一半左右的测试用例&#xff0c;发现有一个逻辑错误在于&#xff0c;当腐烂的橘子位于两端时&#xff0c;可以…

约数(因数)问题(ACwing算法笔记)

869.试除法求约数 注意点&#xff1a; 1.试除法就是让i遍历的最大值到a/i。 2.约数成对存在&#xff0c;只遍历前一部分即可。 代码&#xff1a; #include<iostream> #include<queue> #include<algorithm> #include<cstring> #include<cmath>…

Go语言学习04~05 函数和面向对象编程

Go语言学习04-函数 函数是一等公民 <font color"Blue">与其他主要编程语言的差异</font> 可以有多个返回值所有参数都是值传递: slice, map, channel 会有传引用的错觉函数可以作为变量的值函数可以作为参数和返回值 学习函数式编程 可变参数 func s…

刷题28-30(力扣0322/0078/0221)

0322. 零钱兑换 题目&#xff1a; 给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。你可以…

LLM - 大语言模型的分布式训练 概述

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://blog.csdn.net/caroline_wendy/article/details/136924304 大语言模型的分布式训练是一个复杂的过程&#xff0c;涉及到将大规模的计算任务分散到多个计算节点上。这样做的目的是为了处…

java面试:常见的限流算法有哪些

1 什么是限流算法 限流算法是一种用于限制流量请求的频率或速率的算法&#xff0c;其目的是在高并发或大流量请求的情况下&#xff0c;保护系统服务的安全性和可用性。限流算法可以应对热点业务带来的突发请求、调用方bug导致的突发请求以及恶意攻击请求等情况。是一种系统保护…

10W字解析 SpringBoot技术内幕文档,实战+原理齐飞,spring事务实现原理面试

第3章&#xff0c;Spring Boot构造流程源码分析&#xff0c;Spring Boot的启动非常简单&#xff0c;只需执行一个简单的main方法即可&#xff0c;但在整个main方法中&#xff0c;Spring Boot都做了些什么呢&#xff1f;本章会为大家详细讲解Spring Boot启动过程中所涉及的源代码…

《深入解析 C#》—— C# 3 部分

文章目录 第三章 C#3&#xff1a;LINQ及相关特性3.1 自动实现属性&#xff08;*&#xff09;3.2 隐式类型 var&#xff08;*&#xff09;3.3 对象和集合初始化3.3.1 对象初始化器3.3.2 集合初始化器 3.4 匿名类型3.4.1 基本语法和行为3.4.2 编译器生成类型3.4.3 匿名类型的局限…

Linux信号补充——信号捕捉处理

一、信号的捕捉处理 ​ 信号保存后会在合适的时间进行处理&#xff1b; 1.1信号处理时间 ​ 进程会在操作系统的调度下处理信号&#xff0c;操作系统只管发信号&#xff0c;即信号处理是由进程完成的&#xff1b; ​ 1.信号处理首先进程得检查是否有信号&#xff1b;2.进程…

双指针(对撞指针、快慢指针)

本博客将讲述OJ题中的常用的双指针 双指针的含义 双指针算法是一种常用的算法技巧&#xff0c;它通常用于在数组或字符串中进行快速查找、匹配、排序或移动操作。 双指针并非真的用指针实现&#xff0c;一般用两个变量来表示下标&#xff08;在后面都用指针来表示)。双指针算…

QML TextField 默认无法鼠标选中内容

1.import QtQuick.Controls 2.0 后的TextField默认无法选中内容如下图&#xff1a; 2.增加属性设置 selectByMouse: true 可以选中内容了 TextField{ selectByMouse: true text:"1234567890987654321" } 效果如下:

多线程(JUC, ReentrantLock, 原子类, 线程池, 信号量 Semaphore, CountDownLatch)

JUC Java.util.concurrent 包, 存放了并发编程相关的组件, 目的是更好的支持高并发任务 (多线程只是实现并发编程的一种具体方式 …) ReentrantLock 可重入互斥锁, 和 synchronized 定位类似, 用来实现互斥效果, 保证线程安全. synchronized 对对象加锁, 保护临界资源Reentreat…

面向量产!基于视觉的速度距离估计

面向量产&#xff01;基于视觉的速度距离估计 论文名称&#xff1a;Vision-based Vehicle Speed Estimation: A Survey 导读 在精确检测车速车距的方案中&#xff0c;视觉方案是非常具有挑战性的&#xff0c;但由于没有昂贵的距离传感器而大幅降低成本&#xff0c;所以潜力巨…

【现代C++】范围基于的for循环

现代C中的范围基于的for循环&#xff08;range-based for loop&#xff09;是C11引入的一项特性&#xff0c;旨在简化对容器或范围的迭代过程。这种循环语法不仅使代码更清晰易读&#xff0c;还减少了迭代时的错误。以下是范围基于的for循环的详细介绍&#xff1a; 1. 基本用法…

Vue3的与2的简单区别

Vue2选项式api Vue3组合式API setup方法的使用&#xff0c;最后需要return setup语法糖省略了内部的export default{} 和return 内容 以及组件的注册 reactive生成响应式对象&#xff0c;只能适用于复杂对象&#xff0c;简单类型不可 ref生成响应式数据&#xff1a;复杂类型和简…