news 2026/10/15 18:56:59

Python+Vue网上药房商城:Django/Flask全栈开发详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python+Vue网上药房商城:Django/Flask全栈开发详解

做毕业设计或者练手项目的时候,选“网上药房商城”这个方向的人其实不少。但真把“python基于vue的网上药房在线买药商城系统django flask pycharm”这个标题落到代码层面,很多人写着写着就懵了:药品和普通商品不一样,库存、处方药、订单状态、前后端联调,每个环节都有坑。这篇文章就是围绕这个标题做一个完整拆解,把技术选型、数据库建模、后端接口、前端页面、联调排错串成一条线,让准备复现这个项目的朋友能少走弯路。无论你是要用Django写毕业设计,还是想练手一个前后端分离的全栈项目,都可以拿这篇当作战地图。

我先说个总体结论:这类项目的核心难点不在“写代码”,而在于业务约束多、数据关系复杂、前后端坑位密集。药品商城表面上是个电商系统,实际上比普通电商多了几层东西——处方药与OTC的区分、库存批次管理、订单状态流转的严谨性、价格金额的精度控制。把这些想清楚再动手,比急着撸代码重要得多。

1. 拆解标题里的技术选型:为什么这几种技术能凑成一套完整方案

1.1 Django、Flask、Vue、PyCharm各司其职

标题里的每个词都不是随便堆上去的,先看一张分工表,你就明白这套组合为什么是经典搭配:

技术栈承担的职责为什么选它
Python后端语言基础,所有业务逻辑、数据处理都跑在上面语法友好、生态成熟,毕业设计和快速开发的首选
Django后端主框架,负责ORM、认证、Admin、路由、模板渲染能力自带Admin后台,药品和订单管理能省大量手写代码
Flask后端备选框架,在轻量场景下替代Django适合小型原型或想要精细化控制接口时使用
Vue前端框架,负责页面交互、购物车状态、下单流程响应式数据驱动,配合组件化开发,用户端体验好做
PyCharm开发IDE,贯穿前后端开发、调试、数据库操作的全流程对Django有专门支持,调试器和数据库工具非常省事

这个组合的精妙之处在于:Django负责重活重管,Vue负责界面交互,两者通过RESTful API通信,完全的前后端分离;而PyCharm在中间把所有开发环节串起来,让调试和排查效率高一大截。

1.2 Django与Flask的取舍逻辑

标题里同时出现django和flask,很多人会纠结到底用哪个。我的建议是:默认用Django,只有特殊情况才考虑Flask。

Django的优势很实在:自带的ORM能让你用Python类直接映射数据库表,不用手写SQL;自带的Admin后台可以让你在开发阶段就拥有一个能管理药品、订单、用户的可视化界面;自带的认证体系几乎覆盖了用户登录注册的常见需求。这些对一个“商城系统”来说,等于把地基全都给你打好了。

那我为什么还会提到Flask?因为Flask胜在轻量和灵活。如果你只想做一个API后端,每一个接口都由自己完全掌控,不想被Django的“约定大于配置”约束;或者你的核心需求是练习如何从零搭建一套接口服务,那Flask会让你更快看清HTTP请求处理、路由映射、数据库连接这些底层原理。这次的项目里,如果时间充裕,可以先用Django把完整功能跑通,再横向对比一下Flask重写一遍核心接口,学习价值翻倍。

1.3 千万别小看PyCharm的位置

很多教程把PyCharm当成一个高级文本编辑器,这是最大的误区。我在这个项目里最依赖PyCharm的四个能力:

  • 虚拟环境管理:创建项目时直接用PyCharm建好venv,Django和所有依赖都隔离在项目内部,不会污染系统Python。
  • 断点调试:后端逻辑复杂时,在接口处理函数里打几个断点,看请求走到哪一步、变量值是什么、数据库查询结果长什么样,全程可视化。
  • 数据库工具:PyCharm自带Database面板,可以连上SQLite或MySQL直接看表结构、查看数据、执行SQL,不用额外装Navicat。
  • HTTP客户端:自带接口调试工具,写完接口直接在IDE里发起POST请求测一下,省得来回切换Postman。

