当前位置: 首页 > news >正文

169-Django二手交易校园购物系统开发分享

基于Django的二手交易校园购物系统开发分享

📋 项目概述

本项目是一个基于Django框架开发的二手交易校园购物系统,专为校园内的二手商品交易而设计。系统采用B/S架构,提供了完整的电商交易功能,包括用户管理、商品管理、购物车、订单处理、消息系统等核心模块。

基于Django的二手交易校园购物系统

🎯 项目目标

  • 为校园师生提供便捷的二手商品交易平台
  • 实现完整的电商交易流程
  • 提供用户友好的界面和交互体验
  • 确保交易安全和数据完整性

🏗️ 技术架构

后端技术栈

  • 框架: Django 2.0.7
  • 数据库: MySQL (通过PyMySQL连接)
  • ORM: Django ORM
  • 邮件服务: SMTP (163邮箱)
  • 图片处理: Pillow 7.1.1
  • 时区处理: pytz 2018.7
  • 富文本编辑: django-tinymce 2.7.0
  • 后台管理: django-simpleui

前端技术栈

  • HTML/CSS: 原生HTML和CSS
  • JavaScript:
    • jQuery 1.12.4
    • jQuery UI
    • jQuery Cookie
    • 自定义JS组件
  • 字体: FreeMonospaced字体
  • 响应式设计: CSS实现

数据库设计

  • 数据库类型: MySQL
  • 字符集: UTF-8
  • 存储引擎: MyISAM
  • 主要数据表: 用户、商品、购物车、订单、评论、消息等

📁 项目结构

tiaozao_shop/
├── apps/                    # 应用模块
│   ├── df_user/            # 用户管理模块
│   ├── df_goods/           # 商品管理模块
│   ├── df_cart/            # 购物车模块
│   ├── df_order/           # 订单管理模块
│   └── utils/              # 工具模块
├── tiaozao_shop/           # 项目配置
│   ├── settings.py         # 项目设置
│   ├── urls.py            # 主路由配置
│   └── wsgi.py            # WSGI配置
├── static/                 # 静态文件
│   ├── css/               # 样式文件
│   ├── js/                # JavaScript文件
│   ├── images/            # 图片资源
│   └── asserts/           # 其他资源
├── templates/              # 模板文件
├── media/                  # 媒体文件
├── requirements.txt        # 依赖包列表
├── manage.py              # Django管理脚本
└── design_169_market.sql  # 数据库结构文件

🔧 核心功能模块

1. 用户管理模块 (df_user)

用户注册与登录
  • 用户注册: 支持用户名、密码、邮箱注册,包含邮箱唯一性验证
  • 用户登录: 集成验证码验证,支持记住用户名功能
  • 密码安全: 使用SHA1加密存储密码
  • 账号退出: 安全退出,清除session信息
用户信息管理
  • 个人信息: 支持头像上传、个人资料编辑
  • 收货地址: 收货人、地址、邮编、手机号管理
  • 实名认证: 证件类型、证件号码、证件图片上传
  • 密码管理: 密码修改、密码重置(邮件发送)
用户信息修改
@user_decorator.login
def changeInformation(request):uid = request.session['user_id']user = UserInfo.objects.get(id=uid)cart_num = CartInfo.objects.filter(user_id=user.id).count()context = {'page_name': 1,'title': '用户中心','user': user,'guest_cart': 1,'cart_num': cart_num,}if request.method == "POST":logo = request.FILES.get('logo')if logo:user.ulogo = logoelse:user.ulogo = user.ulogouser.usex = request.POST.get('sex')user.uage = request.POST.get('age')user.upersonInf = request.POST.get('personinf')user.save()return render(request, 'df_user/user_changeInformation.html', context)
用户中心信息展示
@user_decorator.login
def info(request):  # 用户中心uid = request.session['user_id']user = UserInfo.objects.get(id=uid)browser_goods = GoodsBrowser.objects.filter(user=user).order_by("-browser_time")cart_num = CartInfo.objects.filter(user_id=int(uid)).count()goods_list = []if browser_goods:goods_list = [browser_good.good for browser_good in browser_goods]  # 从浏览商品记录中取出浏览商品explain = '最近浏览'else:explain = '无最近浏览'context = {'title': '用户中心','page_name': 1,'guest_cart': 1,'cart_num': cart_num,'user_phone': user.uphone,'user_address': user.uaddress,'user_name': user.uname,'user': user,'ucheck_passOrfail': user.ucheck_passOrfail,'goods_list': goods_list,'explain': explain,}return render(request, 'df_user/user_center_info.html', context)
收货地址管理
@user_decorator.login
def site(request):user = UserInfo.objects.get(id=request.session['user_id'])cart_num = CartInfo.objects.filter(user_id=user.id).count()if request.method == "POST":user.ushou = request.POST.get('ushou')user.uaddress = request.POST.get('uaddress')user.uyoubian = request.POST.get('uyoubian')user.uphone = request.POST.get('uphone')user.save()context = {'page_name': 1,'title': '用户中心','user': user,'guest_cart': 1,'cart_num': cart_num,}return render(request, 'df_user/user_center_site.html', context)
密码重置(邮件发送)
def findpwdView(request):context = {'title': '重置密码',}if request.method=="POST":username = request.POST.get("username")email = request.POST.get("email")user = UserInfo.objects.get(uname=username)context = {'title': '重置密码','user': user,}if user.uemail == email:email_title = "二手商品交易平台-重置密码"code = random_str()  # 随机生成的验证码request.session["code"] = code  # 将验证码保存到sessionemail_body = "您的密码已重置,为了您的账号安全,请勿将密码泄露。新的密码为:{0}".format(code)# send_mail的参数分别是 邮件标题,邮件内容,发件箱,收件箱列表,失败静默send_status = send_mail(email_title, email_body, 'woaisilaowu@163.com', [email], fail_silently=False)code = request.session["code"] # 获取传递过来的验证码# 密码加密s1 = sha1()s1.update(code.encode('utf8'))encrypted_pwd = s1.hexdigest()user.upwd = encrypted_pwduser.save()del request.session["code"]  # 删除sessionmessages.success(request, "密码已重置,请登录邮箱接受重置密码!")else:messages.success(request, "用户邮箱与输入邮件不匹配,重置失败!")return render(request,"df_user/change_password1.html",context)return render(request, "df_user/change_password1.html",context)
用户权限控制
  • 登录验证: 使用装饰器进行登录状态验证
  • 账号封禁: 支持违规账号封禁功能
  • 认证审批: 实名认证审批流程

