前端:html+css+js+Vue+Element-ui
后端:Django+DRF+celery+haystack+django_crontab
数据库:Mysql+Redis
一些技术和功能:
为session、短信验证码、用户浏览记录、购物车、异步任务队列 创建缓存
whoosh搜索引擎
异步任务队列 用于发送邮件、短信
定时任务 定时更新静态页面、刷新日志等
腾讯云短信服务
chatGPT客服(New)
支付宝沙盒
客服群聊
数据库乐观锁
页面静态化
JWT认证
发货地址、不同的商品的详情、售后服务等都可以通过后台设置
自选CPU、内存、显卡
"点击此处确认验证邮箱"
对于未登录的用户,购物车数据使用浏览器cookie保存 登陆后合并购物车 对于已登录的用户,购物车数据在后端使用Redis保存
效果如下:
代码过多,这里只展示一部分,欢迎感兴趣的小伙伴一起讨论学习:
import os from alipay import AliPay from rest_framework import status from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.views import APIView from MyApps.orders.models import OrderInfo from MyApps.payment.models import Payment from django.conf import settings class PaymentView(APIView): """ 支付 """ permission_classes = (IsAuthenticated,) def get(self, request, order_id): """ 获取支付链接 """ # 判断订单信息是否正确 try: order = OrderInfo.objects.get(order_id=order_id, user=request.user, pay_method=OrderInfo.PAY_METHODS_ENUM["ALIPAY"], status=OrderInfo.ORDER_STATUS_ENUM["UNPAID"]) except OrderInfo.DoesNotExist: return Response({'message': '订单信息有误'}, status=status.HTTP_400_BAD_REQUEST) # 构造支付宝支付链接地址 alipay = AliPay( appid=settings.ALIPAY_APPID, app_notify_url=None, # 默认回调url app_private_key_string=open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys", "app_private_key.pem")).read(), # app_private_key_string=settings.app_private_key_string, alipay_public_key_string=open(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'keys', 'alipay_public_key.pem')).read(), # alipay_public_key_string=settings.alipay_public_key_string, # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, sign_type="RSA2", # RSA 或者 RSA2 debug=settings.ALIPAY_DEBUG # 默认False ) order_string = alipay.api_alipay_trade_page_pay( out_trade_no=order_id, total_amount=str(order.total_amount), subject="联想商城%s" % order_id, return_url="http://localhost:63342/BMyStore/front_end_pc/pay_success.html", ) # 需要跳转到https://openapi.alipay.com/gateway.do? + order_string # 拼接链接返回前端 alipay_url = settings.ALIPAY_URL + "?" + order_string return Response({'alipay_url': alipay_url}) # 支付宝回调函数接口 put /payment/status/?支付宝参数 class PaymentStatusView(APIView): def put(self, request): # 接收参数,效验参数 # 构造支付宝支付链接地址 alipay_req_data = request.query_params if not alipay_req_data: return Response({"message": "缺少参数"}, status=status.HTTP_400_BAD_REQUEST) alipay_req_dict = alipay_req_data.dict() sign = alipay_req_dict.pop("sign") alipay = AliPay( appid=settings.ALIPAY_APPID, app_notify_url=None, # 默认回调url app_private_key_string=open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/app_private_key.pem")).read(), alipay_public_key_string=open(os.path.join(os.path.dirname(os.path.abspath(__file__)), "keys/alipay_public_key.pem")).read(), # 支付宝的公钥,验证支付宝回传消息使用,不是你自己的公钥, sign_type="RSA2", # RSA 或者 RSA2 debug=settings.ALIPAY_DEBUG # 默认False ) result = alipay.verify(alipay_req_dict, sign) # 保存数据,保存支付结果数据 if result: order_id = alipay_req_dict.get("out_trade_no") trade_id = alipay_req_dict.get("trade_no") # 修改订单状态 Payment.objects.create( order_id=order_id, trade_id=trade_id ) OrderInfo.objects.filter(order_id=order_id).update(status=OrderInfo.ORDER_STATUS_ENUM["UNCOMMENT"]) print('支付成功!') return Response({"trade_id": trade_id}) return Response({"message": "参数有误"}, status=status.HTTP_400_BAD_REQUEST)
from django_filters.rest_framework import DjangoFilterBackend from drf_haystack.viewsets import HaystackViewSet from rest_framework.filters import OrderingFilter from rest_framework.generics import ListAPIView, CreateAPIView, DestroyAPIView, RetrieveAPIView from rest_framework.pagination import PageNumberPagination from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.viewsets import GenericViewSet from MyApps.goods import models from MyApps.goods.models import SKU, GoodsCategory, Collect, Comment1, SKUImage from MyApps.goods.serializers import SKUSerializer, SKUIndexSerializer, CollectSerializer, Comment1Serializer from rest_framework.permissions import IsAuthenticated from django_redis import get_redis_connection from rest_framework.filters import BaseFilterBackend from django_filters import FilterSet, filters class SKUListView(ListAPIView): """ sku列表数据 """ serializer_class = SKUSerializer # 分页与排序 filter_backends = (OrderingFilter,) ordering_fields = ("create_time", "price", "sales") def get_queryset(self): category_id = self.kwargs["category_id"] return SKU.objects.filter(category_id=category_id, is_launched=True) class SKUSearchViewSet(HaystackViewSet): """ SKU搜索 """ index_models = [SKU] serializer_class = SKUIndexSerializer # 分页与排序 # filter_backends = (OrderingFilter,) def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) ordering_fields = ("create_time", "price", "sales") od = request.query_params.get("ordering", None) if od in ordering_fields: queryset = queryset.order_by(od) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response(serializer.data) class CategoriesView(APIView): """获取当前分类信息""" def get(self, request, pk): """ 1.获取前端数据 2. 查询当前三级分类信息 3.通过三级分类信息获取一二集分类 4. 返回 :param request: :return: """ cat3 = GoodsCategory.objects.get(id=pk) # 获取三级 cat2 = cat3.parent # 自关联获取二级, cat1 = cat2.parent # 自关联获取一级 # 返回数据 return Response({ "cat1": cat1.name, "cat2": cat2.name, "cat3": cat3.name }) class GetGoodsView(APIView): """获取当前分类信息""" def get(self, request, pk): SKU1 = models.SKU.objects.filter(pk=pk).first() comment_count = SKU1.goods.comment_count collect_count = SKU1.goods.collect_count goods_id = SKU1.goods_id # 返回数据 return Response({"goods_id": goods_id, 'comment_count': comment_count, 'collect_count': collect_count}) class IsCollectedView(APIView): def post(self, request): print(request.data) sku_id = int(request.data.get("sku_id", -5)) user_id = request.data.get("user_id", 1) if sku_id == -5: return Response({"res_data": 0}) collecs = models.Collect.objects.filter(user_id=user_id) sku_id_list = [i.sku_id for i in collecs] print(sku_id in sku_id_list) res = 0 if sku_id in sku_id_list: res = 1 return Response({"res_data": res}) ################################## class MyPageNumberPagination(PageNumberPagination): page_size_query_param = 'size' page_size = 10 max_page_size = 100 class CommentFilterSet(FilterSet): goods = filters.NumberFilter(field_name='goods', required=True) class Meta: model = models.Comment1 fields = ['goods'] class Comment1View(ListAPIView, GenericViewSet): filter_backends = [DjangoFilterBackend] filterset_class = CommentFilterSet queryset = models.Comment1.objects serializer_class = Comment1Serializer ################################################ class SelfFilterBackend(BaseFilterBackend): def filter_queryset(self, request, queryset, view): return queryset.filter(user=request.user) class CollectViewSet(ListAPIView, CreateAPIView, GenericViewSet): permission_classes = [IsAuthenticated] filter_backends = [SelfFilterBackend, DjangoFilterBackend] pagination_class = MyPageNumberPagination # 当前登录用户的所有收藏记录 queryset = models.Collect.objects serializer_class = CollectSerializer def perform_create(self, serializer): user = self.request.user instance = Collect.objects.filter(user=user, **serializer.validated_data).first() if not instance: instance = serializer.save(user=user) instance.sku.goods.collect_count += 1 instance.sku.goods.save() return Response({"message": 'ok', 'data': {'active': True}}) else: instance.delete() instance.sku.goods.collect_count -= 1 instance.sku.goods.save() return Response({"message": 'ok', 'data': {'active': False}}) class HotSkus(ListAPIView): serializer_class = SKUSerializer # 分页与排序 filter_backends = (OrderingFilter,) ordering_fields = ("sales", "create_time", "price") def get_queryset(self): category_id = self.kwargs["category_id"] return SKU.objects.filter(category_id=category_id, is_launched=True).order_by('-sales')[:2] class ImgListView(APIView): def get(self, request): s_id = request.query_params.get("sku_id") img_list = SKUImage.objects.filter(sku_id=s_id) img_list = [i.image.path.split("BMyStore\\")[1] for i in img_list] return Response({"img_list": img_list})
有些代码写的略显丑陋 不过能跑就不改了 哈哈