换句话说,PyCharm不只是用来“写”代码的,它让整个开发闭环都留在同一个窗口里,这对查错和验证特别重要。

2. 药房商城和普通商城在业务模型上的本质差异

2.1 药品不是普通商品,先想清楚业务约束

开发之前如果只按“图书商城”“服装商城”的思路设计,后面会吃到苦头。药品有几个普通商品没有的特殊约束:

第一,药品有批准文号。这是药品的“身份证”,一个药品的完整信息包括药品名称、规格、生产厂家、批准文号、有效期、用法用量。数据库里得给药品表专门设计这些字段,否则后台没法录入合规的药品信息。

第二,药品分处方药和非处方药(OTC)。处方药不能像普通商品那样直接下单购买。哪怕你做一个学习项目,业务逻辑上也必须有标记和拦截机制:药品表里存一个“处方类型”字段,前端下单时做一个明显的提示和确认弹窗,后端在订单接口里也要做校验,不然用户随便买个抗生素就有点说不过去了。

第三,库存管理更敏感。药品有批次和有效期,真实业务里还会涉及“先进先出”。项目做到基础版,可以简化成“一个药品一个总库存数”,但设计表结构时最好预留批次相关的字段,方便以后扩展。

第四,药品分类更细。成人用药、儿童用药、感冒用药、肠胃用药、维生素矿物质……分类维度比服装的“男装女装”复杂得多,需要两级甚至三级分类。

这些业务约束看起来是“需求条款”,但它们直接决定了字段设计、接口返回值、前端交互逻辑。先列出来,写代码就不会乱。

2.2 核心数据表怎么拆

结合药房业务特点,我建议数据库至少拆成下面这些表。用Django的ORM来翻译,就是一个个models.Model类。

表名核心字段说明
User(用户)username, password, phone, role角色字段可区分普通用户和后台管理员
Category(药品分类)name, parent支持二级分类,parent为空表示一级分类
Drug(药品)name, category, approval_number, prescription_type, price, stock, detail, image核心药品表,价格用Decimal,库存用Integer
CartItem(购物车)user, drug, quantity一个用户对应多个药品条目
Order(订单)order_no, user, total_amount, status, address, created_at订单主表,status是状态机核心
OrderItem(订单明细)order, drug, drug_name, price, quantity下单时快照药品名和价格,防止日后药品信息改动影响历史订单
UserAddress(收货地址)user, receiver, phone, address, is_default近一年常用配送场景基本少不了它

为什么要单独拆OrderItem而不是把药品直接塞进Order?因为一个订单可能包含多种药品,而订单和药品是多对多关系,中间必须有一张明细表。而且明细表里一定要保留“商品名称”和“下单价格”快照,这是订单系统的基本素养——药品以后再改价,历史订单也保持原样。

2.3 价格和库存两个字段设计不能含糊

价格字段在这类项目里翻车率极高。很多新手习惯用FloatField存价格,这是典型的隐患。浮点数是近似值,0.1 + 0.2算出来是0.30000000000000004,一旦涉及金额累加和校验,就会出现“明明价格没错,但订单总额差几分钱”的诡异问题。

正确做法是使用DecimalField:

from django.db import models class Drug(models.Model): name = models.CharField('药品名称', max_length=128) approval_number = models.CharField('批准文号', max_length=64) price = models.DecimalField('单价', max_digits=10, decimal_places=2) stock = models.PositiveIntegerField('库存', default=0) def __str__(self): return self.name

DECIMAL(10, 2)可以存储最大一亿元的价格,两个小数位精准对应货币单位,加减乘除都不会出现精度漂移。

库存字段看起来只是一个整数,但它背后藏着一个并发问题:用户A和用户B同时下单,如果后续扣库存时没有并发控制,库存很容易变成负数。这个问题放后端章节细说,但在建模阶段要有一个意识:库存字段不能任由代码随意赋值。

3. Django后端四条主线实现:认证、药品、购物车、订单

3.1 项目创建和模块结构

用PyCharm新建Django项目之后,我建议按业务模块拆app,而不是把所有代码塞进一个文件里:

# 使用命令行创建项目 django-admin startproject pharmacy_project # 进入项目目录后,创建业务app python manage.py startapp user_app python manage.py startapp drug_app python manage.py startapp order_app python manage.py startapp cart_app

这样拆的好处是:每个app只管一条业务线,文件不会越写越乱。比如drug_app里放药品模型、药品视图、药品序列化器;order_app里放订单模型、订单状态逻辑、下单视图。后期无论是自己维护还是给别人讲解项目,都好理解得多。

3.2 用户认证:Django自带还是JWT

这部分是很多人的纠结点。Django自带Session认证确实开箱即用,但它跟“前后端分离”搭配时体验一般。因为前端跑在Vue环境里,没有浏览器的同源Session概念,用Session需要处理跨域Cookie,配置麻烦,而且移动端几乎没法用。

我用的是JWT(JSON Web Token)。用户登录成功,后端返回一个token,前端存到LocalStorage里,之后每次请求在请求头带上Authorization: Bearer <token>,后端验证通过就认为是登录用户。

Python生态里可以用djangorestframework-simplejwt这个库,配置很少。登录视图大概是这样:

from rest_framework_simplejwt.views import TokenObtainPairView # urlpatterns里直接注册 urlpatterns = [ path('api/user/login/', TokenObtainPairView.as_view(), name='token_obtain_pair'), path('api/user/register/', register_view, name='register'), ]

用JWT之后,购物车和订单接口里就非常方便地能拿到当前登录用户:

from rest_framework.permissions import IsAuthenticated from rest_framework.views import APIView class CartView(APIView): permission_classes = [IsAuthenticated] def get(self, request): user = request.user # 查询该用户的购物车并返回

认证方案的选择影响后面所有接口,这个决策越早定越好。

3.3 药品列表、搜索和详情接口

药品模块的接口不需要太复杂,核心是“列表 + 搜索 + 详情”。

列表接口支持按分类筛选、按药品名模糊搜索、按价格排序,用Django的ORM查询集和DRF(Django REST Framework)很快就能实现:

from rest_framework.generics import ListAPIView from rest_framework.response import Response from .models import Drug from .serializers import DrugSerializer class DrugListView(ListAPIView): queryset = Drug.objects.all() serializer_class = DrugSerializer def get_queryset(self): queryset = super().get_queryset() category_id = self.request.query_params.get('category') keyword = self.request.query_params.get('keyword') ordering = self.request.query_params.get('ordering', 'id') if category_id: queryset = queryset.filter(category_id=category_id) if keyword: queryset = queryset.filter(name__icontains=keyword) if ordering in ['price', '-price', 'stock']: queryset = queryset.order_by(ordering) return queryset

这里有个小细节:icontains模糊搜索对中文很友好,比如搜索“感冒”,能把“感冒灵颗粒”“感冒清热胶囊”都捞出来。前端页面上再配合一个分类下拉框和搜索框,体验就很完整了。

3.4 购物车与订单接口设计

购物车和订单是整个系统交互最密集的地方。接口设计上按照Restful风格来,清晰明了:

接口方法作用
/api/cart/GET获取购物车列表
/api/cart/POST添加药品到购物车
/api/cart/{id}/PUT修改购物车某条记录的数量
/api/cart/{id}/DELETE删除某条购物车记录
/api/orders/POST提交订单,生成主表和明细表
/api/orders/GET获取当前用户的订单列表
/api/orders/{id}/GET获取订单详情

下单接口是最容易写砸的地方,因为它要同时做三件事:读取购物车数据、创建订单主记录、创建订单明细记录。而且这三件事必须“要么全部成功,要么全部失败”,绝不能出现“订单建了,明细丢了”这种半截状态。

用Django的transaction.atomic包起来:

from django.db import transaction class OrderCreateView(APIView): permission_classes = [IsAuthenticated] @transaction.atomic def post(self, request): user = request.user cart_items = CartItem.objects.filter(user=user).select_related('drug') if not cart_items.exists(): return Response({'msg': '购物车为空'}, status=400) total = 0 order = Order.objects.create( order_no=generate_order_no(), user=user, status='pending_payment', address_id=request.data.get('address_id') ) for item in cart_items: drug = item.drug # 检查库存 if drug.stock < item.quantity: raise ValueError(f'药品 {drug.name} 库存不足') # 创建订单明细 OrderItem.objects.create( order=order, drug=drug, drug_name=drug.name, price=drug.price, quantity=item.quantity ) total += drug.price * item.quantity # 扣库存(这一行放到最后统一处理) order.total_amount = total order.save() # 扣库存并清空购物车 for item in cart_items: drug = item.drug drug.stock -= item.quantity drug.save(update_fields=['stock']) cart_items.delete() return Response({'order_no': order.order_no, 'total_amount': str(total)})

这里有几个设计点是日常开发中总结出来的经验:

第一,明细表里存了drug_name和price快照,将来药品改名、改价,历史订单依然可追溯。

第二,扣库存动作单独放到最后统一处理,因为在拆解购物车数据阶段不应该提前修改库存。等订单确认要生成了,再一次性扣减,避免中途异常导致库存莫名其妙减少。

第三,total_amount计算过程中全部使用Decimal,最终输出时转成字符串str(total),绝不能直接返回浮点数给前端。

第四,更严谨的并发扣库存需要借助select_for_update()或数据库锁,但在基础版项目里,先做到事务和库存量检查,已经比大多数实现靠谱了。

3.5 订单状态机:别想得太简单

订单状态是整个后端的灵魂。常见的状态至少有这么几个:

状态值含义
pending_payment待付款
paid已付款,待发货
shipped已发货
completed已完成
canceled已取消

为什么要把状态做成一个状态机,而不是在视图函数里随便改?因为状态之间不是任意跳跃的。只有待付款订单可以取消;只有待付款订单可以变成已付款;已付款订单才能发货;已发货订单才能完成。如果代码里任何地方都能乱改状态,用不了几天数据就乱了。

我习惯在Order模型里写一个状态转换的方法:

class Order(models.Model): STATUS_CHOICES = [ ('pending_payment', '待付款'), ('paid', '已付款'), ('shipped', '已发货'), ('completed', '已完成'), ('canceled', '已取消'), ] status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending_payment') def can_pay(self): return self.status == 'pending_payment' def mark_paid(self): if not self.can_pay(): raise ValueError(f'订单状态不允许支付: {self.status}') self.status = 'paid' self.save(update_fields=['status']) def can_cancel(self): return self.status == 'pending_payment' def cancel(self): if not self.can_cancel(): raise ValueError('当前状态不可取消') self.status = 'canceled' self.save(update_fields=['status'])

这套方法把状态流转规则集中到了模型内部,后续在任何视图里调用都不会乱。代码审查的时候也容易看明白。

4. Vue前端怎么组织:药品浏览、购物车、下单页

4.1 页面和路由规划

Vue项目我用Vue CLI或Vite创建,配合Vue Router和Axios。页面不需要多,核心就四个:

  • 首页/药品列表页:展示药品、分类筛选、搜索
  • 药品详情页:展示药品详细信息、加入购物车
  • 购物车页:修改数量、勾选药品、去结算
  • 下单确认页:选择收货地址、确认订单、提交

路由配置里,购物车和下单页都要做登录校验,否则未登录用户不能访问:

// router/index.js const routes = [ { path: '/', name: 'DrugList', component: DrugList }, { path: '/drug/:id', name: 'DrugDetail', component: DrugDetail }, { path: '/cart', name: 'Cart', component: Cart, meta: { requiresAuth: true } }, { path: '/checkout', name: 'Checkout', component: Checkout, meta: { requiresAuth: true } }, ] router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !localStorage.getItem('token')) { next('/login') } else { next() } })

4.2 药品列表页的请求与渲染

列表页最常用的模式是“搜索框 + 分类侧边栏 + 药品卡片网格”。Axios请求封装成统一方法,把token带上:

// api/drug.js import axios from 'axios' import request from '../utils/request' export function getDrugList(params) { return request({ url: '/api/drugs/', method: 'get', params }) }