2. 商品管理模块 (df_goods)

商品展示
  • 首页展示: 按分类展示最新和热门商品
  • 商品列表: 分页展示,支持排序(最新、价格、人气)
  • 商品详情: 完整商品信息展示
  • 商品搜索: 支持标题、内容、简介关键词搜索
商品发布
  • 商品发布: 支持图片上传、价格设置、库存管理
  • 商品分类: 书籍、家电、衣物、出行、乐器、智能
  • 商品编辑: 商品信息修改和更新
商品发布实现
@user_decorator.login
def publishers(request):user = UserInfo.objects.get(id=request.session['user_id'])cart_num = CartInfo.objects.filter(user_id=user.id).count()typeinfos = TypeInfo.objects.all()if request.method == "POST":gtitle = request.POST.get('title')gpic = request.FILES.get('pic')gunit = user.unamegprice = request.POST.get('price')gjianjie = request.POST.get('jianjie')gkucun = request.POST.get('kucun')gcontent = request.POST.get('content')gtype_id = request.POST.get('type_id')if gtitle=="" or gpic=="" or gprice=="" or gjianjie=="" or gkucun=="" or gcontent=="":messages.success(request, "请完整填充信息!")elif int(gprice) >=100000:messages.success(request, "价格不能大于100000!")else:GoodsInfo.objects.create(gtitle=gtitle, gpic=gpic, gunit=gunit, gprice=gprice,gjianjie=gjianjie, gkucun=gkucun, gcontent=gcontent, gtype_id=gtype_id)messages.success(request, "发布商品成功")context = {'page_name': 1,'title': '用户中心','user': user,'typeinfos': typeinfos,'guest_cart': 1,'cart_num': cart_num,}return render(request, 'df_user/user_publishers.html', context)
首页商品展示实现
def index(request):# 查询各个分类的最新4条,最热4条数据username = request.session.get('user_name')user = UserInfo.objects.filter(uname=username).first()# 联系客服功能username1 = "customer"informations = Information.objects.filter()# 判断用户是否给客服发过信息informations1 = Information.objects.filter(cusername1=username, cusername=username1)import datetimenowTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')  # 现在# 消息回复user_name = UserInfo.objects.get(uname=username1)  # 获取当前消息用户信息if request.method == "POST":cusername = user.unamecusername1 = user_name.unameccontent_chart = request.POST.get('title')cinformation_id = user_name.idif ccontent_chart == "":messages.success(request, "请输入内容!")else:Information.objects.create(cusername=cusername, cusername1=cusername1,ccontent_chart=ccontent_chart, cinformation_id=cinformation_id)messages.success(request, "消息发送成功")return redirect(reverse("df_goods:index"))typelist = TypeInfo.objects.all()# _set 连表操作type0 = typelist[0].goodsinfo_set.order_by('-id')[0:4]  # 按照上传顺序type01 = typelist[0].goodsinfo_set.order_by('-gclick')[0:4]  # 按照点击量type1 = typelist[1].goodsinfo_set.order_by('-id')[0:4]type11 = typelist[1].goodsinfo_set.order_by('-gclick')[0:4]type2 = typelist[2].goodsinfo_set.order_by('-id')[0:4]type21 = typelist[2].goodsinfo_set.order_by('-gclick')[0:4]type3 = typelist[3].goodsinfo_set.order_by('-id')[0:4]type31 = typelist[3].goodsinfo_set.order_by('-gclick')[0:4]type4 = typelist[4].goodsinfo_set.order_by('-id')[0:4]type41 = typelist[4].goodsinfo_set.order_by('-gclick')[0:4]type5 = typelist[5].goodsinfo_set.order_by('-id')[0:4]type51 = typelist[5].goodsinfo_set.order_by('-gclick')[0:4]cart_num = 0# 判断是否存在登录状态if 'user_id' in request.session:user_id = request.session['user_id']cart_num = CartInfo.objects.filter(user_id=int(user_id)).count()context = {'title': '首页','cart_num': cart_num,'guest_cart': 1,'type0': type0, 'type01': type01,'type1': type1, 'type11': type11,'type2': type2, 'type21': type21,'type3': type3, 'type31': type31,'type4': type4, 'type41': type41,'type5': type5, 'type51': type51,'user': user,'informations': informations,'informations1': informations1,'username1': username1,'user_name': user_name,'nowTime': nowTime,}return render(request, 'df_goods/index.html', context)
商品搜索实现
def ordinary_search(request):username = request.session.get('user_name')user = UserInfo.objects.filter(uname=username).first()from django.db.models import Qsearch_keywords = request.GET.get('q', '')pindex = request.GET.get('pindex', 1)search_status = 1cart_num, guest_cart = 0, 0try:user_id = request.session['user_id']except:user_id = Noneif user_id:guest_cart = 1cart_num = CartInfo.objects.filter(user_id=int(user_id)).count()# 使用Q对象进行复杂查询goods_list = GoodsInfo.objects.filter(Q(gtitle__icontains=search_keywords) |Q(gcontent__icontains=search_keywords) |Q(gjianjie__icontains=search_keywords)).order_by("gclick")if goods_list.count() == 0:# 商品搜索结果为空,返回推荐商品search_status = 0goods_list = GoodsInfo.objects.all().order_by("gclick")[:4]paginator = Paginator(goods_list, 4)page = paginator.page(int(pindex))context = {'title': '搜索列表','search_status': search_status,'guest_cart': guest_cart,'cart_num': cart_num,'page': page,'paginator': paginator,'user': user,}return render(request, 'df_goods/ordinary_search.html', context)
商品互动
  • 商品评论: 支持图片上传的评论系统
  • 评论管理: 评论分页展示和管理
  • 点击统计: 商品点击量统计
  • 浏览记录: 用户浏览历史记录
