前言
大家好,我是第一程序员(名字大,人很菜)。作为一个非科班转码、正在学习rust和python的萌新,最近我开始学习python与前端技术的集成。说实话,一开始我对全栈开发的概念还很模糊,但随着学习的深入,我发现python作为后端与前端框架的结合可以构建出功能强大的全栈应用。今天我想分享一下我对python与前端集成的学习心得,希望能给同样是非科班转码的朋友们一些参考。
全栈开发指同时掌握前端(用户界面交互)和后端(服务器、数据库、业务逻辑)的开发能力。python凭借其简洁语法、丰富的web框架(django、flask、fastapi)和强大的数据生态,已成为全栈开发的热门选择之一。对于非科班转码者,从python入手全栈,学习曲线相对平缓。
不要一次性学习所有框架,先选一个后端框架(推荐fastapi或flask)和一个前端框架(react或vue)深入实践,再做横向拓展。
一、后端api设计
1.1 使用fastapi创建restful api
fastapi是一个现代化的python web框架,非常适合构建restful api(一种基于http协议、符合rest架构风格的接口设计规范)
from fastapi import fastapi
from pydantic import basemodel
from typing import list
app = fastapi()
class item(basemodel):
id: int
name: str
price: float
is_offer: bool = none
items = []
@app.get("/")
def read_root():
return {"message": "hello, world!"}
@app.get("/items/{item_id}")
def read_item(item_id: int):
for item in items:
if item.id == item_id:
return item
return {"error": "item not found"}
@app.post("/items/")
def create_item(item: item):
items.append(item)
return item
@app.put("/items/{item_id}")
def update_item(item_id: int, item: item):
for i, existing_item in enumerate(items):
if existing_item.id == item_id:
items[i] = item
return item
return {"error": "item not found"}
@app.delete("/items/{item_id}")
def delete_item(item_id: int):
for i, item in enumerate(items):
if item.id == item_id:
items.pop(i)
return {"message": "item deleted"}
return {"error": "item not found"}
1.2 使用flask创建restful api
flask是另一个流行的python web框架,也可以用于构建restful api:
from flask import flask, request, jsonify
app = flask(__name__)
items = []
@app.route('/', methods=['get'])
def read_root():
return jsonify({"message": "hello, world!"})
@app.route('/items/<int:item_id>', methods=['get'])
def read_item(item_id):
for item in items:
if item['id'] == item_id:
return jsonify(item)
return jsonify({"error": "item not found"})
@app.route('/items/', methods=['post'])
def create_item():
item = request.get_json()
items.append(item)
return jsonify(item)
@app.route('/items/<int:item_id>', methods=['put'])
def update_item(item_id):
item = request.get_json()
for i, existing_item in enumerate(items):
if existing_item['id'] == item_id:
items[i] = item
return jsonify(item)
return jsonify({"error": "item not found"})
@app.route('/items/<int:item_id>', methods=['delete'])
def delete_item(item_id):
for i, item in enumerate(items):
if item['id'] == item_id:
items.pop(i)
return jsonify({"message": "item deleted"})
return jsonify({"error": "item not found"})
if __name__ == '__main__':
app.run(debug=true)
二、前端框架集成
2.1 与react集成
react是一个流行的前端框架,可以与python后端api集成:
// app.js
import react, { usestate, useeffect } from 'react';
function app() {
const [items, setitems] = usestate([]);
const [newitem, setnewitem] = usestate({ id: '', name: '', price: '', is_offer: false });
useeffect(() => {
fetch('http://localhost:8000/items/')
.then(response => response.json())
.then(data => setitems(data));
}, []);
const handlesubmit = (e) => {
e.preventdefault();
fetch('http://localhost:8000/items/', {
method: 'post',
headers: {
'content-type': 'application/json',
},
body: json.stringify(newitem),
})
.then(response => response.json())
.then(data => {
setitems([...items, data]);
setnewitem({ id: '', name: '', price: '', is_offer: false });
});
};
return (
<div>
<h1>items</h1>
<ul>
{items.map(item => (
<li key={item.id}>
{item.name} - ${item.price}
</li>
))}
</ul>
<form onsubmit={handlesubmit}>
<input
type="text"
placeholder="id"
value={newitem.id}
onchange={(e) => setnewitem({...newitem, id: parseint(e.target.value)})}
/>
<input
type="text"
placeholder="name"
value={newitem.name}
onchange={(e) => setnewitem({...newitem, name: e.target.value})}
/>
<input
type="number"
placeholder="price"
value={newitem.price}
onchange={(e) => setnewitem({...newitem, price: parsefloat(e.target.value)})}
/>
<button type="submit">add item</button>
</form>
</div>
);
}
export default app;
2.2 与vue集成
vue是另一个流行的前端框架,也可以与python后端api集成:
<!-- app.vue -->
<template>
<div>
<h1>items</h1>
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }} - ${{ item.price }}
</li>
</ul>
<form @submit.prevent="handlesubmit">
<input
type="text"
placeholder="id"
v-model.number="newitem.id"
/>
<input
type="text"
placeholder="name"
v-model="newitem.name"
/>
<input
type="number"
placeholder="price"
v-model.number="newitem.price"
/>
<button type="submit">add item</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
items: [],
newitem: { id: '', name: '', price: '', is_offer: false }
};
},
mounted() {
this.fetchitems();
},
methods: {
fetchitems() {
fetch('http://localhost:8000/items/')
.then(response => response.json())
.then(data => {
this.items = data;
});
},
handlesubmit() {
fetch('http://localhost:8000/items/', {
method: 'post',
headers: {
'content-type': 'application/json',
},
body: json.stringify(this.newitem),
})
.then(response => response.json())
.then(data => {
this.items.push(data);
this.newitem = { id: '', name: '', price: '', is_offer: false };
});
}
}
};
</script>
三、数据传输
3.1 json数据格式
json是前后端数据传输的标准格式:
# 后端返回json数据
from fastapi import fastapi
from pydantic import basemodel
app = fastapi()
class item(basemodel):
id: int
name: str
price: float
@app.get("/item", response_model=item)
def get_item():
return {"id": 1, "name": "item 1", "price": 10.99}
3.2 处理cors
跨域资源共享(cors)是前后端集成中常见的问题:
# fastapi处理cors
from fastapi import fastapi
from fastapi.middleware.cors import corsmiddleware
app = fastapi()
# 配置cors
app.add_middleware(
corsmiddleware,
allow_origins=["*"], # 在生产环境中应该设置具体的域名
allow_credentials=true,
allow_methods=["*"],
allow_headers=["*"],
)
@app.get("/")
def read_root():
return {"message": "hello, world!"}
# flask处理cors
from flask import flask, jsonify
from flask_cors import cors
app = flask(__name__)
cors(app) # 允许所有跨域请求
@app.route('/')
def read_root():
return jsonify({"message": "hello, world!"})
四、认证与授权
4.1 jwt认证
json web token(jwt)是一种常用的认证方式:
# fastapi中使用jwt
from fastapi import fastapi, depends, httpexception, status
from fastapi.security import oauth2passwordbearer, oauth2passwordrequestform
from jose import jwterror, jwt
from datetime import datetime, timedelta
from pydantic import basemodel
app = fastapi()
# 配置
secret_key = "your-secret-key"
algorithm = "hs256"
access_token_expire_minutes = 30
# 模拟用户数据库
fake_users_db = {
"alice": {
"username": "alice",
"full_name": "alice smith",
"email": "alice@example.com",
"hashed_password": "fakehashedsecret",
"disabled": false,
}
}
# 工具函数
def fake_hash_password(password: str):
return "fakehashed" + password
def verify_password(plain_password, hashed_password):
return hashed_password == fake_hash_password(plain_password)
def get_user(db, username: str):
if username in db:
user_dict = db[username]
return user_dict
def create_access_token(data: dict, expires_delta: timedelta = none):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=15)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, secret_key, algorithm=algorithm)
return encoded_jwt
# 依赖
oauth2_scheme = oauth2passwordbearer(tokenurl="token")
async def get_current_user(token: str = depends(oauth2_scheme)):
credentials_exception = httpexception(
status_code=status.http_401_unauthorized,
detail="could not validate credentials",
headers={"www-authenticate": "bearer"},
)
try:
payload = jwt.decode(token, secret_key, algorithms=[algorithm])
username: str = payload.get("sub")
if username is none:
raise credentials_exception
except jwterror:
raise credentials_exception
user = get_user(fake_users_db, username=username)
if user is none:
raise credentials_exception
return user
# 路由
@app.post("/token")
async def login(form_data: oauth2passwordrequestform = depends()):
user = get_user(fake_users_db, form_data.username)
if not user:
raise httpexception(status_code=400, detail="incorrect username or password")
if not verify_password(form_data.password, user["hashed_password"]):
raise httpexception(status_code=400, detail="incorrect username or password")
access_token_expires = timedelta(minutes=access_token_expire_minutes)
access_token = create_access_token(
data={"sub": user["username"]}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
@app.get("/users/me")
async def read_users_me(current_user: dict = depends(get_current_user)):
return current_user
五、部署
5.1 部署后端
使用docker部署python后端:
# dockerfile from python:3.9-slim workdir /app copy requirements.txt . run pip install --no-cache-dir -r requirements.txt copy . . expose 8000 cmd ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "8000"]
5.2 部署前端
使用vercel、netlify等平台部署前端:
- vercel:适合部署react、next.js应用
- netlify:适合部署vue、react应用
- github pages:适合部署静态网站
5.3 完整部署
使用docker compose部署前后端:
# docker-compose.yml
version: '3'
services:
backend:
build: ./backend
ports:
- "8000:8000"
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
六、python与rust的对比
作为一个同时学习python和rust的转码者,我发现对比学习是一种很好的方法:
6.1 前端集成对比
- python:生态丰富,有fastapi、flask等框架
- rust:有actix-web、rocket等框架
- 开发效率:python开发效率高,rust开发效率相对较低
- 性能:rust性能优异,python性能相对较低
6.2 学习心得
- python的优势:开发效率高,生态丰富
- rust的优势:性能优异,内存安全
- 相互借鉴:从python学习快速开发,从rust学习性能优化
七、实践项目推荐
7.1 全栈项目
- 博客系统:使用python作为后端,react/vue作为前端
- 电商系统:使用python作为后端,react/vue作为前端
- 社交应用:使用python作为后端,react/vue作为前端
- 数据分析平台:使用python作为后端,react/vue作为前端
八、学习方法和技巧
8.1 学习方法
- 循序渐进:先学习后端api开发,再学习前端框架
- 项目实践:通过实际项目来巩固知识
- 文档阅读:仔细阅读框架的官方文档
- 社区交流:加入社区,向他人学习
8.2 常见问题和解决方法
- cors问题:配置cors中间件
- 认证问题:使用jwt等认证方式
- 部署问题:使用docker等容器化技术
- 性能问题:优化api设计,使用缓存
九、总结
python与前端技术的集成可以构建出功能强大的全栈应用。作为一个非科班转码者,我深刻体会到全栈开发的重要性。
到此这篇关于全栈开发进阶:python后端(fastapi/flask)+ react/vue前端集成完整教程的文章就介绍到这了,更多相关python前端框架全栈开发内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论