这里的params就是分类ID、关键词、排序字段。页面交互变化时,重新请求列表数据。为了提升体验,可以用loading状态控制页面加载提示,用computed计算筛选后的展示。

药品卡片上要同时展示药品名、规格、价格、库存状态。这里有一个交互细节:库存为0的药品不能直接禁用整个卡片,而是展示“缺货”标志,点击时提示用户“暂时缺货,关注补货”,这比直接隐藏商品更符合购药场景。

4.3 购物车的状态管理与勾选逻辑

购物车页在前端比较复杂的地方在于勾选结算。用户可能勾选两盒感冒药加一盒维生素,总价要实时计算,未勾选的商品不计入。这个用Vuex或Pinia管理购物车状态很合适。

我用的思路是:

  • 购物车数据存在Vuex里,用户进入购物车页时调用fetchCart获取后端数据。
  • 每个购物车条目有一个selected字段,默认全选。
  • 页面底部显示“已选x件商品,合计xxx元”,用getters计算已选条目和总价。
// store/cart.js 核心getter getters: { selectedItems(state) { return state.items.filter(item => item.selected) }, selectedTotal(state, getters) { return getters.selectedItems.reduce((sum, item) => { return sum + parseFloat(item.drug.price) * item.quantity }, 0) } }

这个设计是参考电商平台最常见的模式,前端只负责展示和计算,后端以购物车原始数据为准。提交订单时,把选中的购物车条目的ID列表传给后端,后端根据ID去数据库里关联用户后再创建订单。千万不要把前端计算的总价当真,后端的total_amount才是一锤定音的数据源。

4.4 下单页与订单提交后的跳转逻辑

下单页需要调用“获取默认地址”和“创建订单”两个接口。创建订单成功后,理想情况是跳转到支付页或订单详情页,但因为是学习项目,可以做成“模拟支付成功”按钮,点击后调用支付确认接口,把订单状态从pending_payment推到paid。

这里有一个很重要的交互逻辑:创建订单成功后要清空购物车数据。我在实践中会先调创建订单接口,成功后调“清空已购商品”的后端接口,同时清空Vuex里的购物车items。这样用户返回购物车页时,已经下单的商品不会重现。

订单提交后的跳转要避免用户重复提交。按钮要加submitting状态,提交期间禁用并显示“处理中”,否则用户手快点两次,后端虽然只有第一次会成功,但前端体验会很糟糕。

5. 联调阶段最常见的三个坑:跨域、时区、金额

5.1 跨域问题:为什么请求发不出去

前后端分离项目最常见的第一道坎就是CORS(跨域资源共享)。Django后端跑在8000端口,Vue前端跑在8080端口,浏览器默认不允许不同源的前端页面调用后端接口,于是控制台报错CORS。

解决方式是在Django里用django-cors-headers:

pip install django-cors-headers

然后在settings.py里配置:

INSTALLED_APPS = [ ... 'corsheaders', ] MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', ... ] CORS_ALLOWED_ORIGINS = [ 'http://localhost:8080', ] CORS_ALLOW_CREDENTIALS = True

配置完重启Django服务,跨域问题就解决了。如果前端用https域名或者部署后的IP地址,记得加到CORS_ALLOWED_ORIGINS列表里。

5.2 Django时区配置:为什么订单时间差了8小时

这是联调时最容易迷惑的问题。Django默认的TIME_ZONE = 'UTC'配合USE_TZ = True,数据库存的时间是UTC,而中国在东八区,前端展示订单创建时间时会出现8个小时的偏差。

最简单的处理方案,在开发阶段把配置改成:

TIME_ZONE = 'Asia/Shanghai' USE_TZ = False

注意:USE_TZ = False时,Django按本地时间存储和读取,对学习和演示项目最直观。如果未来上生产环境,建议用USE_TZ = True并统一转成用户时区展示,但那是更复杂的方案,这里不展开。

改完配置后重建数据库或清空旧数据,再重新下单测试时间就对了。

5.3 金额精度:前端展示和后端计算的微妙关系

前后端联调时总金额不一致,十有八九是浮点数精度问题。前端的parseFloat(item.drug.price)在计算合计时可能出现9.999999之类的浮点尾巴,显示出来很难看,也更让用户困惑。

