1. 项目概述:宠物驯养网站的技术选型与设计思路
去年接手一个宠物驯养平台的开发需求时,我面临一个关键抉择:如何构建一个既能快速迭代又能长期维护的全栈系统?最终确定的方案是Python+Django/Flask后端配合Vue.js前端的架构组合。这种技术栈选择背后有几个重要考量:
首先,Python生态在数据处理和业务逻辑实现上具有天然优势。Django的全能型框架特性适合快速搭建后台管理系统,而Flask的轻量化特点则完美适配需要灵活定制的API服务。当系统需要同时处理宠物档案管理、训练计划制定和用户社交功能时,这种"重型+轻型"的框架组合展现了惊人的适应性。
Vue.js的选择则源于其渐进式框架的特性。宠物驯养网站往往需要丰富的交互功能(如训练进度可视化、宠物行为记录等),但又不能过度复杂化前端架构。Vue的单文件组件和响应式数据绑定,让开发团队能按需引入复杂度,从简单的信息展示页面逐步过渡到复杂的训练计划编排界面。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构深度解析
2.1 后端服务分层设计
采用经典的"三明治"架构模式:
code复制请求层 → 业务逻辑层 → 数据访问层
在Django中的具体实现:
python复制# views.py (请求层)
class TrainingPlanView(APIView):
def post(self, request):
serializer = TrainingPlanSerializer(data=request.data)
if serializer.is_valid():
service.create_plan(serializer.validated_data) # 业务逻辑层
return Response(status=201)
# services.py (业务逻辑层)
def create_plan(validated_data):
plan = Plan.objects.create(**validated_data) # 数据访问层
schedule_reminders(plan)
return plan
Flask则更适合实现微服务架构的特定模块:
python复制# app.py
@app.route('/api/behavior/analyze', methods=['POST'])
def analyze_behavior():
data = request.get_json()
result = BehaviorAnalyzer(data).execute() # 独立分析模块
return jsonify(result)
2.2 前端工程化实践
Vue项目采用最新的组合式API写法:
javascript复制// useTrainingLog.js
export default function useTrainingLog(petId) {
const logs = ref([])
const loading = ref(false)
const fetchLogs = async () => {
loading.value = true
try {
const { data } = await axios.get(`/api/pets/${petId}/logs`)
logs.value = data
} finally {
loading.value = false
}
}
return { logs, loading, fetchLogs }
}
关键工具链配置:
- Vue Router实现动态路由匹配
- Pinia替代Vuex进行状态管理
- Axios封装实现API统一拦截
- VeeValidate处理表单验证
3. 数据库设计与优化
3.1 核心表结构
python复制# models.py
class Pet(models.Model):
PET_TYPES = (
('dog', '犬类'),
('cat', '猫类'),
('bird', '鸟类'),
)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=50)
pet_type = models.CharField(max_length=10, choices=PET_TYPES)
birthday = models.DateField(null=True)
avatar = models.ImageField(upload_to='pet_avatars/')
class TrainingLog(models.Model):
pet = models.ForeignKey(Pet, on_delete=models.CASCADE)
trainer = models.ForeignKey(User, on_delete=models.CASCADE)
start_time = models.DateTimeField()
duration = models.PositiveIntegerField() # 分钟
skills = models.ManyToManyField('Skill')
notes = models.TextField(blank=True)
3.2 性能优化实践
- 查询优化:
python复制# 错误示范 - N+1查询问题
logs = TrainingLog.objects.all()
for log in logs:
print(log.pet.name) # 每次循环都查询数据库
# 正确做法 - select_related
logs = TrainingLog.objects.select_related('pet').all()
- 分库分表策略:
- 宠物基础信息使用MySQL主库
- 训练记录使用TimescaleDB(基于PostgreSQL的时间序列数据库)
- 用户行为日志使用MongoDB
4. 前后端交互关键实现
4.1 JWT认证集成
Django端配置:
python复制# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
)
}
# urls.py
urlpatterns += [
path('api/token/', TokenObtainPairView.as_view()),
path('api/token/refresh/', TokenRefreshView.as_view()),
]
Vue端拦截器示例:
javascript复制// http.js
instance.interceptors.request.use(config => {
const token = localStorage.getItem('access')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
})
instance.interceptors.response.use(
response => response,
async error => {
const originalRequest = error.config
if (error.response.status === 401 && !originalRequest._retry) {
originalRequest._retry = true
const { data } = await authService.refreshToken()
localStorage.setItem('access', data.access)
return instance(originalRequest)
}
return Promise.reject(error)
}
)
4.2 文件上传处理
Django接收图片上传:
python复制class PetAvatarView(APIView):
parser_classes = [MultiPartParser]
def post(self, request):
file = request.FILES['avatar']
img = Image.open(file)
img.thumbnail((500, 500)) # 缩略图处理
pet = get_object_or_404(Pet, pk=request.data['pet_id'])
pet.avatar.save(file.name, file)
return Response(PetSerializer(pet).data)
Vue前端实现:
vue复制<template>
<input type="file" @change="handleUpload" accept="image/*">
</template>
<script setup>
const handleUpload = async (e) => {
const file = e.target.files[0]
const formData = new FormData()
formData.append('avatar', file)
formData.append('pet_id', petId.value)
try {
await axios.post('/api/pets/avatar', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})
} catch (err) {
console.error('上传失败:', err)
}
}
</script>
5. 开发环境配置指南
5.1 PyCharm专业版配置
- 必备插件:
- Vue.js
- Database Tools and SQL
- REST Client
- Python Docstring Generator
- 运行配置:
- 为Django项目配置Python解释器(建议使用虚拟环境)
- 设置JavaScript调试配置连接Vue开发服务器
- 配置Database工具连接MySQL/PostgreSQL
- 实用技巧:
- 使用"Run Django Console"快速测试模型操作
- 利用HTTP Client测试API接口(无需Postman)
- 使用Live Template快速生成Vue组件模板
5.2 VSCode替代方案配置
json复制// settings.json
{
"python.pythonPath": "venv/bin/python",
"python.linting.enabled": true,
"vetur.validation.template": false,
"eslint.validate": [
"javascript",
"javascriptreact",
"vue"
],
"files.associations": {
"*.vue": "vue"
}
}
6. 部署实战方案
6.1 Docker化部署
Dockerfile示例:
dockerfile复制# Django容器
FROM python:3.9
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "core.wsgi"]
# Vue容器
FROM node:16 as build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
docker-compose.yml配置:
yaml复制version: '3'
services:
db:
image: postgres:13
volumes:
- pg_data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: pet1234
backend:
build: ./backend
ports:
- "8000:8000"
depends_on:
- db
frontend:
build: ./frontend
ports:
- "8080:80"
6.2 性能监控配置
使用Sentry实现错误追踪:
python复制# settings.py
INSTALLED_APPS += ['sentry_sdk']
import sentry_sdk
sentry_sdk.init(
dsn="YOUR_DSN",
integrations=[DjangoIntegration()],
traces_sample_rate=1.0,
)
前端性能监控:
javascript复制// main.js
import * as Sentry from '@sentry/vue'
import { BrowserTracing } from '@sentry/tracing'
Sentry.init({
Vue,
dsn: 'YOUR_DSN',
integrations: [
new BrowserTracing({
routingInstrumentation: Sentry.vueRouterInstrumentation(router)
})
],
tracesSampleRate: 1.0
})
7. 项目经验与避坑指南
7.1 跨域问题终极解决方案
Django配置示例:
python复制# settings.py
CORS_ALLOWED_ORIGINS = [
"http://localhost:8080",
"https://yourdomain.com"
]
# 开发环境允许所有(慎用)
if DEBUG:
CORS_ALLOW_ALL_ORIGINS = True
Vue开发服务器代理配置:
javascript复制// vue.config.js
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
pathRewrite: {
'^/api': ''
}
}
}
}
}
7.2 时区处理最佳实践
- 数据库层面统一UTC:
python复制# settings.py
TIME_ZONE = 'UTC'
USE_TZ = True
- 前端展示时转换:
javascript复制// utils/date.js
export function localizeUTC(date) {
return new Date(date).toLocaleString(navigator.language, {
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone
})
}
- 用户个人时区偏好存储:
python复制# models.py
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
timezone = models.CharField(
max_length=50,
default='UTC',
choices=[(tz, tz) for tz in pytz.all_timezones]
)
7.3 静态资源处理技巧
Django生产环境配置:
python复制# settings.py
STATIC_URL = '/static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_DIRS = [BASE_DIR / 'static']
# 使用Whitenoise中间件
MIDDLEWARE.insert(1, 'whitenoise.middleware.WhiteNoiseMiddleware')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
Vue构建优化:
javascript复制// vue.config.js
module.exports = {
chainWebpack: config => {
config.plugin('preload').tap(options => {
options[0].fileBlacklist.push(/\.map$/)
return options
})
config.optimization.splitChunks({
chunks: 'all',
maxSize: 244 * 1024 // 拆分包大小阈值
})
}
}
8. 扩展功能实现思路
8.1 宠物训练进度可视化
使用ECharts实现:
vue复制<template>
<div ref="chart" style="width: 100%; height: 400px;"></div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import * as echarts from 'echarts'
const chart = ref(null)
const props = defineProps(['progressData'])
onMounted(() => {
const instance = echarts.init(chart.value)
instance.setOption({
radar: {
indicator: props.progressData.skills.map(skill => ({
name: skill.name,
max: 100
}))
},
series: [{
data: [{
value: props.progressData.scores,
areaStyle: { color: 'rgba(255, 228, 52, 0.6)' }
}]
}]
})
})
</script>
8.2 训练提醒系统
Celery定时任务示例:
python复制# tasks.py
@app.task
def send_training_reminders():
now = timezone.now()
upcoming = TrainingSession.objects.filter(
start_time__range=(now, now + timedelta(hours=24)),
reminder_sent=False
)
for session in upcoming:
send_mail(
subject=f"训练提醒: {session.pet.name}",
message=f"您预约的{session.skill.name}训练将在{session.start_time}开始",
recipient_list=[session.trainer.email]
)
session.reminder_sent = True
session.save()
8.3 行为分析算法集成
使用scikit-learn实现简单分类:
python复制# analyzer.py
from sklearn.ensemble import RandomForestClassifier
import joblib
class BehaviorClassifier:
def __init__(self):
try:
self.model = joblib.load('model.pkl')
except:
self.model = RandomForestClassifier()
def train(self, X, y):
self.model.fit(X, y)
joblib.dump(self.model, 'model.pkl')
def predict(self, features):
return self.model.predict([features])[0]
9. 测试策略与实施
9.1 后端测试方案
Django测试用例示例:
python复制class TrainingLogTest(APITestCase):
@classmethod
def setUpTestData(cls):
cls.user = User.objects.create(username='tester')
cls.pet = Pet.objects.create(name='Buddy', owner=cls.user)
def test_create_log(self):
self.client.force_login(self.user)
data = {
'pet': self.pet.id,
'start_time': '2023-07-20T10:00:00Z',
'duration': 30,
'notes': '基础服从训练'
}
response = self.client.post('/api/logs/', data)
self.assertEqual(response.status_code, 201)
self.assertEqual(TrainingLog.objects.count(), 1)
9.2 前端测试方案
Vitest组件测试示例:
javascript复制import { mount } from '@vue/test-utils'
import TrainingLogForm from './TrainingLogForm.vue'
describe('TrainingLogForm', () => {
it('emits submit event with form data', async () => {
const wrapper = mount(TrainingLogForm, {
props: { petId: '1' }
})
await wrapper.find('input[name="duration"]').setValue(30)
await wrapper.find('form').trigger('submit')
expect(wrapper.emitted('submit')[0][0]).toEqual({
petId: '1',
duration: 30,
notes: ''
})
})
})
9.3 E2E测试配置
使用Cypress实现:
javascript复制// cypress/e2e/training.cy.js
describe('Training Log', () => {
beforeEach(() => {
cy.login('trainer@example.com', 'password123')
cy.visit('/pets/1/training')
})
it('should create new log', () => {
cy.get('[data-test="duration-input"]').type('45')
cy.get('[data-test="notes-textarea"]').type('高级服从训练')
cy.get('[data-test="submit-btn"]').click()
cy.contains('.alert', '训练记录已保存').should('be.visible')
cy.get('[data-test="log-item"]').should('have.length.gt', 0)
})
})
10. 项目演进与重构建议
10.1 微服务化改造
当系统规模扩大时的拆分方案:
- 用户服务:处理认证和个人资料
- 宠物档案服务:核心数据管理
- 训练服务:训练计划与进度跟踪
- 社交服务:用户互动功能
使用gRPC进行服务间通信:
proto复制service TrainingService {
rpc CreatePlan (PlanRequest) returns (PlanResponse);
rpc GetProgress (ProgressRequest) returns (ProgressResponse);
}
message PlanRequest {
string pet_id = 1;
repeated string skill_ids = 2;
google.protobuf.Timestamp start_time = 3;
}
10.2 前端性能优化
- 路由懒加载:
javascript复制const routes = [
{
path: '/training',
component: () => import('./views/TrainingView.vue')
}
]
- 虚拟滚动长列表:
vue复制<template>
<RecycleScroller
:items="logs"
:item-size="72"
key-field="id"
>
<template #default="{ item }">
<LogItem :log="item" />
</template>
</RecycleScroller>
</template>
- Web Worker处理复杂计算:
javascript复制// worker.js
self.onmessage = (e) => {
const result = heavyCalculation(e.data)
self.postMessage(result)
}
// 组件中
const worker = new ComlinkWorker('./worker.js')
const result = await worker.calculate(data)
10.3 类型安全增强
后端使用mypy检查:
python复制# pyproject.toml
[tool.mypy]
python_version = "3.9"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
前端TypeScript迁移:
typescript复制// types/pet.ts
interface Pet {
id: string
name: string
type: 'dog' | 'cat' | 'bird'
birthday?: Date
owner: User
}
// 组件中使用
const pet = ref<Pet>({
id: '1',
name: 'Buddy',
type: 'dog',
owner: currentUser.value
})
11. 团队协作规范
11.1 Git工作流设计
- 分支策略:
main:生产环境代码staging:预发布分支feature/*:功能开发分支hotfix/*:紧急修复分支
- Commit规范:
code复制feat: 新增训练计划创建功能
fix(api): 修复时区处理错误
docs: 更新部署文档
chore: 更新依赖版本
11.2 代码审查要点
后端审查清单:
- Django模型是否正确定义了
__str__方法 - 查询是否使用了select_related/prefetch_related
- 是否有N+1查询风险
- 序列化器是否正确处理了所有字段
- 视图是否包含适当的权限检查
前端审查清单:
- 组件是否遵循单一职责原则
- 是否合理使用计算属性和侦听器
- API调用是否有错误处理
- 是否有内存泄漏风险(事件监听器等)
- 是否考虑了响应式布局
11.3 CI/CD流水线配置
GitHub Actions示例:
yaml复制name: Django CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:13
env:
POSTGRES_PASSWORD: postgres
ports: ['5432:5432']
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run tests
env:
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
run: |
python manage.py test
12. 安全防护实践
12.1 常见漏洞防护
- SQL注入防护:
- 始终使用ORM或参数化查询
- 禁止直接拼接SQL语句
- XSS防护:
python复制# Django模板自动转义
{{ user_input }}
# 明确标记安全内容
{{ html_content|safe }}
- CSRF防护:
javascript复制// axios配置
axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken'
12.2 敏感数据处理
- 密码哈希:
python复制# Django自动处理
user.set_password('new_password')
user.save()
- 环境变量管理:
python复制# settings.py
SECRET_KEY = os.getenv('DJANGO_SECRET_KEY')
# .env文件
DJANGO_SECRET_KEY=your-random-string
DATABASE_URL=postgres://user:pass@localhost/dbname
- 日志脱敏:
python复制LOGGING = {
'filters': {
'remove_sensitive': {
'()': 'django.utils.log.CallbackFilter',
'callback': lambda record: sanitize_data(record)
}
}
}
12.3 权限控制系统
基于角色的访问控制:
python复制# models.py
class Role(models.Model):
name = models.CharField(max_length=50)
permissions = models.ManyToManyField(Permission)
# decorators.py
def trainer_required(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
if not request.user.role.name == 'trainer':
raise PermissionDenied
return view_func(request, *args, **kwargs)
return _wrapped_view
前端权限指令:
javascript复制// auth.directive.js
export default {
mounted(el, binding) {
const { value } = binding
const hasPermission = checkPermission(value)
if (!hasPermission) {
el.parentNode?.removeChild(el)
}
}
}
// 使用方式
<button v-permission="'create_training'">新建训练</button>
13. 性能监控与优化
13.1 后端性能指标
Django调试工具栏配置:
python复制# settings.py
DEBUG_TOOLBAR_CONFIG = {
'SHOW_TOOLBAR_CALLBACK': lambda request: DEBUG,
'PROFILER_MAX_DEPTH': 10,
}
MIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']
INSTALLED_APPS += ['debug_toolbar']
关键监控指标:
- 视图响应时间
- SQL查询次数及耗时
- 缓存命中率
- 内存使用情况
13.2 前端性能分析
Chrome DevTools关键检查项:
- Lighthouse评分
- 网络请求瀑布图
- JavaScript执行时间
- 布局重绘次数
- 内存占用趋势
Webpack打包分析:
javascript复制// vue.config.js
module.exports = {
chainWebpack: config => {
config.plugin('webpack-bundle-analyzer')
.use(require('webpack-bundle-analyzer').BundleAnalyzerPlugin)
}
}
13.3 数据库优化技巧
- 索引优化:
python复制class TrainingLog(models.Model):
class Meta:
indexes = [
models.Index(fields=['pet', '-start_time']),
]
- 查询分析:
python复制# 使用explain()分析查询计划
print(TrainingLog.objects.filter(pet__owner=user).explain())
- 连接池配置:
python复制# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'HOST': 'localhost',
'NAME': 'pet_train',
'USER': 'db_user',
'PASSWORD': 'secret',
'OPTIONS': {
'connect_timeout': 5,
'application_name': 'pet_train_app',
},
'CONN_MAX_AGE': 300, # 连接池保持时间
}
}
14. 移动端适配方案
14.1 响应式布局实现
Vue中使用CSS Grid:
vue复制<template>
<div class="training-grid">
<div v-for="session in sessions" :key="session.id" class="session-card">
<!-- 内容 -->
</div>
</div>
</template>
<style scoped>
.training-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1rem;
}
@media (max-width: 768px) {
.training-grid {
grid-template-columns: 1fr;
}
}
</style>
14.2 PWA集成
- 使用Vue CLI插件:
bash复制vue add pwa
- 配置manifest:
json复制// public/manifest.json
{
"name": "宠物驯养助手",
"short_name": "PetTrain",
"theme_color": "#4DBA87",
"icons": [
{
"src": "./img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": ".",
"display": "standalone",
"background_color": "#000000"
}
- 服务工作线程策略:
javascript复制// src/registerServiceWorker.js
workbox.routing.registerRoute(
new RegExp('/api/'),
new workbox.strategies.NetworkFirst()
)
14.3 原生应用封装
使用Capacitor打包:
bash复制npm install @capacitor/core @capacitor/cli
npx cap init
npx cap add android
npx cap add ios
配置原生功能:
javascript复制// src/utils/native.js
import { Plugins } from '@capacitor/core'
const { Camera } = Plugins
export async function takePetPhoto() {
const image = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: 'uri'
})
return image.webPath
}
15. 项目文档体系
15.1 技术文档生成
- 后端API文档:
python复制# schemas.py
class TrainingSchema(APISchema):
pet_id = fields.Integer(required=True)
start_time = fields.DateTime(required=True)
duration = fields.Integer(validate=lambda n: 0 < n <= 120)
# views.py
class TrainingView(APIView):
"""
post:
创建新的训练记录
parameters:
- name: body
in: body
required: true
schema: TrainingSchema
"""
- 前端组件文档:
javascript复制// src/components/TrainingLog.vue
/**
* @displayName 训练记录
* @description 显示单条训练记录的卡片组件
* @props
* log {Object} 必填,训练记录数据对象
* editable {Boolean} 是否可编辑,默认false
* @events
* update:log 当记录更新时触发
* delete 删除记录时触发
*/
15.2 用户手册编写
使用VuePress生成:
markdown复制# 训练计划创建指南
## 基本步骤
1. 导航至宠物详情页
2. 点击"新建训练"按钮
3. 填写训练信息:
- 选择训练类型
- 设置训练时长(30-120分钟)
- 添加备注说明

