Python高级技术之:`Python`的`Web`框架:`Django`、`Flask`和`FastAPI`的架构对比。

各位好,今天咱们来聊聊Python Web开发的三驾马车:Django、Flask 和 FastAPI。这仨框架,就像武林中的三大门派,各有各的招式和特点,咱们今天就来好好扒一扒它们的架构,看看谁更适合你的项目。

(开场白结束,直接进入正题)

一、Django:全能选手,开箱即用

Django,江湖人称“重型武器”,或者“瑞士军刀”。它最大的特点就是“啥都有”,你需要的,它基本都给你准备好了。

1. 架构:MVT (Model-View-Template)

Django 采用的是 MVT 架构,乍一看有点像 MVC (Model-View-Controller),但实际上还是有些区别的。

  • Model (模型): 负责数据管理,定义数据结构,处理数据库交互。简单来说,就是告诉 Django,你的数据长啥样,怎么存,怎么取。

    # models.py
    from django.db import models
    
    class Article(models.Model):
        title = models.CharField(max_length=200)
        content = models.TextField()
        pub_date = models.DateTimeField('date published')
    
        def __str__(self):
            return self.title

    这段代码定义了一个 Article 模型,包含了标题、内容和发布日期。 Django 会根据这个模型自动创建数据库表。

  • View (视图): 负责处理用户请求,调用 Model 获取数据,并将数据传递给 Template 进行渲染。 视图就像一个中间人,连接数据和展示。

    # views.py
    from django.shortcuts import render
    from .models import Article
    
    def article_list(request):
        articles = Article.objects.all()
        return render(request, 'article_list.html', {'articles': articles})

    这个 article_list 视图从数据库获取所有文章,并将它们传递给 article_list.html 模板进行渲染。

  • Template (模板): 负责展示数据,将 Model 传递过来的数据渲染成 HTML 页面。 模板就是前端的“皮囊”,负责美化数据。

    <!-- article_list.html -->
    <!DOCTYPE html>
    <html>
    <head>
        <title>Article List</title>
    </head>
    <body>
        <h1>Article List</h1>
        <ul>
            {% for article in articles %}
                <li>{{ article.title }} - {{ article.pub_date }}</li>
            {% endfor %}
        </ul>
    </body>
    </html>

    这个模板循环遍历 articles 列表,并将每篇文章的标题和发布日期显示在页面上。

    注意: 在MVT架构中,Django框架本身充当了Controller的角色,处理URL路由,请求分发等。所以开发者主要关注Model、View和Template的编写即可。

2. 特点:

  • 功能齐全: 自带 ORM、模板引擎、表单处理、用户认证、安全机制等,几乎所有你需要的功能,Django 都已经帮你实现了。 就像一个装备精良的战士,直接可以上战场。

  • 开发效率高: 由于功能齐全,很多重复性的工作都可以交给 Django 自动完成,大大提高了开发效率。

  • 安全性高: Django 内置了很多安全机制,例如 CSRF 保护、XSS 保护等,可以有效防止常见的 Web 攻击。

  • 社区庞大: Django 拥有庞大的社区,遇到问题可以很容易找到解决方案。

  • 学习曲线陡峭: Django 的功能太多了,需要学习的东西也比较多,上手难度相对较高。

  • 重量级: 对于一些小型项目,Django 显得有些笨重。

3. 适用场景:

  • 大型 Web 应用
  • 需要快速开发的项目
  • 对安全性要求高的项目

4. 示例代码:一个简单的博客示例