商品详情与点击统计
def detail(request, gid):if 'user_id' in request.session:uid = request.session['user_id']user = UserInfo.objects.get(id=uid)good_id = gidgoods = GoodsInfo.objects.get(pk=int(good_id))goods.gclick = goods.gclick + 1  # 商品点击量goods.save()news = goods.gtype.goodsinfo_set.order_by('-id')[0:2]context = {'title': goods.gtype.ttitle,'guest_cart': 1,'cart_num': cart_count(request),'goods': goods,'news': news,'id': good_id,'user': user,}response = render(request, 'df_goods/detail.html', context)# 记录用户浏览历史try:browsed_good = GoodsBrowser.objects.get(user_id=int(uid), good_id=int(good_id))except Exception:browsed_good = Noneif browsed_good:from datetime import datetimebrowsed_good.browser_time = datetime.now()browsed_good.save()else:GoodsBrowser.objects.create(user_id=int(uid), good_id=int(good_id))browsed_goods = GoodsBrowser.objects.filter(user_id=int(uid))browsed_good_count = browsed_goods.count()if browsed_good_count > 5:ordered_goods = browsed_goods.order_by("-browser_time")for _ in ordered_goods[5:]:_.delete()return response
商品评论发布
def content(request, gid, pindex):if 'user_id' in request.session:uid = request.session['user_id']user = UserInfo.objects.get(id=uid)good_id = gidgoods = GoodsInfo.objects.get(pk=int(good_id))# 获取当前货物信息news = goods.gtype.goodsinfo_set.order_by('-id')[0:2]# 条件查询goodsContents = GoodsContent.objects.filter(cgoodsname_id=good_id).order_by('-date_publish')# 创建Paginator一个分页对象paginator = Paginator(goodsContents, 2)# 返回Page对象,包含商品信息page = paginator.page(int(pindex))context = {'title': goods.gtype.ttitle,'guest_cart': 1,'cart_num': cart_count(request),'goods': goods,'id': good_id,'news': news,'user': user,'goodsContents': goodsContents,'paginator': paginator,'page': page,}if request.method == "POST":ctitle = goods.gtitlecpic = request.FILES.get('pic')cusername = user.unameclogo = user.ulogocuser_content = request.POST.get('text')cgoodsname_id = goods.idif cpic == "":GoodsContent.objects.create(ctitle=ctitle, cusername=cusername, cuser_content=cuser_content, cgoodsname_id=cgoodsname_id, clogo=clogo)messages.success(request, "评论成功!")else:GoodsContent.objects.create(ctitle=ctitle, cpic=cpic, cusername=cusername, cuser_content=cuser_content, cgoodsname_id=cgoodsname_id, clogo=clogo)messages.success(request, "评论成功!")return render(request, 'df_goods/content.html', context)

3. 购物车模块 (df_cart)

购物车功能
  • 添加商品: 支持数量选择的商品添加
  • 数量修改: 实时修改购物车商品数量
  • 商品删除: 从购物车中删除商品
  • 购物车展示: 购物车商品列表和统计
购物车管理
  • 用户关联: 购物车与用户账号关联
  • 数据持久化: 购物车数据数据库存储
  • AJAX交互: 异步更新购物车信息
