最近在做一个基于Flask+Vue的房屋租赁系统,采用前后端分离架构。这个项目特别适合想学习全栈开发的朋友,尤其是对Python和Vue.js都感兴趣的开发者。整个系统从数据库设计到前后端联调,涵盖了Web开发的完整流程。
作为一个有多年全栈开发经验的工程师,我发现这种前后端分离的项目结构在实际工作中非常常见。Flask作为轻量级的Python框架,特别适合快速开发API服务;而Vue.js的响应式特性则让前端开发变得高效优雅。
选择Flask而不是Django主要基于以下几点考虑:
对于数据库,我推荐MySQL而不是MongoDB,因为:
Vue 3的组合式API相比选项式API有几个优势:
UI组件库选择Element Plus而不是Vant的原因是:
一个合理的Flask项目结构应该如下:
code复制house_rental/
├── app/
│ ├── __init__.py
│ ├── models/
│ │ ├── user.py
│ │ ├── house.py
│ │ └── order.py
│ ├── routes/
│ │ ├── auth.py
│ │ ├── house.py
│ │ └── order.py
│ ├── static/
│ ├── templates/
│ └── config.py
├── migrations/
├── tests/
├── requirements.txt
└── run.py
我推荐使用JWT而不是Session,因为:
实现代码示例:
python复制from flask_jwt_extended import create_access_token
from werkzeug.security import generate_password_hash
@app.route('/api/auth/register', methods=['POST'])
def register():
data = request.get_json()
hashed_password = generate_password_hash(data['password'])
new_user = User(username=data['username'], password=hashed_password)
db.session.add(new_user)
db.session.commit()
return jsonify({"message": "User created"}), 201
@app.route('/api/auth/login', methods=['POST'])
def login():
data = request.get_json()
user = User.query.filter_by(username=data['username']).first()
if user and check_password_hash(user.password, data['password']):
access_token = create_access_token(identity=user.id)
return jsonify(access_token=access_token)
return jsonify({"message": "Invalid credentials"}), 401
房源模型设计需要考虑:
python复制class House(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
description = db.Column(db.Text)
price = db.Column(db.Float, nullable=False)
address = db.Column(db.String(200))
area = db.Column(db.Float) # 面积
room_count = db.Column(db.Integer)
created_at = db.Column(db.DateTime, default=datetime.utcnow)
owner_id = db.Column(db.Integer, db.ForeignKey('user.id'))
images = db.relationship('HouseImage', backref='house', lazy=True)
facilities = db.relationship('Facility', secondary=house_facility, lazy='subquery')
推荐使用如下结构:
code复制src/
├── api/ # API请求封装
├── assets/ # 静态资源
├── components/ # 通用组件
├── composables/ # 组合式函数
├── router/ # 路由配置
├── stores/ # Pinia状态管理
├── styles/ # 全局样式
├── utils/ # 工具函数
├── views/ # 页面组件
├── App.vue # 根组件
└── main.js # 入口文件
实现要点:
vue复制<script setup>
import { ref, onMounted } from 'vue'
import { getHouses } from '@/api/house'
const houses = ref([])
const loading = ref(false)
const pagination = ref({
page: 1,
pageSize: 10,
total: 0
})
const fetchHouses = async () => {
loading.value = true
try {
const res = await getHouses({
page: pagination.value.page,
pageSize: pagination.value.pageSize
})
houses.value = res.data
pagination.value.total = res.total
} finally {
loading.value = false
}
}
onMounted(fetchHouses)
</script>
<template>
<div class="house-list">
<el-table :data="houses" v-loading="loading">
<el-table-column prop="title" label="标题" />
<el-table-column prop="price" label="价格" />
<el-table-column prop="address" label="地址" />
</el-table>
<el-pagination
v-model:current-page="pagination.page"
:page-size="pagination.pageSize"
:total="pagination.total"
@current-change="fetchHouses"
/>
</div>
</template>
采用RESTful风格设计API:
响应格式统一为:
json复制{
"code": 200,
"message": "success",
"data": {}
}
Flask端配置CORS:
python复制from flask_cors import CORS
app = Flask(__name__)
CORS(app, resources={r"/api/*": {"origins": "*"}})
或者开发环境下Vue配置代理:
js复制// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
}
}
核心表包括:
关系:
关键索引:
sql复制-- 用户表
CREATE INDEX idx_user_username ON users(username);
-- 房源表
CREATE INDEX idx_house_price ON houses(price);
CREATE INDEX idx_house_location ON houses(latitude, longitude);
-- 订单表
CREATE INDEX idx_order_user ON orders(user_id);
CREATE INDEX idx_order_house ON orders(house_id);
后端部署方案:
bash复制# 使用Gunicorn启动
gunicorn -w 4 -b 0.0.0.0:5000 run:app
# Nginx配置示例
location /api {
proxy_pass http://127.0.0.1:5000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
前端部署:
bash复制npm run build
# 将dist目录内容部署到Nginx
python复制# 避免N+1查询
houses = House.query.options(
joinedload(House.images),
joinedload(House.facilities)
).all()
python复制from flask_redis import FlaskRedis
redis = FlaskRedis(app)
@app.route('/api/houses')
def get_houses():
cache_key = 'houses:list'
cached_data = redis.get(cache_key)
if cached_data:
return jsonify(json.loads(cached_data))
houses = House.query.all()
result = [house.to_dict() for house in houses]
redis.setex(cache_key, 3600, json.dumps(result))
return jsonify(result)
bash复制# 推荐使用虚拟环境
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
bash复制# 清除缓存重试
rm -rf node_modules package-lock.json
npm cache clean --force
npm install
nginx复制# Nginx配置确保静态文件路径正确
location /static {
alias /path/to/your/static/files;
}
python复制# Flask-SQLAlchemy配置
app.config['SQLALCHEMY_POOL_SIZE'] = 20
app.config['SQLALCHEMY_POOL_RECYCLE'] = 300
在实际开发中,我建议先完成核心功能,再逐步添加这些扩展功能。每个新功能都应该单独创建分支开发,并通过充分的测试后再合并到主分支。