除了上面的基本代码,咱们再来个更完整的例子,一个简单的博客,包含文章列表和文章详情。

  • models.py:

    from django.db import models
    
    class Article(models.Model):
        title = models.CharField(max_length=200)
        content = models.TextField()
        pub_date = models.DateTimeField('date published')
        author = models.CharField(max_length=100, default="Unknown") # 添加作者字段
    
        def __str__(self):
            return self.title
  • views.py:

    from django.shortcuts import render, get_object_or_404
    
    from .models import Article
    
    def article_list(request):
        articles = Article.objects.all().order_by('-pub_date') # 按发布日期倒序排序
        return render(request, 'article_list.html', {'articles': articles})
    
    def article_detail(request, article_id):
        article = get_object_or_404(Article, pk=article_id) # 获取指定ID的文章,如果不存在则返回404
        return render(request, 'article_detail.html', {'article': article})
  • urls.py (项目级别的 urls.py 需要包含 app 的 urls.py):

    from django.contrib import admin
    from django.urls import path, include
    
    urlpatterns = [
        path('admin/', admin.site.urls),
        path('blog/', include('blog.urls')), # 包含 blog 应用的 urls.py
    ]
  • urls.py (blog 应用级别的 urls.py,需要自己创建):

    from django.urls import path
    from . import views
    
    urlpatterns = [
        path('', views.article_list, name='article_list'), # 文章列表
        path('<int:article_id>/', views.article_detail, name='article_detail'), # 文章详情
    ]
  • templates/article_list.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Article List</title>
    </head>
    <body>
        <h1>Article List</h1>
        <ul>
            {% for article in articles %}
                <li>
                    <a href="{% url 'article_detail' article.id %}">{{ article.title }}</a> - {{ article.pub_date }} - By {{ article.author }}
                </li>
            {% endfor %}
        </ul>
    </body>
    </html>
  • templates/article_detail.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>{{ article.title }}</title>
    </head>
    <body>
        <h1>{{ article.title }}</h1>
        <p>Published on: {{ article.pub_date }}</p>
        <p>By: {{ article.author }}</p>
        <p>{{ article.content }}</p>
        <a href="{% url 'article_list' %}">Back to Article List</a>
    </body>
    </html>

这个例子展示了 Django 的基本用法,包括定义模型、创建视图、编写模板、配置 URL。

二、Flask:灵活自由,微框架之王

Flask,江湖人称“轻量级选手”,或者“积木”。它最大的特点就是“小而美”,核心功能非常精简,但可以通过扩展来实现各种功能。

1. 架构:Werkzeug + Jinja2

Flask 本身并没有强制的架构,但通常会采用 Werkzeug (WSGI 工具包) 和 Jinja2 (模板引擎) 来构建 Web 应用。

  • Werkzeug: 负责处理 HTTP 请求和响应,提供路由、调试器等基础功能。 它就像 Flask 的骨架,支撑着整个应用。

  • Jinja2: 负责模板渲染,将数据渲染成 HTML 页面。 和 Django 的模板引擎类似,但更加灵活。

2. 特点:

  • 轻量级: 核心功能非常精简,易于学习和使用。

  • 灵活性高: 可以根据自己的需求选择不同的扩展,定制自己的 Web 应用。 就像一个乐高积木,可以搭建出各种各样的模型。

  • 自由度高: 没有强制的目录结构和代码风格,可以自由发挥。

  • 学习曲线平缓: 上手难度较低,适合初学者。

  • 需要手动集成: 很多功能需要手动集成,例如 ORM、表单处理等。

  • 安全性需要自己把控: 需要自己处理安全问题,例如 CSRF 保护、XSS 保护等。

3. 适用场景:

  • 小型 Web 应用
  • API 开发
  • 需要高度定制的项目

4. 示例代码:一个简单的 Hello World

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

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

这段代码定义了一个 Flask 应用,当访问根路径时,会返回 "Hello, World!"。

5. 示例代码:一个简单的博客示例