购物车添加商品
@user_decorator.login
def add(request, gid, count):uid = request.session['user_id']gid, count = int(gid), int(count)# 查询购物车中是否已经有此商品,如果有则数量增加,如果没有则新增carts = CartInfo.objects.filter(user_id=uid, goods_id=gid)if len(carts) >= 1:cart = carts[0]cart.count = cart.count + countelse:cart = CartInfo()cart.user_id = uidcart.goods_id = gidcart.count = countcart.save()# 如果是ajax提交则直接返回json,否则转向购物车if request.is_ajax():count = CartInfo.objects.filter(user_id=request.session['user_id']).count()return JsonResponse({'count': count})else:return redirect(reverse("df_cart:cart"))
购物车商品数量修改
@user_decorator.login
def edit(request, cart_id, count):data = {}try:cart = CartInfo.objects.get(pk=int(cart_id))cart.count = int(count)cart.save()data['count'] = 0except Exception:data['count'] = countreturn JsonResponse(data)
购物车商品删除
@user_decorator.login
def delete(request, cart_id):data = {}try:cart = CartInfo.objects.get(pk=int(cart_id))cart.delete()data['ok'] = 1except Exception:data['ok'] = 0return JsonResponse(data)
购物车展示
@user_decorator.login
def user_cart(request):uid = request.session['user_id']username = request.session.get('user_name')user = UserInfo.objects.filter(uname=username).first()carts = CartInfo.objects.filter(user_id=uid)cart_num = CartInfo.objects.filter(user_id=uid).count()context = {'title': '购物车','page_name': 1,'guest_cart': 1,'carts': carts,'cart_num': cart_num,'user': user,}if request.is_ajax():count = CartInfo.objects.filter(user_id=request.session['user_id']).count()# 求当前用户购买了几件商品return JsonResponse({'count': count})else:return render(request, 'df_cart/cart.html', context)

4. 订单管理模块 (df_order)

订单处理
  • 订单创建: 从购物车创建订单
  • 订单信息: 收货地址、联系方式管理
  • 价格计算: 商品总价、运费、总金额计算
  • 库存检查: 下单时检查商品库存
订单管理
  • 订单状态: 订单状态跟踪和管理
  • 订单历史: 用户订单历史记录
  • 事务处理: 使用数据库事务确保数据一致性
订单创建与事务处理
@user_decorator.login
@transaction.atomic()  # 事务
def order_handle(request):uid = request.session['user_id']user = UserInfo.objects.get(id=uid)tran_id = transaction.savepoint()  # 保存事务发生点cart_ids = request.POST.get('cart_ids')  # 用户提交的订单购物车user_id = request.session['user_id']data = {}try:order_info = OrderInfo()  # 创建一个订单对象now = datetime.now()order_info.oid = '%s%d' % (now.strftime('%Y%m%d%H%M%S'), user_id)  # 订单号order_info.odate = now  # 订单时间order_info.user_id = int(user_id)  # 订单的用户idorder_info.ototal = Decimal(request.POST.get('total'))  # 订单总价order_info.oaddress = user.uaddressorder_info.save()for cart_id in cart_ids.split(','):  # 逐个处理购物车商品cart = CartInfo.objects.get(pk=cart_id)order_detail = OrderDetailInfo()order_detail.order = order_infogoods = cart.goodsif cart.count <= goods.gkucun:  # 判断库存是否满足订单goods.gkucun = goods.gkucun - cart.countgoods.save()order_detail.goods = goodsorder_detail.price = goods.gpriceorder_detail.count = cart.countorder_detail.username = user.unameorder_detail.shopername = goods.gunitorder_detail.save()cart.delete()  # 删除购物车else:  # 库存不足,事务回滚transaction.savepoint_rollback(tran_id)return HttpResponse('库存不足')data['ok'] = 1transaction.savepoint_commit(tran_id)except Exception as e:print("%s" % e)print('未完成订单提交')transaction.savepoint_rollback(tran_id)  # 事务回滚return JsonResponse(data)

5. 消息系统

用户消息
  • 消息发送: 用户间消息发送功能
  • 消息中心: 消息列表和详情展示
  • 已读状态: 消息已读状态管理
  • 消息历史: 消息历史记录保存
客服功能
  • 客服消息: 与客服的沟通功能
  • 消息回复: 消息回复和对话功能
消息中心实现
@user_decorator.login
def message(request):user = UserInfo.objects.get(id=request.session['user_id'])cart_num = CartInfo.objects.filter(user_id=user.id).count()# 消息用户名去重persons = Information.objects.filter(cinformation_id=user.id).values('cusername','ccheck').distinct().order_by('cusername')# 查询发消息者的头像imgs = UserInfo.objects.filter()context = {'title': '消息中心','page_name': 1,'user': user,'persons': persons,'imgs': imgs,'guest_cart': 1,'cart_num': cart_num,'username': user.uname,}return render(request, 'df_user/user_messages.html', context)
消息详情与回复
@user_decorator.login
def person_message(request):user = UserInfo.objects.get(id=request.session['user_id'])  # 当前登录用户cart_num = CartInfo.objects.filter(user_id=user.id).count()# 消息用户名去重persons = Information.objects.filter(cinformation_id=user.id).values('cusername','ccheck').distinct().order_by('cusername')# 查询发消息者的头像imgs = UserInfo.objects.filter()# 展示消息username = request.GET['username']informations = Information.objects.filter()logo = UserInfo.objects.get(uname=username)# 展示消息后使消息变为已读状态for information in informations:if information.cusername == username:information.ccheck = Trueinformation.save()# 消息回复user_name = UserInfo.objects.get(uname=username)  # 获取当前消息用户信息if request.method == "POST":cusername = user.unamecusername1 = user_name.unameccontent_chart = request.POST.get('title')cinformation_id = user_name.idif ccontent_chart == "":messages.success(request, "请输入内容!")else:Information.objects.create(cusername=cusername, cusername1=cusername1,ccontent_chart=ccontent_chart, cinformation_id=cinformation_id)messages.success(request, "消息发送成功")return redirect(reverse("df_user:message"))context = {'title': '消息中心','page_name': 1,'user': user,'informations': informations,'persons': persons,'imgs': imgs,'logo': logo,'username': username,'user_name': user_name,'guest_cart': 1,'cart_num': cart_num,}return render(request, 'df_user/user_messages.html', context)