前端展示金额,建议统一用toFixed(2)处理,或者用整数分单位计算。不过最稳妥的原则是:前端价格只做展示,不做后端信任的数据源;后端订单总价必须自己根据购物车明细重新计算,并且用Decimal存储。

开发时验证一下这个原则很简单:前端选两件价格是13.49和8.98的药品,如果后端算出来是11.47之类的乱七八糟数字,说明某个环节浮点精度崩了。正确结果应该永远是22.47整。

6. 踩坑实录:订单支付后状态一直不更新的完整排查过程

6.1 现象与复现条件

这个项目的联调阶段,我遇到过最典型的Bug是:用户在前端点“模拟支付成功后”,页面提示成功了,订单状态也一度变成了已付款。但是刷新页面再看订单列表,订单状态又变回了“待付款”。反复复现,每次都这样。

这种现象特别有欺骗性:接口看起来成功了,数据也变化过,但最终结果却不对。它既不是完全没写,也不是报错,而是“中间出了岔子被回滚了”。

6.2 排查链路:从现象一路倒查

我的排错习惯是沿着“前端 → 接口 → 后端逻辑 → 数据库”逐层倒查。

先看前端的请求。打开浏览器开发者工具,Network面板里查看“模拟支付”请求的响应的确返回了成功。这个请求是POST /api/orders/{id}/pay/,状态码200,返回体里写着status: paid。到这一步,前端没有问题。

再看后端日志。Django控制台没有明显报错,但为了保险,我在pay视图里打了一行print,确认请求进到了支付逻辑里。接着查数据库,发现订单状态确实是“待付款”。问题来了:为什么接口返回paid,数据库还是pending_payment?

到这里我开始怀疑是有代码在支付成功后把状态改回去了。顺着这个思路检查订单详情接口、订单列表接口,最终定位到订单模型的save()方法重载上。

6.3 根因:一行被遗忘的save逻辑

问题不在支付逻辑,而在于我之前为了给订单自动生成订单号,重载了模型的save()方法,并在里面根据订单号是否为空来决定是否补一个order_no。但人不小心把逻辑写成了:

def save(self, *args, **kwargs): if not self.order_no: self.order_no = generate_order_no() super().save(*args, **kwargs)

表面看这没问题。问题出在支付视图调用mark_paid()时我写了self.save(update_fields=['status'])。因为update_fields只更新status字段,而模型里的super().save()执行时,如果不传update_fields,Django会保存所有字段的最新值。问题不是这里。

真正触雷的是另一行:在我给订单列表接口返回数据时,我顺手对查询出来的每个订单调用了serializer输出,而在某个工具函数里写了一段逻辑:“如果订单处于待付款状态超过1小时,自动取消订单”。这段逻辑被放进了list接口的序列化流程里。支付成功后,列表接口刷新时拿到订单,检测到pending_payment已超时,于是自动置为canceled。但页面显示的是待付款回退的现象是因为自动取消后又被另一个“恢复待付款”的兜底逻辑改了回来,两个逻辑打架,把状态来回拉扯。

这个坑的教训非常直接:不要把业务副作用塞进序列化过程,更不要在读取数据的接口里偷偷写数据。查询就是查询,状态变更必须走明确的动作方法。清理掉那两段自动逻辑之后,订单状态完全正常。

6.4 排查习惯与预防清单

那次排错之后,我给自己定了一个清单,每次遇到状态不对的问题都先过一遍:

排查项检查内容
前端传参请求体字段名和后端期望是否一致
接口返回响应状态码和返回数据是否与业务预期一致
后端日志视图函数是否执行到预期位置
数据库落库目标字段是否真的写入预期值
是否存在中途覆盖查询接口、序列化器、模型save是否偷偷改数据
并发与事务是否有其他进程或事务回滚了本次修改

这个清单看起来简单,但大部分“接口成功但数据不对”的问题都能通过它定位。排查时最忌讳直接改代码瞎碰,一层层验证,故障点自然就浮出来了。

7. 项目跑通之后的优化方向与我的个人体会