为了更清晰地展示 Flask 的用法,我们再来一个简单的博客示例。

  • app.py:

    from flask import Flask, render_template, request, redirect, url_for
    from flask_sqlalchemy import SQLAlchemy
    from datetime import datetime
    
    app = Flask(__name__)
    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db' # 使用 SQLite 数据库
    db = SQLAlchemy(app)
    
    class Article(db.Model):
        id = db.Column(db.Integer, primary_key=True)
        title = db.Column(db.String(200), nullable=False)
        content = db.Column(db.Text, nullable=False)
        pub_date = db.Column(db.DateTime, default=datetime.utcnow)
        author = db.Column(db.String(100), default="Unknown")
    
        def __repr__(self):
            return '<Article %r>' % self.title
    
    @app.route('/')
    def index():
        articles = Article.query.order_by(Article.pub_date.desc()).all()
        return render_template('index.html', articles=articles)
    
    @app.route('/article/<int:id>')
    def article(id):
        article = Article.query.get_or_404(id)
        return render_template('article.html', article=article)
    
    @app.route('/create', methods=['GET', 'POST'])
    def create():
        if request.method == 'POST':
            title = request.form['title']
            content = request.form['content']
            author = request.form['author']
            new_article = Article(title=title, content=content, author=author)
    
            try:
                db.session.add(new_article)
                db.session.commit()
                return redirect('/')
            except:
                return 'There was an issue adding your article'
        else:
            return render_template('create.html')
    
    if __name__ == "__main__":
        with app.app_context():
            db.create_all()  # Create database tables
        app.run(debug=True)
  • templates/index.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Flask Blog</title>
    </head>
    <body>
        <h1>Flask Blog</h1>
        <a href="{{ url_for('create') }}">Create New Article</a>
        <ul>
            {% for article in articles %}
                <li>
                    <a href="{{ url_for('article', id=article.id) }}">{{ article.title }}</a> - {{ article.pub_date }} - By {{ article.author }}
                </li>
            {% endfor %}
        </ul>
    </body>
    </html>
  • templates/article.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>{{ article.title }}</title>
    </head>
    <body>
        <h1>{{ article.title }}</h1>
        <p>Published on: {{ article.pub_date }}</p>
        <p>By: {{ article.author }}</p>
        <p>{{ article.content }}</p>
        <a href="{{ url_for('index') }}">Back to Home</a>
    </body>
    </html>
  • templates/create.html:

    <!DOCTYPE html>
    <html>
    <head>
        <title>Create New Article</title>
    </head>
    <body>
        <h1>Create New Article</h1>
        <form action="{{ url_for('create') }}" method="POST">
            <label for="title">Title:</label><br>
            <input type="text" id="title" name="title"><br><br>
            <label for="content">Content:</label><br>
            <textarea id="content" name="content" rows="4" cols="50"></textarea><br><br>
            <label for="author">Author:</label><br>
            <input type="text" id="author" name="author"><br><br>
            <input type="submit" value="Submit">
        </form>
    </body>
    </html>

这个例子使用了 Flask-SQLAlchemy 扩展来操作数据库,展示了 Flask 的基本用法,包括定义路由、渲染模板、处理表单。

三、FastAPI:高性能,异步之选

FastAPI,江湖人称“速度之王”,或者“新贵”。它最大的特点就是“快”,基于 ASGI (Asynchronous Server Gateway Interface) 构建,可以处理大量的并发请求。

1. 架构:基于 ASGI

FastAPI 基于 ASGI 构建,这意味着它可以利用异步特性来提高性能。 传统的 WSGI 应用是同步的,而 ASGI 应用是异步的,可以并发处理多个请求。

2. 特点:

  • 高性能: 基于 ASGI 构建,可以处理大量的并发请求。 适合对性能要求高的项目。

  • 自动数据验证: 基于 Pydantic 进行数据验证,可以自动验证请求和响应的数据类型。 减少了手动验证的工作量。

  • 自动 API 文档: 可以自动生成 OpenAPI (Swagger UI) 和 ReDoc API 文档。 方便 API 的使用和测试。

  • 易于使用: 语法简洁,易于学习和使用。

  • 异步编程: 需要掌握异步编程的概念,上手难度相对较高。

  • 生态系统相对较小: 相比 Django 和 Flask,FastAPI 的生态系统还不够完善。