6. 退货退款功能

退货申请
  • 退货提交: 退货申请信息填写
  • 退货信息: 快递信息、地址、退货理由
  • 审批流程: 退货申请审批管理
  • 状态跟踪: 退货状态跟踪
退货申请实现
@user_decorator.login
def tuihuo(request):uid = request.session['user_id']user = UserInfo.objects.get(id=uid)if request.method == "POST":title = request.POST.get('title')username = request.POST.get('username')username1 = request.POST.get('username1')person_number = request.POST.get('person_number')order_number = request.POST.get('order_number')kuaidi = request.POST.get('kuaidi')kuaidi_number = request.POST.get('kuaidi_number')address = request.POST.get('address')address1 = request.POST.get('address1')text = request.POST.get('text')if title == "" or username == "" or username1 == "" or person_number == "" or order_number == "" or kuaidi == "" or kuaidi_number == "" or address == "" or address1 == "":messages.success(request, "请填写完整信息!")else:tuihuoInfo.objects.create(title=title, username=username, username1=username1,person_number=person_number, order_number=order_number,kuaidi=kuaidi, kuaidi_number=kuaidi_number,address=address, address1=address1, text=text)messages.success(request, "提交成功,等待审批!")return redirect(reverse("df_user:info"))context = {'title': '填写退货信息','page_name': 1,'user': user,}return render(request, 'df_user/tuihuo.html', context)
订单管理实现
@user_decorator.login
def order(request, index):user_id = request.session['user_id']orders_list = OrderInfo.objects.filter(user_id=int(user_id)).order_by('-odate')cart_num = CartInfo.objects.filter(user_id=int(user_id)).count()tuohuo_infos = tuihuoInfo.objects.filter()paginator = Paginator(orders_list, 2)page = paginator.page(int(index))user = UserInfo.objects.get(id=request.session['user_id'])context = {'paginator': paginator,'page': page,'title': "用户中心",'user': user,'page_name': 1,'guest_cart': 1,'cart_num': cart_num,'tuohuo_infos': tuohuo_infos,}return render(request, 'df_user/user_center_order.html', context)

🎨 界面设计

首页设计

  • 轮播图: 商品轮播展示
  • 分类导航: 商品分类快速导航
  • 热门商品: 按点击量排序的热门商品
  • 最新商品: 按时间排序的最新商品

用户界面

  • 响应式设计: 适配不同屏幕尺寸
  • 用户友好: 简洁直观的操作界面
  • 交互反馈: 操作成功/失败提示
  • 加载优化: 页面加载性能优化

🔒 安全特性

数据安全

  • 密码加密: SHA1加密存储用户密码
  • 验证码: 图片验证码防止恶意注册
  • Session管理: 安全的用户会话管理
  • SQL注入防护: 使用Django ORM防止SQL注入
密码加密实现
def register_handle(request):username = request.POST.get('user_name')password = request.POST.get('pwd')confirm_pwd = request.POST.get('confirm_pwd')email = request.POST.get('email')# 判断两次密码一致性if password != confirm_pwd:return redirect('/user/register/')# 密码加密s1 = sha1()s1.update(password.encode('utf8'))encrypted_pwd = s1.hexdigest()# 创建对象UserInfo.objects.create(uname=username, upwd=encrypted_pwd, uemail=email)
验证码生成实现
def verify_code(request):import random# 定义变量,用于画面的背景色、宽、高bgcolor = (224, 224, 224)width = 100height = 34# 创建画面对象im = Image.new('RGB', (width, height), bgcolor)# 创建画笔对象draw = ImageDraw.Draw(im)# 调用画笔的point()函数绘制噪点for i in range(0, 100):xy = (random.randrange(0, width), random.randrange(0, height))fill = (random.randrange(0, 255), 255, random.randrange(0, 255))draw.point(xy, fill=fill)# 定义验证码的备选值str1 = 'abcdefghijklmnopqrstuvwsyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'# 随机选取4个值作为验证码rand_str = ''for i in range(0, 4):rand_str += str1[random.randrange(0, len(str1))]# 构造字体对象font = ImageFont.truetype('arial.ttf', 23)# 构造字体颜色fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))# 绘制4个字draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)# 存入session,用于做进一步验证request.session['verifycode'] = rand_str# 内存文件操作buf = BytesIO()# 将图片保存在内存中,文件类型为pngim.save(buf, 'png')# 将内存中的图片数据返回给客户端,MIME类型为图片pngreturn HttpResponse(buf.getvalue(), 'image/png')

权限控制

  • 登录验证: 严格的登录状态验证
  • 权限装饰器: 自定义权限验证装饰器
  • 账号封禁: 违规账号封禁机制
  • 实名认证: 用户身份验证机制
