MVC模式开发:Flask中的拆分

这篇博文主要用于记录拆分项目Fyyur中控制层和模型层的过程,以及自己的一些感悟。

前言

在学习Web App开发的一开始,我就学习了MVC模式。但是因为写的只是todo-app这样的小demo,所以我对使用MVC模式进行开发的好处感受得并不深。

最近在用Flask写Fyyur项目。与之前的todo-app相比,这个项目会更大一些,也因此,我对MVC模式的优势的感受更深了一些。

在本文的余下部分,我将对自己利用MVC模式重构Fyyur项目代码的过程进行描述。另外说明的是,因为我在写这篇博文的时候还是初学者,如有不对的地方,欢迎指正。

🏜️ 项目代码:Github

MVC概述

MVC说起来很简单。它是一种软件设计模式,通过将软件的各个基本部分进行分离,从而降低复杂度,使程序结构更加直观。

MVC模式将软件系统分为三个基本部分,

  • 模型层 (Model layer) :实现程序的功能(如实现算法等);进行数据库设计和数据的管理
  • 视图层 (View layer) :UI界面,
  • 控制层 (Controller layer) :接收、处理请求

重构Fyyur代码

来看一下初始的项目结构,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
├── README.md
├── app.py *** the main driver of the app. Includes SQLAlchemy models.
"python app.py" to run after installing dependencies
├── config.py *** Database URLs, CSRF generation, etc
├── error.log
├── forms.py *** web forms which creats data
├── requirements.txt *** The dependencies we need to install with "pip3 install -r requirements.txt"
├── static
│   ├── css
│   ├── font
│   ├── ico
│   ├── img
│   └── js
└── templates *** the web frontend
├── errors
├── forms
├── layouts
└── pages

可以看出,视图层(View layer)已经被隔离出来了,放在了templates和static中。但是模型层和控制层都被放到了 app.y 这一个文件中,导致一个文件内代码过多。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# app.py文件结构,代码已省略

# ============================================================================ #
# Imports #
# ============================================================================ #


# ============================================================================ #
# App Config. #
# ============================================================================ #


# ============================================================================ #
# Models. #
# ============================================================================ #


# ============================================================================ #
# Filters. #
# ============================================================================ #


# ============================================================================ #
# Controllers. #
# ============================================================================ #


# ============================================================================ #
# Launch. #
# ============================================================================ #

于是我想把Model和Controller部分的代码隔离开,减少 app.py 文件里代码的数量。

第1次尝试

建立一个 models.py 文件,将模型部分的代码放到里面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# models.py

from app import db

class Venue(db.Model):
__tablename__ = 'venues'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)

class Artist(db.Model):
__tablename__ = 'artists'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)

app.py 文件中,只需要导入模型即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# app.py

# ============================================================================ #
# Imports #
# ============================================================================ #

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
# from models import *

# ============================================================================ #
# App Config. #
# ============================================================================ #

app = Flask(__name__)
db = SQLAlchemy(app)

# ============================================================================ #
# Models. #
# ============================================================================ #

from models import *

# ============================================================================ #
# Filters. #
# ============================================================================ #


# ============================================================================ #
# Controllers. #
# ============================================================================ #


# ============================================================================ #
# Launch. #
# ============================================================================ #

但这么写其实是不符合规范的,from models import * 应该是被写到文件顶部的(被注释的那个位置)。然而如果我们将 import 写在文件顶部,运行时会报错:ImportError: cannot import name 'db' 。这个很好理解,因为执行 from models import * 时,在 models.py 文件里需要引用 app.py 文件中的 db , 而此时,db 还没有创建,所以会报错。

第2次尝试

问题的关键在 db 这里。一个解决循环导包的方法是,将 db 放到另一个单独的.py文件中,切断 app.pymodels.py 之间的循环引用。

具体来说,

总结

虽然完成了视图层、模型层以及控制层的拆分,但整个项目的结构仍然不够好。

我曾尝试将项目结构划分为前端和后端两部分,但是在引用上出了一些问题,导致项目不能正常运行。因此这篇博客就到此为止,希望在未来,可以随着自己水平的不断提升,写出更符合工程规范的代码。