3. 适用场景:

  • API 开发
  • 微服务
  • 需要高性能的项目

4. 示例代码:一个简单的 Hello World

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"Hello": "World"}

这段代码定义了一个 FastAPI 应用,当访问根路径时,会返回一个 JSON 对象。

5. 示例代码:一个简单的带参数的 API

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

这段代码定义了一个 API,可以接收一个 item_id 参数和一个可选的 q 参数。 FastAPI 会自动验证 item_id 是否为整数。

6. 示例代码:一个简单的博客 API

为了更清晰地展示 FastAPI 的用法,我们再来一个简单的博客 API 示例。

  • main.py:

    from typing import List
    from fastapi import FastAPI, HTTPException
    from pydantic import BaseModel
    from datetime import datetime
    
    app = FastAPI()
    
    class Article(BaseModel):
        id: int = None
        title: str
        content: str
        pub_date: datetime = None
        author: str = "Unknown"
    
    articles = []
    article_id_counter = 1
    
    @app.get("/articles", response_model=List[Article])
    async def list_articles():
        return articles
    
    @app.post("/articles", response_model=Article)
    async def create_article(article: Article):
        global article_id_counter
        article.id = article_id_counter
        article.pub_date = datetime.utcnow()
        articles.append(article)
        article_id_counter += 1
        return article
    
    @app.get("/articles/{article_id}", response_model=Article)
    async def get_article(article_id: int):
        for article in articles:
            if article.id == article_id:
                return article
        raise HTTPException(status_code=404, detail="Article not found")
    
    @app.put("/articles/{article_id}", response_model=Article)
    async def update_article(article_id: int, updated_article: Article):
        for i, article in enumerate(articles):
            if article.id == article_id:
                updated_article.id = article_id
                updated_article.pub_date = article.pub_date # 保留原发布日期
                articles[i] = updated_article
                return updated_article
        raise HTTPException(status_code=404, detail="Article not found")
    
    @app.delete("/articles/{article_id}")
    async def delete_article(article_id: int):
        for i, article in enumerate(articles):
            if article.id == article_id:
                del articles[i]
                return {"message": "Article deleted"}
        raise HTTPException(status_code=404, detail="Article not found")

这个例子展示了 FastAPI 的基本用法,包括定义数据模型、创建 API 接口、处理 HTTP 请求。 你可以通过访问 http://127.0.0.1:8000/docshttp://127.0.0.1:8000/redoc 来查看自动生成的 API 文档。

四、总结:选择适合你的框架

好,说了这么多,咱们来总结一下这三个框架的特点,方便大家选择。

特性 Django Flask FastAPI
架构 MVT Werkzeug + Jinja2 基于 ASGI
特点 功能齐全,开发效率高 轻量级,灵活性高 高性能,自动 API 文档
学习曲线 陡峭 平缓 适中
适用场景 大型 Web 应用 小型 Web 应用,API 开发 API 开发,微服务
是否自带ORM 否(需要集成) 否(需要集成)
是否自带模板引擎 是(Jinja2) 否(需要集成,但常用)
异步支持 较弱(但已在改进) 强大

选择建议:

  • 如果你需要快速开发一个大型 Web 应用,并且对安全性要求很高,那么 Django 是一个不错的选择。
  • 如果你需要开发一个小型 Web 应用或者 API,并且希望有更高的灵活性,那么 Flask 是一个不错的选择。
  • 如果你需要开发一个高性能的 API 或者微服务,那么 FastAPI 是一个不错的选择。

当然,选择框架并不是绝对的,最终还是要根据你的项目需求和个人喜好来决定。 重要的是理解每个框架的优缺点,才能做出最合适的选择。

今天的讲座就到这里,希望对大家有所帮助! 祝大家编程愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注