实名认证实现
@user_decorator.login
def check_user(request):user = UserInfo.objects.get(id=request.session['user_id'])cart_num = CartInfo.objects.filter(user_id=user.id).count()if request.method == "POST":user.urealname = request.POST.get('name')user.uzhengjian_type = request.POST.get('type_id')user.uzhengjian_tel = request.POST.get('tel')user.uzhengjian_img = request.FILES.get('pic')if user.urealname == None or user.uzhengjian_type == None or user.uzhengjian_tel == None or user.uzhengjian_img == None:print("error:请填写完整信息")messages.success(request, "请填写完整信息")else:user.save()print("请等待审批")messages.success(request, "提交成功,请等待审批")context = {'page_name': 1,'title': '用户中心','user': user,'guest_cart': 1,'cart_num': cart_num,}return render(request, 'df_user/user_check_username.html', context)
密码修改实现
@user_decorator.login
def changeInPwd(request):uid = request.session['user_id']user = UserInfo.objects.get(id=uid)cart_num = CartInfo.objects.filter(user_id=user.id).count()context = {'page_name': 1,'title': '用户中心','user': user,'guest_cart': 1,'cart_num': cart_num,}if request.method == "POST":password = request.POST.get('password')password2 = request.POST.get('password2')if password == "" or password2 == "":messages.success(request, "请输入要修改的密码!")elif password == password2:# 密码加密s1 = sha1()s1.update(password.encode('utf8'))encrypted_pwd = s1.hexdigest()user.upwd = encrypted_pwduser.save()messages.success(request, "修改成功!")else:messages.success(request, "两次密码输入不正确!")return render(request, 'df_user/user_changePwd.html', context)
登录验证装饰器实现
def login(func):def login_fun(request, *args, **kwargs):if 'user_id' in request.session:return func(request, *args, **kwargs)else:red = HttpResponseRedirect(reverse("df_user:login"))red.set_cookie('url', request.get_full_path())# 保证用户再登陆验证之后仍点击到希望的页面return redreturn login_fun
用户登录处理
def login_handle(request):# 接受请求信息uname = request.POST.get('username')upwd = request.POST.get('pwd')jizhu = request.POST.get('jizhu', 0)vc = request.POST.get('vc')verifycode = request.session['verifycode']user = UserInfo.objects.filter(uname=uname)if len(user) == 1:  # 判断用户密码并跳转s1 = sha1()s1.update(upwd.encode('utf8'))if s1.hexdigest() == user[0].upwd and vc == verifycode and user[0].uname_passOrfail == True:url = request.COOKIES.get('url', '/')red = HttpResponseRedirect(url)# 是否勾选记住用户名,设置cookieif jizhu != 0:red.set_cookie('uname', uname)else:red.set_cookie('uname', '', max_age=-1)request.session['user_id'] = user[0].idrequest.session['user_name'] = unamereturn redelif user[0].uname_passOrfail == False:messages.success(request, "你的账号存在违规行为,已被封禁。")

📊 数据库设计

核心数据表

用户相关表
  • df_user_userinfo: 用户基本信息
  • df_user_goodsbrowser: 用户浏览记录
  • df_user_information: 用户消息
  • df_user_tuihuoinfo: 退货信息
商品相关表
  • df_goods_goodsinfo: 商品信息
  • df_goods_typeinfo: 商品分类
  • df_goods_goodscontent: 商品评论
  • df_goods_contentchart: 评论回复
交易相关表
  • df_cart_cartinfo: 购物车信息
  • df_order_orderinfo: 订单信息
  • df_order_orderdetailinfo: 订单详情

数据关系

  • 用户与商品:多对多关系(通过购物车、订单、评论)
  • 商品与分类:多对一关系
  • 订单与用户:多对一关系
  • 评论与商品:多对一关系

数据模型设计

用户信息模型 (UserInfo)
class UserInfo(models.Model):uname = models.CharField(max_length=20, verbose_name="用户名", unique=True)usex = models.CharField(max_length=10, verbose_name="性别", default="")uage = models.CharField(max_length=10, verbose_name="年龄", default="")upersonInf = models.CharField(max_length=200, verbose_name="个人简介", default="")ulogo = models.FileField(verbose_name="用户头像", upload_to='images', default='default.jpg')upwd = models.CharField(max_length=40, verbose_name="用户密码", blank=False)uemail = models.EmailField(verbose_name="邮箱", unique=True)urealname = models.CharField(max_length=20, default="", verbose_name="真实姓名")uzhengjian_type = models.CharField(max_length=20, default="", verbose_name="证件类型")uzhengjian_tel = models.CharField(max_length=18, default="", verbose_name="证件号码")uzhengjian_img = models.FileField(upload_to='images/zhengjian_img', default="", verbose_name="证件图片")ucheck_passOrfail = models.BooleanField(verbose_name="认证审批", default=False)ushou = models.CharField(max_length=20, default="", verbose_name="收货名称")uaddress = models.CharField(max_length=100, default="", verbose_name="地址")uyoubian = models.CharField(max_length=6, default="", verbose_name="邮编")uphone = models.CharField(max_length=11, default="", verbose_name="手机号")uname_passOrfail = models.BooleanField(verbose_name="允许登录", default=True)class Meta:verbose_name = "用户信息"verbose_name_plural = verbose_namedef __str__(self):return self.uname
商品信息模型 (GoodsInfo)
class GoodsInfo(models.Model):isDelete = models.BooleanField(default=False)  # 逻辑删除gtitle = models.CharField(max_length=20, verbose_name="商品名称", unique=True)gpic = models.ImageField(verbose_name='商品图片', upload_to='df_goods/image/%Y/%m', null=True, blank=True)gprice = models.DecimalField(max_digits=7, decimal_places=2, verbose_name="商品价格")gunit = models.CharField(max_length=20, verbose_name="卖家昵称")gclick = models.IntegerField(verbose_name="点击量", default=0, null=False)gjianjie = models.CharField(max_length=200, verbose_name="简介")gkucun = models.IntegerField(verbose_name="库存", default=0)gcontent = HTMLField(max_length=200, verbose_name="详情")gtype = models.ForeignKey(TypeInfo, on_delete=models.CASCADE, verbose_name="分类")class Meta:verbose_name = "商品"verbose_name_plural = verbose_namedef __str__(self):return self.gtitle
订单信息模型 (OrderInfo)
class OrderInfo(models.Model):oid = models.CharField(max_length=20, primary_key=True, verbose_name="大订单号")user = models.ForeignKey(UserInfo, on_delete=models.CASCADE, verbose_name="订单用户")odate = models.DateTimeField(auto_now=True, verbose_name="时间")oIsPay = models.BooleanField(default=False, verbose_name="是否支付")ototal = models.DecimalField(max_digits=8, decimal_places=2, verbose_name="总价")oaddress = models.CharField(max_length=150, verbose_name="订单地址")class Meta:verbose_name = "未付款订单"verbose_name_plural = verbose_namedef __str__(self):return "{0}在的订单{1}".format(self.user.uname, self.odate)