基础版本跑通之后,如果你的目标是毕业设计拿个好分数,或者想把项目写进简历,我建议再往这几个方向延展一下。这也是我在实际迭代中觉得最有价值的部分。

第一,为购物车和订单增加缓存层。高频读取的药品分类和热门药品列表,可以用Redis或Django缓存框架存起来,减少数据库压力。这个优化点写进项目介绍里特别加分。

第二,补一个简单的后台销售统计接口。用Django的ORM聚合查询,统计每天订单量、销售额、热门药品TOP5。前端用图表库展示,项目从“功能型”升级为“带数据分析型”,整体含金量提高不少。

第三,药品库存预警。后台设置一个库存阈值,低于阈值的药品在Admin后台和列表接口里都显示“库存告急”,这是药房业务非常有实际意义的场景。

第四,把支付流程替换成真实的第三方支付沙箱环境。毕业设计如果只停留在“模拟支付”,答辩时很容易被追问;接一个沙箱环境,代码复杂度和说服力都会上去。

最后说几句个人体会。这类全栈项目,我在实际开发中最受益的是习惯“先设计状态和数据关系,再写视图”。商城系统的坑很少在语法层面,而几乎全部都集中在“状态修改、金额计算、库存并发”这三件事上。如果你刚开始写,建议一步一步来:先把Django后端的订单和购物车逻辑用postman测到稳,再动Vue页面;宁可前端页面丑一点,也不能让订单逻辑飘。

还有一个小技巧:在PyCharm里给Django配置好断点调试之后,遇到任何“奇怪的问题”第一反应不要是加print,而是打断点看数据。亲眼看到某一行数据不对劲,比自己脑补一遍要高效得多。这个习惯保留下来,后面做任何项目都受用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/15 18:56:03

OpenDroid权限配置全指南:无障碍服务等5大权限如何一次配齐

【免费下载链接】opendroid Your Open Autonomous Android Agent — A production-ready, self-planning AI assistant powered by local/remote LLMs and accessibility-driven screen automation. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/op/opendroid 点击查看…

作者头像 李华
网站建设 2026/10/15 18:55:09

RDKit 机器学习数据统计模块 `rdkit.ML.Data.Stats` 源码级解析

科学计算科研机器学习 【免费下载链接】rdkit The official sources for the RDKit library 项目地址&#xff1a; https://gitcode.com/gh_mirrors/rd/rdkit 点击查看 免费下载 rdkit.ML.Data.Stats 是 RDKit 机器学习子包&#xff08;rdkit.ML&#xff09;中用于数据矩阵统计…

作者头像 李华
网站建设 2026/10/15 18:54:56

PyTorch目标检测训练避坑指南:数据格式、损失拆解与训练稳定性

1. 为什么“从零训练一个目标检测模型”比想象中更像重新学开车很多人点开“PyTorch目标检测训练教程”时&#xff0c;心里想的是&#xff1a;“不就是换掉数据集、改几行路径、跑个train.py吗&#xff1f;”——我试过三次&#xff0c;每次都在第47分钟崩溃。第一次卡在DataLo…

作者头像 李华
网站建设 2026/10/15 18:54:19

影刀RPA深度实战:电商数据采集系统从0到1完整搭建手册

影刀RPA深度实战&#xff1a;电商数据采集系统从0到1完整搭建手册 作者&#xff1a;林焱 做电商数据采集的时候&#xff0c;最头疼的不是元素抓不到&#xff0c;而是流程跑两天就崩——元素失效、页面加载超时、数据重复、异常中断后无法续跑。我之前做一个小红书采集项目的时候…

作者头像 李华
网站建设 2026/10/15 18:52:56

STM8驱动LT8920 2.4G模块:SPI通信、寄存器配置与低功耗实战

简介&#xff1a;这份资源是面向嵌入式开发者的LT8920 2.4G无线模块测试程序&#xff0c;基于STM8微控制器实现&#xff0c;适合初学者入门2.4G无线通信&#xff0c;也可作为有经验开发者的参考资料。压缩包共62个文件&#xff0c;约825KB&#xff0c;包含8个c源文件与8个h头文…

作者头像 李华