尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Python+Django构建旅游拼团系统实战

发布时间:2026/9/23 23:03:17

资讯中心
01
ARTICLE

Python+Django构建旅游拼团系统实战

Python+Django构建旅游拼团系统实战
1. 项目概述最近在开发一个旅游自助拼团系统用PythonDjango实现后端服务。这个系统的核心目标是让旅行爱好者能够自主发起和加入拼团活动解决独自旅行费用高、缺少同伴的问题。作为一个经常独自旅行的程序员我深知拼团旅游的痛点——传统旅行社的拼团选择有限而社交平台上的自发组团又缺乏安全保障。这个项目就是想用技术手段解决这些问题。系统采用B/S架构前端用Vue.js构建响应式界面后端使用Django REST framework提供API服务数据库选用MySQL。整个开发周期约2个月目前已经实现了核心的拼团发布、搜索、订单管理等功能。下面我会详细分享这个项目的技术实现细节和踩过的坑。2. 技术选型与架构设计2.1 为什么选择PythonDjango选择Django主要基于以下几个考虑开发效率Django自带Admin后台、ORM、用户认证等常用功能可以快速搭建原型安全性Django默认提供CSRF防护、XSS防护等安全机制扩展性Django的App设计理念让系统可以模块化扩展社区支持有丰富的第三方包可供选择如DRF、Django-filter等提示如果项目对性能要求极高可以考虑FlaskSQLAlchemy的组合但需要自行实现更多基础功能。2.2 前端技术选型虽然Django自带模板引擎但我们还是选择了Vue.js作为前端框架原因包括更好的用户体验SPA应用无需整页刷新前后端分离方便后期App端复用API组件化开发拼团卡片、搜索筛选等组件可以复用// 示例Vue组件拼团卡片 Vue.component(group-card, { props: [group], template: div classcard h3{{ group.destination }}/h3 p出发日期{{ group.start_date }}/p p当前人数{{ group.current_members }}/{{ group.max_members }}/p button clickjoinGroup加入拼团/button /div , methods: { joinGroup() { this.$emit(join, this.group.id) } } })2.3 数据库设计优化最初的数据库设计比较简单在实际开发中我们做了以下优化添加冗余字段在Group表中添加current_members字段避免每次都要COUNT关联订单使用索引为常用的搜索字段如destination、start_date添加数据库索引软删除设计添加is_deleted字段而不是直接删除记录# 优化后的模型设计 class Group(models.Model): creator models.ForeignKey(User, on_deletemodels.PROTECT) destination models.CharField(max_length100, db_indexTrue) start_date models.DateField(db_indexTrue) end_date models.DateField() max_members models.IntegerField() current_members models.IntegerField(default1) # 冗余字段 is_deleted models.BooleanField(defaultFalse) class Meta: indexes [ models.Index(fields[destination, start_date]), ]3. 核心功能实现细节3.1 用户认证系统我们扩展了Django内置的User模型添加了手机号字段并实现了JWT认证# serializers.py from rest_framework_simplejwt.serializers import TokenObtainPairSerializer class MyTokenObtainPairSerializer(TokenObtainPairSerializer): classmethod def get_token(cls, user): token super().get_token(user) token[mobile] user.mobile return token # models.py from django.contrib.auth.models import AbstractUser class User(AbstractUser): mobile models.CharField(max_length11, uniqueTrue) avatar models.URLField(nullTrue) REQUIRED_FIELDS [mobile] # 注册时必须提供手机号踩坑记录Django的AbstractUser默认username是唯一标识但国内用户更习惯用手机号登录。我们通过自定义User模型和认证后端实现了手机号密码登录。3.2 拼团搜索功能搜索功能需要考虑多种查询条件和分页# filters.py import django_filters from .models import Group class GroupFilter(django_filters.FilterSet): destination django_filters.CharFilter(lookup_expricontains) start_date_gte django_filters.DateFilter(field_namestart_date, lookup_exprgte) start_date_lte django_filters.DateFilter(field_namestart_date, lookup_exprlte) class Meta: model Group fields [destination, start_date_gte, start_date_lte] # views.py from rest_framework import generics from django_filters.rest_framework import DjangoFilterBackend class GroupList(generics.ListAPIView): queryset Group.objects.filter(is_deletedFalse) serializer_class GroupSerializer filter_backends [DjangoFilterBackend] filterset_class GroupFilter pagination_class PageNumberPagination3.3 支付系统对接对接微信支付时需要注意的几个关键点签名验证所有请求都需要计算签名防止篡改异步通知支付结果以微信服务器通知为准订单状态管理需要处理支付超时、重复通知等情况# 微信支付工具类 import hashlib import time import requests class WeChatPay: def __init__(self, appid, mch_id, api_key): self.appid appid self.mch_id mch_id self.api_key api_key def create_order(self, order_id, amount, desc, notify_url): nonce_str self._generate_nonce_str() params { appid: self.appid, mch_id: self.mch_id, nonce_str: nonce_str, body: desc, out_trade_no: order_id, total_fee: amount, notify_url: notify_url, trade_type: JSAPI, sign_type: MD5 } params[sign] self._calculate_sign(params) # 发送请求到微信支付API... def _calculate_sign(self, params): # 签名计算逻辑... key_list sorted(params.keys()) string_a .join([f{k}{params[k]} for k in key_list if params[k]]) string_sign_temp f{string_a}key{self.api_key} return hashlib.md5(string_sign_temp.encode()).hexdigest().upper()4. 性能优化实践4.1 缓存热门拼团数据使用Redis缓存热门目的地的拼团列表from django.core.cache import cache def get_hot_groups(destination): cache_key fhot_groups:{destination} groups cache.get(cache_key) if not groups: groups Group.objects.filter( destinationdestination, start_date__gtetimezone.now() ).order_by(-current_members)[:10] cache.set(cache_key, groups, timeout3600) # 缓存1小时 return groups4.2 数据库查询优化使用select_related和prefetch_related减少查询次数# 不好的写法会产生N1查询问题 groups Group.objects.all() for group in groups: print(group.creator.username) # 每次循环都会查询数据库 # 优化后的写法 groups Group.objects.select_related(creator).all() for group in groups: print(group.creator.username) # 只会有1次查询4.3 异步任务处理使用Celery处理耗时操作如发送通知邮件# tasks.py from celery import shared_task from django.core.mail import send_mail shared_task def send_join_notification(email, group_name): subject f您已成功加入拼团{group_name} message 感谢您的参与请按时参加活动 send_mail(subject, message, noreplyexample.com, [email])5. 安全防护措施5.1 防止SQL注入Django的ORM已经提供了SQL注入防护但直接使用原生SQL时需要特别注意# 不安全的写法 query fSELECT * FROM groups WHERE destination {user_input} # 安全的写法 from django.db import connection with connection.cursor() as cursor: cursor.execute(SELECT * FROM groups WHERE destination %s, [user_input])5.2 XSS防护Django模板默认会自动转义HTML字符但在前后端分离项目中前端也需要做防护// Vue中显示用户输入内容时使用v-text而不是v-html div v-textuserContent/div5.3 敏感数据保护用户密码必须加密存储绝对不能明文保存# Django会自动处理密码哈希 user User.objects.create_user( usernametest, passwordsecret, # 会自动转为哈希值存储 mobile13800138000 )6. 测试与部署6.1 单元测试编写为关键功能编写测试用例from django.test import TestCase from django.urls import reverse from rest_framework.test import APIClient class GroupTest(TestCase): def setUp(self): self.client APIClient() self.user User.objects.create_user( usernametest, passwordtest123, mobile13800138000 ) self.client.force_authenticate(userself.user) def test_create_group(self): url reverse(group-list) data { destination: 三亚, start_date: 2023-12-01, end_date: 2023-12-07, max_members: 10 } response self.client.post(url, data, formatjson) self.assertEqual(response.status_code, 201) self.assertEqual(Group.objects.count(), 1)6.2 接口测试使用Postman进行接口测试时建议创建测试集合按功能模块组织请求使用环境变量管理不同环境的URL和认证信息编写测试脚本验证响应数据和状态码6.3 生产环境部署我们使用NginxGunicorn部署Django应用# Gunicorn启动命令 gunicorn --workers 4 --bind unix:/tmp/gunicorn.sock project.wsgi:application # Nginx配置示例 server { listen 80; server_name example.com; location / { proxy_pass http://unix:/tmp/gunicorn.sock; proxy_set_header Host $host; } location /static/ { alias /path/to/static/files/; } }部署经验使用supervisor管理进程配置自动重启静态文件通过Nginx直接服务减轻应用服务器负担。7. 扩展功能实现7.1 实时聊天功能使用Django Channels实现拼团聊天室# consumers.py from channels.generic.websocket import AsyncWebsocketConsumer import json class GroupChatConsumer(AsyncWebsocketConsumer): async def connect(self): self.group_id self.scope[url_route][kwargs][group_id] self.room_group_name fchat_{self.group_id} await self.channel_layer.group_add( self.room_group_name, self.channel_name ) await self.accept() async def receive(self, text_data): data json.loads(text_data) message data[message] await self.channel_layer.group_send( self.room_group_name, { type: chat_message, message: message, sender: self.scope[user].username } ) async def chat_message(self, event): await self.send(text_datajson.dumps({ message: event[message], sender: event[sender] }))7.2 旅游攻略分享实现类似博客的功能用户可以撰写和分享旅游攻略# models.py class TravelGuide(models.Model): author models.ForeignKey(User, on_deletemodels.CASCADE) title models.CharField(max_length200) content models.TextField() destinations models.ManyToManyField(Destination) created_at models.DateTimeField(auto_now_addTrue) updated_at models.DateTimeField(auto_nowTrue) class Meta: ordering [-created_at] class Destination(models.Model): name models.CharField(max_length100) description models.TextField()8. 项目总结与反思这个项目从技术角度来说不算复杂但涉及的知识点非常全面包括前后端开发、数据库设计、支付对接、实时通信等。在开发过程中我总结了以下几点经验合理规划数据模型初期设计的不足会导致后期大量重构建议先画好ER图考虑清楚实体间的关系重视测试特别是支付这类关键功能必须覆盖各种边界情况性能从设计开始数据库索引、缓存策略等应该在设计阶段就考虑而不是等出现性能问题再优化安全第一用户数据保护、支付安全等必须作为最高优先级考虑未来可以考虑增加的功能包括拼团成团后的行程协同规划用户信用评价系统基于地理位置的附近拼团推荐整个项目最让我满意的是支付系统的健壮性设计经过多次测试和优化目前没有出现过支付状态不一致的问题。最大的教训是在初期低估了实时聊天功能的复杂度导致后期不得不调整架构引入Django Channels。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。