💻 项目演示

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

🚀 部署方案

环境要求

  • Python: 3.6+
  • Django: 2.0.7
  • MySQL: 5.7+
  • Pillow: 7.1.1
  • PyMySQL: 数据库连接

部署步骤

  1. 环境准备: 安装Python、MySQL等基础环境
  2. 依赖安装: 安装requirements.txt中的依赖包
  3. 数据库配置: 创建数据库,导入SQL文件
  4. 配置修改: 修改settings.py中的数据库配置
  5. 静态文件: 收集静态文件
  6. 服务启动: 启动Django开发服务器

配置说明

# 数据库配置
DATABASES = {'default': {'ENGINE': 'django.db.backends.mysql','NAME': 'design_169_market','USER': 'root','PASSWORD': '123456','HOST': '127.0.0.1','PORT': '3306'}
}# 邮件配置
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = False
EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 465
EMAIL_HOST_USER = 'woaisilaowu@163.com'
EMAIL_HOST_PASSWORD = 'PZDOHBIYHAJSCVPS'# 静态文件配置
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),
]# 媒体文件配置
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')# 富文本编辑器配置
TINYMCE_DEFAULT_CONFIG = {'theme': 'advanced','width': 600,'height': 400,
}# 时区和语言配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_TZ = False

📈 性能优化

数据库优化

  • 索引优化: 为常用查询字段添加索引
  • 查询优化: 使用select_related减少查询次数
  • 分页处理: 大数据量分页展示
查询优化示例
# 优化前:N+1查询问题
goods_list = GoodsInfo.objects.all()
for goods in goods_list:print(goods.gtype.ttitle)  # 每次都会查询数据库# 优化后:使用select_related预加载关联数据
goods_list = GoodsInfo.objects.select_related('gtype').all()
for goods in goods_list:print(goods.gtype.ttitle)  # 只查询一次数据库
分页处理示例
from django.core.paginator import Paginatordef good_list(request, tid, pindex, sort):# 根据排序方式获取商品列表if sort == '1':  # 默认最新goods_list = GoodsInfo.objects.filter(gtype_id=int(tid)).order_by('-id')elif sort == '2':  # 按照价格goods_list = GoodsInfo.objects.filter(gtype_id=int(tid)).order_by('-gprice')elif sort == '3':  # 按照人气点击量goods_list = GoodsInfo.objects.filter(gtype_id=int(tid)).order_by('-gclick')# 创建Paginator分页对象paginator = Paginator(goods_list, 4)  # 每页4个商品# 返回Page对象,包含商品信息page = paginator.page(int(pindex))context = {'title': '商品列表','page': page,'paginator': paginator,'sort': sort,}return render(request, 'df_goods/list.html', context)

前端优化

  • 静态文件: 静态文件CDN加速
  • 图片优化: 图片压缩和格式优化
  • 缓存策略: 浏览器缓存和服务器缓存
