1. 项目概述与技术选型
这个宠物领养寄养系统采用前后端分离架构,后端使用Flask框架,前端基于Vue.js构建。作为一个完整的Web应用,它需要处理宠物信息管理、用户交互、申请流程等核心业务场景。
为什么选择Flask而不是Django?Flask的轻量级特性更适合这种中等规模的项目:
- 不需要Django自带的全套功能(如admin后台)
- 更灵活的路由和视图函数设计
- 可以按需选择扩展库(SQLAlchemy、WTForms等)
前端选用Vue.js的考虑:
- 组件化开发模式天然契合宠物卡片展示需求
- 响应式数据绑定简化了表单交互逻辑
- 丰富的生态系统(Vue Router、Vuex等)
开发工具链配置:
- PyCharm Professional(支持Vue模板语法高亮)
- Python 3.8+虚拟环境
- Node.js 14+环境
2. 后端架构设计与实现
2.1 项目结构规划
典型的Flask项目结构如下:
code复制pet_home/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes/
│ │ ├── pet.py
│ │ ├── user.py
│ │ └── __init__.py
│ ├── static/
│ └── templates/
├── config.py
├── requirements.txt
└── run.py
使用Blueprints实现模块化路由:
python复制# app/routes/pet.py
from flask import Blueprint
bp = Blueprint('pet', __name__, url_prefix='/api/pets')
@bp.route('/')
def list_pets():
return {'data': []}
2.2 数据模型设计
核心模型包括Pet、User和Application:
python复制# models.py
from datetime import datetime
from app import db
class Pet(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(80), nullable=False)
category = db.Column(db.String(50)) # 猫/狗/其他
breed = db.Column(db.String(100)) # 品种
age = db.Column(db.Integer) # 月为单位
status = db.Column(db.String(20)) # 可领养/已寄养/已领养
created_at = db.Column(db.DateTime, default=datetime.utcnow)
def to_dict(self):
return {c.name: getattr(self, c.name) for c in self.__table__.columns}
2.3 RESTful API设计
典型接口示例:
python复制# app/routes/pet.py
@bp.route('/<int:pet_id>', methods=['PUT'])
def update_pet(pet_id):
pet = Pet.query.get_or_404(pet_id)
data = request.get_json()
# 只允许更新特定字段
allowed_fields = {'name', 'status'}
for field in allowed_fields:
if field in data:
setattr(pet, field, data[field])
db.session.commit()
return jsonify(pet.to_dict())
3. 前端Vue组件开发
3.1 核心组件结构
code复制src/
├── components/
│ ├── PetCard.vue # 单个宠物卡片
│ ├── PetFilter.vue # 筛选组件
│ └── AdoptionForm.vue # 领养表单
├── views/
│ ├── Home.vue # 首页
│ └── Dashboard.vue # 用户中心
└── store/ # Vuex状态管理
3.2 宠物列表实现
使用axios进行数据获取:
javascript复制// PetList.vue
export default {
data() {
return {
pets: [],
loading: false,
error: null
}
},
async created() {
try {
this.loading = true
const res = await axios.get('/api/pets')
this.pets = res.data.data
} catch (err) {
this.error = err.response?.data?.message || err.message
} finally {
this.loading = false
}
}
}
3.3 表单验证处理
领养表单的Vuelidate示例:
javascript复制// AdoptionForm.vue
import { required, email, minLength } from 'vuelidate/lib/validators'
export default {
data() {
return {
form: {
name: '',
contact: '',
message: ''
}
}
},
validations: {
form: {
name: { required },
contact: { required, email },
message: { required, minLength: minLength(10) }
}
}
}
4. 开发环境配置与部署
4.1 PyCharm项目设置
-
创建Python虚拟环境:
bash复制python -m venv venv source venv/bin/activate # Linux/Mac venv\Scripts\activate # Windows -
安装依赖:
bash复制
pip install flask flask-sqlalchemy flask-cors -
配置运行配置:
- 设置Working directory为项目根目录
- Python interpreter选择虚拟环境中的python
- 添加环境变量FLASK_APP=run.py
4.2 前后端联调配置
开发模式下启动命令:
bash复制# 后端
export FLASK_ENV=development
flask run --port 5000
# 前端
npm run serve -- --port 8080
配置proxy解决跨域:
javascript复制// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
}
}
4.3 生产环境部署
Nginx配置示例:
nginx复制server {
listen 80;
server_name pet-home.example.com;
location /api {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
}
location / {
root /var/www/pet-home/dist;
try_files $uri $uri/ /index.html;
}
}
使用Gunicorn启动Flask应用:
bash复制gunicorn -w 4 -b 127.0.0.1:8000 run:app
5. 关键问题与解决方案
5.1 图片上传处理
Flask端实现:
python复制@app.route('/api/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
filepath = os.path.join(current_app.config['UPLOAD_FOLDER'], filename)
file.save(filepath)
return jsonify({'url': f'/uploads/{filename}'})
前端上传组件:
vue复制<template>
<div>
<input type="file" @change="handleUpload">
<img v-if="imageUrl" :src="imageUrl">
</div>
</template>
<script>
export default {
methods: {
async handleUpload(e) {
const file = e.target.files[0]
const formData = new FormData()
formData.append('file', file)
try {
const res = await axios.post('/api/upload', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
this.imageUrl = res.data.url
} catch (err) {
console.error('Upload failed:', err)
}
}
}
}
</script>
5.2 用户认证实现
JWT认证方案示例:
python复制# auth.py
from datetime import datetime, timedelta
import jwt
from werkzeug.security import generate_password_hash, check_password_hash
def create_token(user_id):
payload = {
'sub': user_id,
'iat': datetime.utcnow(),
'exp': datetime.utcnow() + timedelta(days=7)
}
return jwt.encode(payload, current_app.config['SECRET_KEY'], algorithm='HS256')
def verify_token(token):
try:
payload = jwt.decode(token, current_app.config['SECRET_KEY'], algorithms=['HS256'])
return payload['sub']
except jwt.PyJWTError:
return None
5.3 数据库迁移管理
使用Flask-Migrate进行数据库版本控制:
bash复制# 初始化
flask db init
# 生成迁移脚本
flask db migrate -m "create pet table"
# 执行迁移
flask db upgrade
6. 项目优化建议
-
性能优化:
- 实现分页查询:
/api/pets?page=2&size=10 - 添加Redis缓存热门宠物数据
- 使用WebSocket实现实时通知
- 实现分页查询:
-
安全增强:
- 实现CSRF保护
- 添加请求速率限制
- 敏感操作记录审计日志
-
用户体验改进:
- 实现收藏功能
- 添加宠物搜索功能
- 开发移动端适配界面
-
测试覆盖:
python复制# test_pet.py def test_get_pet(client, init_db): resp = client.get('/api/pets/1') assert resp.status_code == 200 assert 'name' in resp.json
实际开发中,我发现在处理宠物状态变更时,需要特别注意并发控制。比如当多个用户同时申请领养同一只宠物时,应该使用数据库事务和乐观锁机制:
python复制@app.route('/api/pets/<int:pet_id>/adopt', methods=['POST'])
def adopt_pet(pet_id):
try:
pet = Pet.query.get(pet_id)
if pet.status != 'available':
raise ValueError('Pet not available')
# 开始事务
db.session.begin()
pet.status = 'pending'
application = Application(
pet_id=pet.id,
user_id=current_user.id,
status='pending'
)
db.session.add(application)
db.session.commit()
return jsonify({'message': 'Application submitted'})
except Exception as e:
db.session.rollback()
return jsonify({'error': str(e)}), 400