15.3 架构决策记录(ADR)
示例模板:
code复制# 2023-05-01 前端状态管理方案选择
## 状态
已采纳
## 背景
随着功能复杂度增加,需要统一的状态管理方案
## 决策
选择Pinia而非Vuex 4.x
## 原因
1. 更简单的API设计
2. 更好的TypeScript支持
3. 组合式API风格更统一
4. 更小的包体积
## 后果
- 需要团队学习新API
- 迁移现有Vuex代码
16. 本地开发技巧
16.1 数据库种子数据
使用Django fixtures:
python复制# management/commands/seed.py
class Command(BaseCommand):
def handle(self, *args, **options):
User.objects.create_superuser('admin', 'admin@example.com', 'admin123')
pets = [
Pet(name='Max', pet_type='dog'),
Pet(name='Luna', pet_type='cat')
]
Pet.objects.bulk_create(pets)
16.2 接口Mock方案
使用MSW(Mock Service Worker):
javascript复制// src/mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.get('/api/pets', (req, res, ctx) => {
return res(
ctx.delay(150),
ctx.json([
{ id: 1, name: 'Mock Pet' }
])
)
})
]
// src/main.js
if (process.env.NODE_ENV === 'development') {
const { worker } = require('./mocks/browser')
worker.start()
}
16.3 热重载优化
Django开发服务器配置:
bash复制python manage.py runserver --nothreading --noreload
Vue组件热更新配置:
javascript复制// vue.config.js
module.exports = {
devServer: {
hot: true,
client: {
overlay: {
warnings: false,
errors: true
}
}
}
}
17. 第三方服务集成
17.1 支付系统对接
Stripe集成示例:
python复制# views.py
@csrf_exempt
def create_payment(request):
checkout_session = stripe.checkout.Session.create(
payment_method_types=['card'],
line_items=[{
'price': 'price_123',
'quantity': 1,
}],
mode='payment',
success_url=request.build_absolute_uri('/success/'),
cancel_url=request.build_absolute_uri('/cancel/'),
)
return JsonResponse({'id': checkout_session.id})
前端支付流程:
javascript复制const stripe = Stripe('pk_test_123')
const { error } = await stripe.redirectToCheckout({
sessionId: sessionId
})
17.2 消息推送服务
Firebase Cloud Messaging:
javascript复制// firebase-messaging-sw.js
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-app.js')
importScripts('https://www.gstatic.com/firebasejs/8.10.0/firebase-messaging.js')
firebase.initializeApp({
apiKey: 'YOUR_KEY',
projectId: 'YOUR_PROJECT',
messagingSenderId: 'YOUR_SENDER'
})
const messaging = firebase.messaging()
messaging.onBackgroundMessage((payload) => {
self.registration.showNotification(payload.notification.title, {
body: payload.notification.body
})
})
17.3 地图服务集成
百度地图Vue组件:
vue复制<template>
<baidu-map class="map" :center="center" :zoom="zoom">
<bm-marker :position="marker" />
</baidu-map>
</template>
<script setup>
import { ref } from 'vue'
const center = ref({ lng: 116.404, lat: 39.915 })
const zoom = ref(15)
const marker = ref({ lng: 116.404, lat: 39.915 })
</script>
18. 国际化(i18n)实现
18.1 后端多语言支持
Django国际化配置:
python复制# settings.py
LANGUAGE_CODE = 'zh-hans'
USE_I18N = True
LOCALE_PATHS = [BASE_DIR / 'locale']
# views.py
from django.utils.translation import gettext as _
return Response({'message': _('Training created successfully')})
翻译文件生成:
bash复制django-admin makemessages -l zh_Hans
django-admin compilemessages
18.2 前端多语言方案
Vue I18n集成:
javascript复制// i18n.js
import { createI18n } from 'vue-i18n'
const messages = {
en: {
training: {
create: 'Create Training',
duration: 'Duration (minutes)'
}
},
zh: {
training: {
create: '创建训练',
duration: '时长(分钟)'
}
}
}
export default createI18n({
locale: navigator.language.split('-')[0] || 'en',
fallbackLocale: 'en',
messages
})
组件中使用:
vue复制<template>
<h1>{{ $t('training.create') }}</h1>
</template>
19. 数据分析功能实现
19.1 训练数据统计
使用Pandas分析:
python复制# analytics.py
def get_training_stats(pet_id):
logs = TrainingLog.objects.filter(pet_id=pet_id)
df = pd.DataFrame.from_records(logs.values())
stats = {
'total_hours': df['duration'].sum() / 60,
'avg_duration': df['duration'].mean(),
'skill_distribution': df['skill'].value_counts().to_dict()
}
return stats
19.2 可视化报表
ECharts集成:
javascript复制// useTrainingStats.js
export function useTrainingStats(petId) {
const fetchStats = async () => {
const { data } = await axios.get(`/api/pets/${petId}/stats`)
return data
}
const initChart = (dom, stats) => {
const chart = echarts.init(dom)
chart.setOption({
tooltip: {},
xAxis: { data: Object.keys(stats.skill_distribution) },
yAxis: {},
series: [{
type: 'bar',
data: Object.values(stats.skill_distribution)
}]
})
return chart
}
return { fetchStats, initChart }
}
19.3 用户行为分析
前端埋点示例:
javascript复制// tracker.js
export function track(event, payload = {}) {
if (process.env.NODE_ENV === 'production') {
navigator.sendBeacon('/analytics', {
event,
timestamp: new Date().toISOString(),
...payload
})
}
}
// 组件中使用
import { track