AJAX异步加载示例
// 购物车数量异步更新
$(function () {$('.input_btn').click(function () {q = $('.input_text').val();if(q==""){alert("请输入搜索内容");} else {location.href = '{% url "df_goods:ordinary_search" %}?q='+q+'&page=1'}})
})// 购物车商品数量修改
function edit_cart(cart_id, count) {$.get('/cart/edit' + cart_id + '_' + count + '/', function(data) {if(data.count == 0) {// 更新成功update_cart_display();} else {alert('修改失败');}});
}

代码优化

  • 代码复用: 提取公共组件和函数
  • 异常处理: 完善的异常处理机制
  • 日志记录: 系统运行日志记录
异常处理示例
@user_decorator.login
def edit(request, cart_id, count):data = {}try:cart = CartInfo.objects.get(pk=int(cart_id))cart.count = int(count)cart.save()data['count'] = 0except Exception:data['count'] = countreturn JsonResponse(data)@user_decorator.login
def delete(request, cart_id):data = {}try:cart = CartInfo.objects.get(pk=int(cart_id))cart.delete()data['ok'] = 1except Exception:data['ok'] = 0return JsonResponse(data)

🐛 常见问题与解决方案

1. 数据库连接问题

问题: PyMySQL连接MySQL失败
解决方案:

import pymysql
pymysql.install_as_MySQLdb()

2. 用户注册验证问题

问题: 用户名和邮箱重复验证
解决方案:

def register_exist(request):username = request.GET.get('uname')uemail = request.GET.get('uemail')count = UserInfo.objects.filter(uname=username).count()email_count = UserInfo.objects.filter(uemail=uemail).count()return JsonResponse({'count': count, 'email_count': email_count})

3. 静态文件问题

问题: 静态文件无法加载
解决方案:

STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'),
]

4. 媒体文件上传问题

问题: 上传文件无法访问
解决方案:

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')# urls.py配置
from django.views.static import serve
urlpatterns = [# ... 其他URL配置url(r'^media/(?P<path>.*)$', serve, {"document_root": MEDIA_ROOT})
]

5. Session管理问题

问题: 用户登录状态丢失
解决方案:

# 登录时设置session
request.session['user_id'] = user[0].id
request.session['user_name'] = uname# 退出时清除session
def logout(request):request.session.flush()return redirect(reverse("df_goods:index"))

6. 事务处理问题

问题: 订单创建时数据不一致
解决方案:

@transaction.atomic()
def order_handle(request):tran_id = transaction.savepoint()try:# 订单处理逻辑transaction.savepoint_commit(tran_id)except Exception as e:transaction.savepoint_rollback(tran_id)return HttpResponse('订单创建失败')

7. 验证码问题

问题: 验证码图片无法显示
解决方案: 确保Pillow库正确安装,字体文件存在

🔮 项目扩展建议

功能扩展

  • 支付集成: 集成支付宝、微信支付
  • 物流跟踪: 集成快递查询API
  • 消息推送: 集成推送通知服务
  • 数据分析: 添加数据统计和分析功能

技术升级

  • Django版本: 升级到最新稳定版本
  • 数据库: 考虑使用PostgreSQL
  • 缓存: 集成Redis缓存
  • 异步处理: 使用Celery处理异步任务

安全增强

  • HTTPS: 启用HTTPS协议
  • CSRF防护: 增强CSRF防护
  • XSS防护: 加强XSS攻击防护
  • SQL注入: 进一步防止SQL注入

📚 学习资源

官方文档

  • Django官方文档
  • Django ORM文档
  • Django模板文档

相关技术

  • MySQL官方文档
  • jQuery官方文档
  • Pillow官方文档

最佳实践

  • Django最佳实践
  • Web安全指南
  • Python编码规范

🎉 项目总结

这个基于Django的二手交易校园购物系统成功实现了完整的电商交易功能,具有以下特点:

技术亮点

  • 完整的电商流程: 从用户注册到订单完成的完整流程
  • 模块化设计: 清晰的模块划分和代码组织
  • 安全可靠: 完善的安全机制和权限控制
  • 用户友好: 直观的界面设计和交互体验

功能特色

  • 校园特色: 专为校园环境设计的交易平台
  • 互动功能: 评论、消息、浏览记录等互动功能
  • 管理完善: 完整的后台管理系统
  • 扩展性强: 良好的代码结构便于功能扩展

学习价值

  • Django框架: 深入学习Django框架的使用
  • 数据库设计: 学习关系型数据库设计和优化
  • 前端交互: 学习前后端交互和用户体验设计
  • 项目架构: 学习大型项目的架构设计和模块化开发

这个项目不仅是一个功能完整的电商系统,更是一个很好的学习案例,涵盖了Web开发的各个方面,对于学习Django框架和Web开发具有很高的参考价值。


本文档详细介绍了基于Django的二手交易校园购物系统的开发过程、技术架构、功能特性等内容,希望对您的学习和开发有所帮助。如有任何问题或建议,欢迎交流讨论。

http://www.dtcms.com/a/306206.html

相关文章:

  • django-4事务
  • 游戏盾是如何做到免疫攻击的
  • Android自定义游戏view积累
  • 从混乱走向高效:重塑企业IT服务管理的未来路径
  • 【网络运维】Linux:软件包管理
  • python案例分析:基于抖音评论的文本分析,使用svm算法进行情感分析以及LDA主题分析,准确率接近90%
  • Qt Quick 可视化组件应用
  • 应用药品 GMP 证书识别技术,实现证书信息的自动化、精准化提取与核验
  • OriGene:一种可自进化的虚拟疾病生物学家,实现治疗靶点发现自动化
  • RK3568下的进程间通信:基于UDP的mash网络节点通信
  • Java注解与反射:从自定义注解到框架设计原理
  • 双线串行的 “跨界对话”:I2C 与 MDIO 的异同解析
  • 详细聊下easyexcel导出
  • 实例教学FPN原理与PANet,Pytorch逐行精讲实现
  • 【源力觉醒 创作者计划 】文心大模型4.5系列与DeepSeek、通义千问Qwen 3.0深度对比分析
  • 人工智能与安全:智能安防的创新与伦理边界
  • pycharm中debug的一些小细节
  • 压敏电阻的选型与计算分析
  • YOLO-01目标检测基础
  • 电子对抗技术在特种车辆中的实战应用与发展解析
  • windows环境下MySQL 8.0 修改或重置密码
  • mysql创建一个管理员用户
  • 《校园生活平台从 0 到 1 的搭建》第五篇:商品后端
  • 《零基础入门AI:传统机器学习核心算法解析(KNN、模型调优与朴素贝叶斯)》
  • Java Stream核心:ReferencePipeline解析
  • 如何判断一个数据库是不是出问题了?
  • Python处理JSON和Excel文件的转换
  • 2025年6月电子学会青少年软件编程(C语言)等级考试试卷(一级)
  • Elasticsearch 8.19.0 和 9.1.0 中 LogsDB 和 TSDS 的性能与存储改进
  • 分布式搜索和分析引擎Elasticsearch实战指南