【目录结构】

 

 APPS中的表数据

feeder表(model没有数据)

  1 url.py
  2 
  3 
  4 from django.contrib import admin
  5 from django.urls import path, include
  6 from rest_framework.routers import SimpleRouter
  7 from .views import (
  8     FeederLoginView,
  9     FeederInfoView,
 10     FeederOrdersView,
 11     FeederRemunerationView,
 12 )
 13 
 14 
 15 router = SimpleRouter()
 16 router.register("login", FeederLoginView, "login")
 17 router.register("feederinfo", FeederInfoView, "feederinfo")
 18 router.register("orders", FeederOrdersView, "orders")
 19 router.register("remuneration", FeederRemunerationView, "remuneration")
 20 
 21 
 22 urlpatterns = [path("", include(router.urls))]
 23 
 24 
 25 ----------------------------------------------------------------------------
 26 
 27 view.py
 28 
 29 from utils.common_response import APIResponse
 30 from rest_framework.viewsets import GenericViewSet
 31 from user.serializer import LoginSerializer
 32 from django.contrib import auth
 33 from rest_framework.decorators import action
 34 from rest_framework_simplejwt.authentication import JWTAuthentication
 35 from rest_framework.permissions import IsAuthenticated
 36 from user.models import User, FeederRemuneration
 37 import json
 38 from rest_framework.response import Response
 39 from order.models import Order
 40 from datetime import datetime
 41 from decimal import Decimal
 42 
 43 
 44 # 多方式登录接口
 45 class FeederLoginView(GenericViewSet):
 46     serializer_class = LoginSerializer
 47 
 48     def _login(self, request, *args, **kwargs):
 49         serializer = self.get_serializer(data=request.data)
 50         serializer.is_valid(raise_exception=True)
 51         token = serializer.context.get("token")
 52         user = serializer.context.get("username")
 53         icon = serializer.context.get("icon")
 54         if user.is_pet_feeder == 1:
 55             auth.login(request, user)
 56             return APIResponse(
 57                 token=token,
 58                 username=user.username,
 59                 icon=icon,
 60                 msg="登录成功!",
 61                 data=serializer.data,
 62             )
 63         else:
 64             return APIResponse(code=400, msg="用户不是喂养员,无法登录!")
 65 
 66     @action(methods=["POST"], detail=False)
 67     def multiple_login(self, request, *args, **kwargs):
 68         return self._login(request, *args, **kwargs)
 69 
 70 
 71 class FeederInfoView(GenericViewSet):
 72     authentication_classes = [JWTAuthentication]
 73     permission_classes = [IsAuthenticated]
 74 
 75     def list(self, request, *args, **kwargs):
 76         user = request.user
 77         feeder = user.feeder
 78         if feeder:
 79             data = {
 80                 "id": feeder.id,
 81                 "name": feeder.name,
 82                 "icon": "http://192.168.1.38:8000/media/" + str(feeder.icon),
 83                 "gender": feeder.gender,
 84                 "desc": feeder.desc,
 85                 "service_duration": feeder.service_duration,
 86                 "price": feeder.price,
 87                 "feed_type": feeder.feed_type,
 88             }
 89             return Response({"code": 100, "msg": "查询成功!", "result": data})
 90         else:
 91             return Response({"code": 400, "msg": "用户不是喂养员"})
 92 
 93 
 94 class FeederOrdersView(GenericViewSet):
 95     authentication_classes = [JWTAuthentication]
 96     permission_classes = [IsAuthenticated]
 97 
 98     # 待接单点击变成待上门
 99     @action(methods=["PUT"], detail=False)
100     def jiedan(self, request, *args, **kwargs):
101         feeder_id = request.user.feeder_id
102         order_id = request.data.get("order_id")  # 0512046476199352916
103         qs = Order.objects.filter(order_id=order_id).first()
104         qs.feeder_id = feeder_id
105         qs.order_status = 2
106         qs.save()
107         return APIResponse(msg="接单成功!")
108 
109     # 待上门点击变成进行中
110     @action(methods=["PUT"], detail=False)
111     def daishangmen(self, request, *args, **kwargs):
112         order_id = request.data.get("order_id")
113         qs = Order.objects.filter(order_id=order_id).first()
114         qs.order_status = 3
115         qs.save()
116         return APIResponse(msg="确认成功!")
117 
118     # 进行中点击变成已完成
119     @action(methods=["PUT"], detail=False)
120     def jinxingzhong(self, request, *args, **kwargs):
121         order_id = request.data.get("order_id")
122         qs = Order.objects.filter(order_id=order_id).first()
123         qs.order_status = 4
124         qs.complete_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
125         qs.save()
126 
127         remuneration = qs.actual_payment - qs.actual_payment * Decimal("0.2")
128 
129         feeder_obj = FeederRemuneration.objects.filter(feeder=qs.feeder).first()
130         feeder_obj.remuneration += remuneration
131         feeder_obj.save()
132 
133         return APIResponse(msg="订单完成!")
134 
135 
136 class FeederRemunerationView(GenericViewSet):
137     authentication_classes = [JWTAuthentication]
138     permission_classes = [IsAuthenticated]
139 
140     def list(self, request, *args, **kwargs):
141         user = request.user.feeder_id
142         qs = FeederRemuneration.objects.filter(feeder=user).first()
143         remuneration = qs.remuneration
144         return APIResponse(msg="查询成功!", remuneration=remuneration)

 

home表数据

 1 admin.py
 2 
 3 from django.contrib import admin
 4 
 5 # Register your models here.
 6 from .models import Banner
 7 
 8 
 9 @admin.register(Banner)
10 class BannerAdmin(admin.ModelAdmin):
11     list_display = ("title", "image", "link", "info", "description")
12 
13 ---------------------------------------------------------------------------
14 apps.py
15 
16 from django.apps import AppConfig
17 
18 
19 class HomeConfig(AppConfig):
20     default_auto_field = "django.db.models.BigAutoField"
21     name = "home"
22     verbose_name = "首页"
23 
24 
25 -----------------------------------------------------------------------------
26 models.py
27 
28 from django.db import models
29 
30 from utils.common_models import BaseModel
31 
32 
33 class Banner(BaseModel):
34     title = models.CharField(max_length=64, unique=True, verbose_name="名称")
35     image = models.ImageField(upload_to="banner", verbose_name="图片")
36     link = models.CharField(max_length=64, verbose_name="跳转链接")
37     info = models.TextField(verbose_name="详情")
38     description = models.TextField(null=True, blank=True, verbose_name="介绍")
39 
40     class Meta:
41         db_table = "puddingpet_banner"
42         verbose_name = "轮播图"
43         verbose_name_plural = verbose_name
44 
45 ----------------------------------------------------------------------------------
46 serializers.py
47 
48 from rest_framework import serializers
49 from .models import Banner
50 
51 
52 class BannerSerializer(serializers.ModelSerializer):
53     class Meta:
54         model = Banner
55         fields = "__all__"
56 
57 
58 -------------------------------------------------------------------------------------
59 url.py
60 
61 from django.contrib import admin
62 from django.urls import path, include
63 from rest_framework.routers import SimpleRouter
64 from .views import BannerView
65 
66 router = SimpleRouter()
67 router.register("banner", BannerView, "banner")
68 
69 
70 urlpatterns = [path("", include(router.urls))]
71 
72 ------------------------------------------------------------------------------------
73 viwe.py
74 
75 from django.shortcuts import render
76 from rest_framework.viewsets import GenericViewSet
77 from utils.common_mixin import CacheListModelMixin
78 from .models import Banner
79 from django.conf import settings
80 from .serializer import BannerSerializer
81 
82 
83 class BannerView(GenericViewSet, CacheListModelMixin):
84     cache_key = "banner_list"
85 
86 
87     queryset = (
88         Banner.objects.all().filter(is_delete=False, is_show=True).order_by("orders")
89     )
90 
91     serializer_class = BannerSerializer

 

order表数据

  1 admin.py
  2 
  3 from django.contrib import admin
  4 from .models import Order
  5 
  6 
  7 @admin.register(Order)
  8 class OrderAdmin(admin.ModelAdmin):
  9     list_display = (
 10         "order_id",
 11         "order_time",
 12         "complete_time",
 13         "customer",
 14         "feeder",
 15         "appointment_time",
 16         "address",
 17         "pet",
 18         "remarks",
 19         "actual_payment",
 20         "payment_method",
 21         "review",
 22         "order_status",
 23     )
 24 
 25 ------------------------------------------------------------------------------------
 26 apps.py
 27 
 28 from django.apps import AppConfig
 29 
 30 
 31 class OrderConfig(AppConfig):
 32     default_auto_field = "django.db.models.BigAutoField"
 33     name = "order"
 34     verbose_name = "订单表"
 35 
 36 --------------------------------------------------------------------------------------
 37 models.py
 38 
 39 from django.db import models
 40 from user.models import User, PetFeeder, UserAddress
 41 import random
 42 from pet.models import Pet
 43 
 44 
 45 def generate_order_id():
 46     """生成19位纯数字的订单ID"""
 47     return "".join(random.choices("0123456789", k=19))
 48 
 49 
 50 class Order(models.Model):
 51     order_id = models.CharField(
 52         max_length=19,
 53         default=generate_order_id,
 54         unique=True,
 55         editable=False,
 56         verbose_name="订单号码",
 57     )  # 订单号码 随机生成
 58     order_time = models.DateTimeField(
 59         auto_now_add=True, verbose_name="下单时间"
 60     )  # 下单时间
 61     complete_time = models.DateTimeField(
 62         null=True, blank=True, verbose_name="完成时间"
 63     )  # 完成时间
 64     customer = models.ForeignKey(
 65         User, on_delete=models.CASCADE, verbose_name="下单人"
 66     )  # 下单人(外键)
 67     feeder = models.ForeignKey(
 68         PetFeeder,
 69         on_delete=models.CASCADE,
 70         verbose_name="预约对象",
 71         blank=True,
 72         null=True,
 73     )  # 预约对象(外键)
 74     appointment_time = models.CharField(
 75         max_length=128, verbose_name="预约上门时间"
 76     )  # 预约上门时间
 77     address = models.ForeignKey(
 78         UserAddress, on_delete=models.CASCADE, verbose_name="预约上门地址"
 79     )  # 预约上门地址(外键)
 80     pet = models.ForeignKey(
 81         Pet, on_delete=models.CASCADE, verbose_name="预约宠物"
 82     )  # 预约宠物(外键)
 83     remarks = models.TextField(blank=True, null=True, verbose_name="备注")  # 备注
 84     actual_payment = models.IntegerField(
 85         verbose_name="实付款", blank=True, null=True
 86     )  # 实付款
 87 
 88     PAYMENT_METHOD_CHOICES = (
 89         (0, "微信支付"),
 90         (1, "支付宝"),
 91         (2, "当面支付"),
 92     )
 93     payment_method = models.IntegerField(
 94         choices=PAYMENT_METHOD_CHOICES,
 95         verbose_name="支付方式",
 96         blank=True,
 97         null=True,
 98     )  # 支付方式
 99 
100     review = models.CharField(
101         max_length=128, blank=True, null=True, verbose_name="订单评价"
102     )  # 订单评价
103 
104     ORDER_STATUS_CHOICES = (
105         (0, "待付款"),
106         (1, "待接单"),
107         (2, "待上门"),
108         (3, "进行中"),
109         (4, "已完成"),
110     )
111     order_status = models.IntegerField(
112         choices=ORDER_STATUS_CHOICES, default=0, verbose_name="订单状态"
113     )  # 订单状态
114 
115     class Meta:
116         db_table = "puddingpet_order"
117         verbose_name = "订单表"
118         verbose_name_plural = verbose_name
119 
120     def __str__(self):
121         return f"订单{self.order_id} by {self.customer.username}"
122 
123 ------------------------------------------------------------------------------
124 pagination .py
125 
126 from rest_framework.pagination import PageNumberPagination
127 
128 
129 class CommonPagination(PageNumberPagination):
130     page_size = 3  # 每页显示多少条
131     page_query_param = "page"  # http://127.0.0.1:8000/book/bookview/?page=2 分页
132     page_size_query_param = (
133         "size"  # http://127.0.0.1:8000/book/bookview/?page=1&size=3 每页显示条数
134     )
135     max_page_size = 10  # 不管size输入多少,最多显示10条
136 
137 --------------------------------------------------------------------------------
138 serializers.py
139 
140 
141 from rest_framework import serializers
142 
143 from .models import Order
144 
145 
146 class OrderSerializer(serializers.ModelSerializer):
147     order_id = serializers.CharField(read_only=True)
148     order_time = serializers.CharField(read_only=True)  # 2024-06-03 10:12:42
149 
150     class Meta:
151         model = Order
152         fields = [
153             "order_id",  # 订单号码 随机生成
154             "order_time",  # 下单时间
155             "complete_time",  # 完成时间
156             "customer",  # 下单人(外键)
157             "feeder",  # 预约对象(外键)
158             "appointment_time",  # 预约上门时间
159             "address",  # 预约上门地址(外键)
160             "pet",  # 预约宠物(外键)
161             "remarks",  # 备注
162             "actual_payment",  # 实付款
163             "payment_method",  # 支付方式
164             "review",  # 订单评价
165             "order_status",  # 订单状态
166         ]
167 
168     # 如果有饲养员id,就是选择下单,有price,待付款
169     # 如果没有饲养员id,就是直接下单,price=0,待接单
170     # 等有饲养员接单了,把价格设置进去,让他付款
171     def create(self, validated_data):
172         print(validated_data)
173         # {'customer': <User: heart>, 'feeder': <PetFeeder: 超级喂养员>, 'appointment_time': '2024-06-09 18:41',
174         # 'address': <UserAddress: hearttest>, 'pet': <Pet: 哈基米>, 'remarks': '321', 'actual_payment': 0}
175         feeder_obj = validated_data.get("feeder")
176         if feeder_obj:
177             order = Order.objects.create(**validated_data)
178             return order
179         else:
180             order = Order.objects.create(**validated_data)
181             order.order_status = 1
182             order.save()
183             return order
184 
185 
186 class OrderReviewSerializer(serializers.Serializer):
187     review = serializers.CharField()
188 
189 
190 class UserOrderSerializer(serializers.ModelSerializer):
191     order_id = serializers.CharField(read_only=True)
192     order_time = serializers.CharField(read_only=True)  # 2024-06-03 10:12:42
193     payment_method = serializers.CharField(source="get_payment_method_display")
194     order_status = serializers.CharField(source="get_order_status_display")
195 
196     class Meta:
197         model = Order
198         fields = [
199             "order_id",  # 订单号码 随机生成
200             "order_time",  # 下单时间
201             "complete_time",  # 完成时间
202             "customer",  # 下单人(外键)
203             "feeder",  # 预约对象(外键)
204             "appointment_time",  # 预约上门时间
205             "address",  # 预约上门地址(外键)
206             "pet",  # 预约宠物(外键)
207             "remarks",  # 备注
208             "actual_payment",  # 实付款
209             "payment_method",  # 支付方式
210             "review",  # 订单评价
211             "order_status",  # 订单状态
212         ]
213         depth = 1
214 
215 ------------------------------------------------------------------------------
216 tasks.py
217 
218 from celery import shared_task
219 import time
220 from .models import Order, PetFeeder
221 import redis
222 
223 redis_client = redis.StrictRedis(host="127.0.0.1", port=6379, db=0)
224 
225 
226 @shared_task
227 def qiangdan(order_id, feeder_id, feeder_price):
228     # Redis 分布式锁
229     lock_key = f"lock:order:{order_id}"  # 生成一个唯一的锁键(key)。 使用订单 ID 作为锁的标识符,这样每个订单都有一个唯一的锁,可以防止同一个订单被多次处理。
230     lock_timeout = 5  # 锁的超时时间,单位是秒
231     lock = redis_client.lock(
232         lock_key, timeout=lock_timeout
233     )  # 创建一个 Redis 锁对象。 初始化锁对象,以便后续操作(获取和释放锁)。
234 
235     if lock.acquire(
236         blocking=False
237     ):  # 尝试获取锁  blocking=False 表示非阻塞方式获取锁。如果锁当前被其他任务持有,立即返回 False,否则返回 True 并成功获取锁。
238         # 确保任务能在锁可用时立即开始处理订单。如果锁不可用,则不会等待,而是立即返回 False,表示获取锁失败。
239         try:
240             print(f"获取锁成功,开始处理订单")
241             print(f"查询订单是否还存在,耗时2s")
242             time.sleep(2)
243 
244             try:
245                 order_obj = Order.objects.get(
246                     order_id=order_id, order_status=1, feeder__isnull=True
247                 )
248                 # 如果订单存在,直接进行处理
249                 print("订单存在,开始处理")
250                 time.sleep(1)  # 模拟处理时间
251                 print("下单,耗时2s")
252                 feeder_obj = PetFeeder.objects.filter(id=feeder_id).first()
253                 order_obj.feeder = feeder_obj
254                 order_obj.order_status = 0
255                 order_obj.actual_payment = feeder_price
256                 order_obj.save()
257                 time.sleep(2)
258                 return True
259             except (
260                 Order.DoesNotExist
261             ):  # 如果数据库中没有满足这些条件的订单对象,就会抛出 Order.DoesNotExist 异常。
262                 print("订单不存在或已被抢")
263                 return False
264         finally:
265             if lock.locked():
266                 try:
267                     lock.release()
268                     print("释放锁")
269                 except (
270                     redis.exceptions.LockNotOwnedError  # type: ignore
271                 ):  # Redis-Py 库中的一个异常类。当尝试释放一个不再由你持有的锁时,会抛出这个异常。
272                     print("锁已经被自动释放或不再拥有,无法释放")
273     else:
274         print("抢单失败")
275         return False
276 
277 ------------------------------------------------------------------------------------
278 urls.py
279 
280 from django.contrib import admin
281 from django.urls import path, include
282 from rest_framework.routers import SimpleRouter
283 from .views import OrderView, OrderReviewView, UserOrderView, QiangdanView
284 
285 
286 router = SimpleRouter()
287 router.register("order", OrderView, "order")
288 router.register("review", OrderReviewView, "review")
289 router.register("userorder", UserOrderView, "userorder")
290 router.register("qiangdan", QiangdanView, "qiangdan")
291 
292 
293 urlpatterns = [path("", include(router.urls))]
294 
295 ----------------------------------------------------------------------------------
296 views.py
297 
298 from django.db.models import Q
299 from django.shortcuts import render
300 from rest_framework.generics import CreateAPIView
301 from .models import Order
302 from utils.common_logger import logger
303 from utils.common_response import APIResponse
304 from rest_framework.viewsets import GenericViewSet, ViewSet
305 from .serializer import OrderSerializer, OrderReviewSerializer, UserOrderSerializer
306 from rest_framework_simplejwt.authentication import JWTAuthentication
307 from rest_framework.permissions import IsAuthenticated
308 from user.models import User
309 from utils.common_mixin import APIListModelMixin
310 from .pagination import CommonPagination
311 from rest_framework.decorators import action
312 from .tasks import qiangdan
313 from celery.result import AsyncResult
314 from user.models import PetFeeder, UserBalance
315 
316 
317 class OrderView(GenericViewSet):
318     queryset = Order.objects.all()
319     serializer_class = OrderSerializer
320     authentication_classes = [JWTAuthentication]
321     permission_classes = [IsAuthenticated]
322 
323     def create(self, request, *args, **kwargs):
324         print(
325             request.data
326         )  # {'customer': 'heart', 'appointment_time': '2024-06-09 18:41',
327         # 'address': 2, 'pet': '2', 'remarks': '123', 'actual_payment': 0}
328         user = User.objects.filter(pk=request.user.id).first()
329         request.data["customer"] = user.id
330         serializer = self.get_serializer(data=request.data)
331         serializer.is_valid(raise_exception=True)
332         serializer.save()
333         return APIResponse(msg="下单成功!")
334 
335     # 付款
336     @action(methods=["POST"], detail=False)
337     def pay(self, request, *args, **kwargs):
338         order_id = request.data.get("order_id")
339         actual_payment = int(request.data.get("actual_payment"))
340         user_balance_obj = UserBalance.objects.filter(user=request.user).first()
341         order_obj = Order.objects.filter(order_id=order_id).first()
342         if int(user_balance_obj.balance) < actual_payment:
343             return APIResponse(code=401, msg="余额不足!请先充值!")
344         else:
345             shifukuan = int(user_balance_obj.balance) - int(actual_payment)
346             user_balance_obj.balance = shifukuan
347             user_balance_obj.save()
348             order_obj.order_status = 1
349             order_obj.payment_method = 0
350             order_obj.save()
351             return APIResponse(msg=f"支付成功!剩余金额{shifukuan}元!")
352 
353 
354 class OrderReviewView(GenericViewSet, APIListModelMixin):
355     queryset = Order.objects.exclude(review__isnull=True)
356     serializer_class = OrderReviewSerializer
357 
358 
359 class UserOrderView(GenericViewSet):
360     queryset = Order.objects.all()
361     serializer_class = UserOrderSerializer
362     pagination_class = CommonPagination
363     authentication_classes = [JWTAuthentication]
364     permission_classes = [IsAuthenticated]
365 
366     def _get_user(self, request):
367         return request.user.id
368 
369     def _check_data(self, qs):
370         if qs:
371             serializer = self.get_serializer(instance=qs, many=True)
372             return APIResponse(msg="查询成功!", results=serializer.data)
373         else:
374             return APIResponse(code=400, msg="没有订单哦!")
375 
376     def list(self, request, *args, **kwargs):
377         user = self._get_user(request)  # type: ignore
378         qs = self.paginate_queryset(
379             Order.objects.filter(customer=user).order_by("-order_time").all()
380         )
381         return self._check_data(qs)  # type: ignore
382 
383     @action(methods=["GET"], detail=False)
384     def daifukuanall(self, request, *args, **kwargs):
385         qs = self.paginate_queryset(
386             Order.objects.filter(order_status=0).order_by("-order_time").all()
387         )
388         if qs:
389             serializer = self.get_serializer(instance=qs, many=True)
390             return APIResponse(msg="查询成功!", results=serializer.data)
391         else:
392             return APIResponse(code=400, msg="没有订单哦!")
393 
394     @action(methods=["GET"], detail=False)
395     def daijiedanall(self, request, *args, **kwargs):
396         qs = self.paginate_queryset(
397             Order.objects.filter(
398                 Q(order_status=0) | Q(order_status=1), feeder=request.user.feeder
399             )
400             .order_by("-order_time")
401             .all()
402         )
403         if qs:
404             serializer = self.get_serializer(instance=qs, many=True)
405             return APIResponse(msg="查询成功!", results=serializer.data)
406         else:
407             return APIResponse(code=400, msg="没有订单哦!")
408 
409     @action(methods=["GET"], detail=False)
410     def daishangmenall(self, request, *args, **kwargs):
411         qs = self.paginate_queryset(
412             Order.objects.filter(order_status=2, feeder=request.user.feeder)
413             .order_by("-order_time")
414             .all()
415         )
416         if qs:
417             serializer = self.get_serializer(instance=qs, many=True)
418             return APIResponse(msg="查询成功!", results=serializer.data)
419         else:
420             return APIResponse(code=400, msg="没有订单哦!")
421 
422     @action(methods=["GET"], detail=False)
423     def jinxingzhongall(self, request, *args, **kwargs):
424         qs = self.paginate_queryset(
425             Order.objects.filter(order_status=3, feeder=request.user.feeder)
426             .order_by("-order_time")
427             .all()
428         )
429         if qs:
430             serializer = self.get_serializer(instance=qs, many=True)
431             return APIResponse(msg="查询成功!", results=serializer.data)
432         else:
433             return APIResponse(code=400, msg="没有订单哦!")
434 
435     @action(methods=["GET"], detail=False)
436     def yiwanchengall(self, request, *args, **kwargs):
437         qs = self.paginate_queryset(
438             Order.objects.filter(order_status=4, feeder=request.user.feeder)
439             .order_by("-order_time")
440             .all()
441         )
442         if qs:
443             serializer = self.get_serializer(instance=qs, many=True)
444             return APIResponse(msg="查询成功!", results=serializer.data)
445         else:
446             return APIResponse(code=400, msg="没有订单哦!")
447 
448     # feeder__isnull=True
449     @action(methods=["GET"], detail=False)
450     def daiqiangdanall(self, request, *args, **kwargs):
451         qs = self.paginate_queryset(
452             Order.objects.filter(order_status=1, feeder__isnull=True)
453             .order_by("-order_time")
454             .all()
455         )
456         if qs:
457             serializer = self.get_serializer(instance=qs, many=True)
458             return APIResponse(msg="查询成功!", results=serializer.data)
459         else:
460             return APIResponse(code=400, msg="没有订单哦!")
461 
462     @action(methods=["GET"], detail=False)
463     def daifukuan(self, request, *args, **kwargs):
464         user = self._get_user(request)  # type: ignore
465         qs = self.paginate_queryset(
466             Order.objects.filter(customer=user, order_status=0)
467             .order_by("-order_time")
468             .all()
469         )
470         return self._check_data(qs)  # type: ignore
471 
472     @action(methods=["GET"], detail=False)
473     def daijiedan(self, request, *args, **kwargs):
474         user = self._get_user(request)  # type: ignore
475         qs = self.paginate_queryset(
476             Order.objects.filter(customer=user, order_status=1)
477             .order_by("-order_time")
478             .all()
479         )
480 
481         return self._check_data(qs)  # type: ignore
482 
483     @action(methods=["GET"], detail=False)
484     def daishangmen(self, request, *args, **kwargs):
485         user = self._get_user(request)  # type: ignore
486         qs = self.paginate_queryset(
487             Order.objects.filter(customer=user, order_status=2)
488             .order_by("-order_time")
489             .all()
490         )
491         return self._check_data(qs)  # type: ignore
492 
493     @action(methods=["GET"], detail=False)
494     def jinxingzhong(self, request, *args, **kwargs):
495         user = self._get_user(request)  # type: ignore
496         qs = self.paginate_queryset(
497             Order.objects.filter(customer=user, order_status=3)
498             .order_by("-order_time")
499             .all()
500         )
501         return self._check_data(qs)  # type: ignore
502 
503     @action(methods=["GET"], detail=False)
504     def yiwancheng(self, request, *args, **kwargs):
505         user = self._get_user(request)  # type: ignore
506         qs = self.paginate_queryset(
507             Order.objects.filter(customer=user, order_status=4)
508             .order_by("-order_time")
509             .all()
510         )
511         return self._check_data(qs)  # type: ignore
512 
513 
514 class QiangdanView(ViewSet):
515     authentication_classes = [JWTAuthentication]
516     permission_classes = [IsAuthenticated]
517 
518     @action(methods=["POST"], detail=False)
519     def paidui(self, request, *args, **kwargs):
520         order_id = request.data.get("order_id")
521         feeder_price = request.data.get("feeder_price")
522         feeder_id = request.user.feeder.id
523         task_id = qiangdan.delay(str(order_id), feeder_id, feeder_price)
524         return APIResponse(msg="您正在排队", task_id=str(task_id))
525 
526     @action(methods=["GET"], detail=False)
527     def get_result(self, request, *args, **kwargs):
528         task_id = request.GET.get("task_id")
529         a = AsyncResult(
530             id=task_id
531         )  # 使用 Celery 的 AsyncResult 类,根据任务 ID 获取任务结果对象 a。
532         if a.successful():  # 检查任务是否成功完成。
533             result = a.get()  # 获取任务的返回结果(True 或 False)。
534             if result:  # 如果任务成功(返回 True),返回抢单成功的响应。
535                 return APIResponse(success="1", msg="抢单成功!")
536             else:  # 如果任务失败(返回 False),返回抢单失败的响应,并告知订单已被抢。
537                 return APIResponse(success="0", msg="抢单失败!")
538         elif (
539             a.status == "PENDING"
540         ):  # 如果任务状态为 PENDING,表示任务在等待执行,返回相应的响应。
541             return APIResponse(success="2", msg="任务等待中被执行!")
542         else:
543             return APIResponse(success="3", msg="抢单任务正在执行!")

 

pet表

  1 admin.py
  2 
  3 from django.contrib import admin
  4 from .models import *
  5 
  6 
  7 # Register your models here.
  8 @admin.register(Pet)
  9 class PetAdmin(admin.ModelAdmin):
 10     list_display = (
 11         "name",
 12         "icon",
 13         "pet_type",
 14         "variety",
 15         "gender",
 16         "birthday",
 17         "weight",
 18         "character",
 19     )
 20 
 21 ---------------------------------------------------------------------------------------
 22 models.py
 23 
 24 from django.db import models
 25 from user.models import User
 26 
 27 
 28 # Create your models here.
 29 # 宠物表,一个用户可以有多只宠物,一只宠物只能属于一个用户
 30 class Pet(models.Model):
 31     GENDER_CHOICES = [
 32         (0, "妹妹"),
 33         (1, "弟弟"),
 34     ]
 35     PETFEEDER_CHOICES = [(0, "猫猫"), (1, "狗狗")]
 36     name = models.CharField(max_length=32, verbose_name="名字")  # 名字
 37     icon = models.ImageField(
 38         upload_to="pet_icon", default="pet_icon/default.png", verbose_name="头像"
 39     )  # 头像
 40     pet_type = models.IntegerField(
 41         choices=PETFEEDER_CHOICES, verbose_name="宠物类别"
 42     )  # 宠物类别
 43     variety = models.CharField(max_length=32, verbose_name="宠物品种")  # 宠物品种
 44     gender = models.IntegerField(choices=GENDER_CHOICES, verbose_name="性别")  # 性别
 45     birthday = models.CharField(max_length=32, verbose_name="出生日期")  # 出生日期
 46     weight = models.IntegerField(verbose_name="体重")  # 体重
 47     character = models.CharField(max_length=255, verbose_name="性格")  # 性格描述
 48     user = models.ForeignKey(
 49         User, on_delete=models.CASCADE, verbose_name="用户"
 50     )  # 对应用户
 51 
 52     class Meta:
 53         db_table = "puddingpet_pet"
 54         verbose_name = "宠物表"
 55         verbose_name_plural = verbose_name
 56 
 57     def __str__(self):
 58         return self.name
 59 
 60 
 61 -----------------------------------------------------------------------------------
 62 serializers
 63 
 64 from rest_framework import serializers
 65 from .models import Pet
 66 from user.models import User
 67 
 68 
 69 class PetSerializer(serializers.ModelSerializer):
 70     pet_type = serializers.CharField(source="get_pet_type_display", read_only=True)
 71     gender = serializers.CharField(source="get_gender_display", read_only=True)
 72     user = serializers.CharField(source="user.username", read_only=True)
 73     id = serializers.CharField(read_only=True)
 74 
 75     class Meta:
 76         model = Pet
 77         fields = [
 78             "id",
 79             "name",
 80             "icon",
 81             "pet_type",
 82             "variety",
 83             "gender",
 84             "birthday",
 85             "weight",
 86             "character",
 87             "user",
 88         ]
 89 
 90 
 91 class BindPetSerializer(serializers.ModelSerializer):
 92     user = serializers.CharField()
 93 
 94     class Meta:
 95         model = Pet
 96         fields = [
 97             "name",
 98             "icon",
 99             "pet_type",
100             "variety",
101             "gender",
102             "birthday",
103             "weight",
104             "character",
105             "user",
106         ]
107 
108     def create(self, validated_data):
109         user = validated_data.pop("user")
110         user_obj = User.objects.filter(pk=int(user)).first()
111         pet_obj = Pet.objects.create(**validated_data, user=user_obj)
112         return pet_obj
113 
114 ------------------------------------------------------------------------------------
115 url.py
116 
117 from django.contrib import admin
118 from django.urls import path, include
119 from rest_framework.routers import SimpleRouter
120 from .views import PetView, BindPetView, PetAvatarView
121 
122 router = SimpleRouter()
123 router.register("petinfo", PetView, "petinfo")
124 router.register("bindpet", BindPetView, "bindpet")
125 router.register("petavatar", PetAvatarView, "petavatar")
126 
127 urlpatterns = [path("", include(router.urls))]
128 
129 -----------------------------------------------------------------------------------
130 view.py
131 
132 from django.shortcuts import render
133 from rest_framework.viewsets import GenericViewSet
134 from .models import Pet
135 from .serializer import PetSerializer, BindPetSerializer
136 from utils.common_response import APIResponse
137 from rest_framework_simplejwt.authentication import JWTAuthentication
138 from rest_framework.permissions import IsAuthenticated
139 from django.core.files.storage import default_storage
140 from django.core.files.base import ContentFile
141 from rest_framework.exceptions import APIException
142 from rest_framework.decorators import action
143 
144 
145 class PetView(GenericViewSet):
146     queryset = Pet.objects.all()
147     serializer_class = PetSerializer
148     authentication_classes = [JWTAuthentication]
149     permission_classes = [IsAuthenticated]
150 
151     @action(methods=["GET"], detail=False)
152     def all_pet(self, request, *args, **kwargs):
153         queryset = self.get_queryset()
154         serializer = self.get_serializer(queryset, many=True)
155         return APIResponse(data=serializer.data)
156 
157     @action(methods=["GET"], detail=False)
158     def user_pet(self, request, *args, **kwargs):
159         user = request.user.id
160         queryset = Pet.objects.filter(user=user)
161         serializer = self.get_serializer(queryset, many=True)
162         return APIResponse(results=serializer.data)
163 
164 
165 class BindPetView(GenericViewSet):
166     queryset = Pet.objects.all()
167     serializer_class = BindPetSerializer
168     authentication_classes = [JWTAuthentication]
169     permission_classes = [IsAuthenticated]
170 
171     # 添加宠物
172     def create(self, request, *args, **kwargs):
173         user = self.request.user.id
174         request.data["user"] = user
175         icon = request.headers.get("Icon").replace("/media/", "")
176         print(request.headers.get("Icon"))
177         print(icon)
178         serializer = self.get_serializer(data=request.data)
179         serializer.is_valid(raise_exception=True)
180         pet_obj = serializer.save()
181         pet_obj.icon = icon
182         pet_obj.save()
183         return APIResponse(msg="添加成功!")
184 
185 
186 class PetAvatarView(GenericViewSet):
187     def create(self, request, *args, **kwargs):
188         avatar = request.FILES.get("avatar")
189         if avatar:
190             file_name = default_storage.save(
191                 f"pet_icon/" + str(avatar)[-15:], ContentFile(avatar.read())
192             )
193             # print(file_name)  # pet_icon/716f48749ef.jpg
194             file_url = default_storage.url(file_name)  # /media/pet_icon/716f48749ef.jpg
195             path = "http://192.168.1.38:8000" + file_url
196             print(path)
197         else:
198             raise APIException("服务器异常!")
199         return APIResponse(msg="上传头像成功!", file_url=path, file_name=file_name)

 

user表

  1 admin.py
  2 
  3 from django.contrib import admin
  4 
  5 # Register your models here.
  6 from .models import *
  7 
  8 
  9 @admin.register(User)
 10 class UserAdmin(admin.ModelAdmin):
 11     list_display = ("id", "username", "mobile", "gender", "age", "is_pet_feeder")
 12 
 13 
 14 @admin.register(UserAddress)
 15 class UserAddressAdmin(admin.ModelAdmin):
 16     list_display = (
 17         "name",
 18         "mobile",
 19         "province",
 20         "city",
 21         "detail",
 22         "is_default",
 23     )
 24 
 25 
 26 @admin.register(PetFeeder)
 27 class PetFeederAdmin(admin.ModelAdmin):
 28     list_display = (
 29         "name",
 30         "icon",
 31         "gender",
 32         "desc",
 33         "service_duration",
 34         "price",
 35     )
 36 
 37 ----------------------------------------------------------------------------------
 38 apps.py
 39 
 40 from django.apps import AppConfig
 41 
 42 
 43 class UserConfig(AppConfig):
 44     default_auto_field = "django.db.models.BigAutoField"
 45     name = "user"
 46     verbose_name = "用户"
 47 
 48 -----------------------------------------------------------------------------------
 49 models.py
 50 
 51 from django.db import models
 52 from django.contrib.auth.models import AbstractUser
 53 
 54 
 55 # 用户表
 56 class User(AbstractUser):
 57     GENDER_CHOICES = [
 58         (0, ""),
 59         (1, ""),
 60     ]
 61     PETFEEDER_CHOICES = [(0, ""), (1, "")]
 62     mobile = models.CharField(
 63         max_length=11, unique=True, verbose_name="手机号"
 64     )  # 手机号
 65     icon = models.ImageField(
 66         upload_to="icon", default="icon/default.png", verbose_name="头像"
 67     )  # 头像
 68     gender = models.IntegerField(
 69         choices=GENDER_CHOICES, null=True, verbose_name="性别", blank=True
 70     )  # 性别
 71     age = models.CharField(max_length=32, null=True, verbose_name="年龄")  # 年龄
 72     is_pet_feeder = models.IntegerField(
 73         choices=PETFEEDER_CHOICES, default=0, verbose_name="是否喂养员"
 74     )  # 是否是喂养员
 75     feeder = models.OneToOneField(
 76         to="PetFeeder",
 77         on_delete=models.CASCADE,
 78         null=True,
 79         blank=True,
 80         verbose_name="喂养员id",
 81     )  # type: ignore
 82 
 83     class Meta:
 84         db_table = "puddingpet_user"
 85         verbose_name = "用户表"
 86         verbose_name_plural = verbose_name
 87 
 88     def __str__(self):
 89         return self.username
 90 
 91 
 92 # 用户地址表,一个用户可以有多个地址,一个地址只能属于一个用户
 93 class UserAddress(models.Model):
 94     name = models.CharField(max_length=32, verbose_name="名字")  # 名字
 95     mobile = models.CharField(max_length=11, verbose_name="手机号")  # 手机号
 96     province = models.CharField(max_length=32, verbose_name="")  #
 97     city = models.CharField(max_length=32, verbose_name="")  #
 98     detail = models.CharField(max_length=128, verbose_name="详细地址")  # 详细地址
 99     is_default = models.BooleanField(default=False, verbose_name="是否默认")  # 是否默认
100     user = models.ForeignKey(
101         User, on_delete=models.CASCADE, verbose_name="对应用户"
102     )  # 对应用户
103 
104     class Meta:
105         db_table = "puddingpet_address"
106         verbose_name = "用户地址表"
107         verbose_name_plural = verbose_name
108 
109     def __str__(self):
110         return self.name
111 
112 
113 # 喂养员表
114 class PetFeeder(models.Model):
115     GENDER_CHOICES = [
116         (0, ""),
117         (1, ""),
118     ]
119     FEED_TYPE_CHOICES = [(0, ""), (1, "")]
120     name = models.CharField(max_length=32, verbose_name="名字")  # 名字
121     icon = models.ImageField(
122         upload_to="feeder_icon", default="feeder_icon/default.png", verbose_name="头像"
123     )  # 头像
124     gender = models.IntegerField(
125         choices=GENDER_CHOICES, null=True, verbose_name="性别"
126     )  # 性别
127     desc = models.TextField(blank=True, null=True, verbose_name="简介")  # 简介
128     service_duration = models.CharField(
129         max_length=255, verbose_name="服务时长"
130     )  # 服务时长
131     price = models.IntegerField(verbose_name="价格")  # 价格
132     feed_type = models.IntegerField(
133         choices=FEED_TYPE_CHOICES, null=True, verbose_name="喂养类型"
134     )  # 喂养类型(猫,狗)
135 
136     class Meta:
137         db_table = "puddingpet_feeder"
138         verbose_name = "喂养员表"
139         verbose_name_plural = verbose_name
140 
141     def __str__(self):
142         return self.name
143 
144 
145 # 消息表
146 class Message(models.Model):
147     sender = models.ForeignKey(
148         User,
149         related_name="sent_messages",
150         on_delete=models.CASCADE,
151         verbose_name="发送者",
152     )  # 发送者
153     receiver = models.ForeignKey(
154         User,
155         related_name="received_messages",
156         on_delete=models.CASCADE,
157         verbose_name="接收者",
158     )  # 接收者
159     content = models.TextField(verbose_name="内容")  # 内容
160     send_time = models.DateTimeField(
161         auto_now_add=True, verbose_name="发送时间"
162     )  # 发送时间
163 
164     class Meta:
165         db_table = "puddingpet_message"
166         verbose_name = "消息表"
167         verbose_name_plural = verbose_name
168 
169     def __str__(self):
170         return str(self.sender)
171 
172 
173 # 用户反馈表
174 class Feedback(models.Model):
175     image = models.ImageField(
176         upload_to="feedback", verbose_name="反馈图片", null=True, blank=True
177     )
178     content = models.TextField(verbose_name="反馈内容")
179 
180     class Meta:
181         db_table = "puddingpet_feedback"
182         verbose_name = "反馈表"
183         verbose_name_plural = verbose_name
184 
185 
186 class UserBalance(models.Model):
187     user = models.ForeignKey(
188         User,
189         related_name="user_balance",
190         on_delete=models.CASCADE,
191         verbose_name="用户",
192     )
193     balance = models.IntegerField(verbose_name="用户余额")
194 
195     class Meta:
196         db_table = "puddingpet_user_balance"
197         verbose_name = "用户余额表"
198         verbose_name_plural = verbose_name
199 
200 
201 class FeederRemuneration(models.Model):
202     feeder = models.ForeignKey(
203         PetFeeder,
204         related_name="feeder_remuneration",
205         on_delete=models.CASCADE,
206         verbose_name="喂养员",
207     )
208     remuneration = models.DecimalField(
209         verbose_name="喂养员酬金",
210         max_digits=10,  # Total number of digits (adjust as needed)
211         decimal_places=2,  # Number of decimal places (adjust as needed)
212     )
213 
214     class Meta:
215         db_table = "puddingpet_feeder_remuneration"
216         verbose_name = "喂养员酬金表"
217         verbose_name_plural = verbose_name
218 
219 --------------------------------------------------------------------------------
220 serializers.py
221 
222 from rest_framework import serializers
223 from django.core.cache import cache
224 from django.conf import settings
225 from rest_framework.exceptions import ValidationError, APIException
226 from rest_framework_simplejwt.tokens import RefreshToken
227 import re
228 from .models import (
229     User,
230     Message,
231     PetFeeder,
232     UserAddress,
233     Feedback,
234     UserBalance,
235     FeederRemuneration,
236 )
237 
238 
239 class CommonLoginSerializer:
240     def _get_user(self, attrs):
241         raise Exception("这个方法必须被重写")
242 
243     def _get_token(self, user):
244         refresh = RefreshToken.for_user(user)
245         return str(refresh.access_token)
246 
247     def _pre_data(self, token, user):
248         self.context["token"] = token
249         self.context["username"] = user
250         # self.instance=user # 当前用户,放到instance中了
251         self.context["icon"] = (
252             settings.BACKEND_URL + "media/" + str(user.icon)
253         )  # 不带 域名前缀的
254 
255     def validate(self, attrs):
256         # 1 取出用户名(手机号,邮箱)和密码
257         user = self._get_user(attrs)
258         # 2 如果存在:签发token,返回
259         token = self._get_token(user)
260         # 3 把token,用户名和icon放入context
261         self._pre_data(token, user)
262         return attrs
263 
264 
265 class LoginSerializer(CommonLoginSerializer, serializers.ModelSerializer):
266     username = serializers.CharField()
267 
268     class Meta:
269         model = User
270         fields = ["username", "password", "icon"]
271         extra_kwargs = {"password": {"write_only": True}}  # 它不做序列化
272         # depth = 1
273 
274     def _get_user(self, attrs):
275         username = attrs.get("username")
276         password = attrs.get("password")
277         if re.match(r"^1[3-9][0-9]{9}$", username):
278             user = User.objects.filter(mobile=username).first()
279         elif re.match("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$", username):  # type: ignore
280             user = User.objects.filter(email=username).first()
281         else:
282             user = User.objects.filter(username=username).first()
283 
284         if user and user.check_password(password):
285             return user
286         else:
287             raise ValidationError("用户名或密码错误")
288 
289 
290 class SMSLoginSerializer(CommonLoginSerializer, serializers.Serializer):
291     code = serializers.CharField()
292     mobile = serializers.CharField()
293 
294     def _get_user(self, attrs):
295         mobile = attrs.get("mobile")
296         code = attrs.get("code")
297         old_code = cache.get(f"cache_code_{mobile}")
298         assert old_code == code or (settings.DEBUG and code == "8888"), ValidationError(
299             "验证码错误"
300         )
301         user = User.objects.filter(mobile=mobile).first()
302         assert user, ValidationError("该手机号未注册!")
303         return user
304 
305 
306 class RegisterSerializer(serializers.ModelSerializer):
307     code = serializers.CharField()
308 
309     class Meta:
310         model = User
311         fields = ["mobile", "password", "code"]
312 
313     def validate(self, attrs):
314         code = attrs.pop("code")
315         mobile = attrs.get("mobile")
316         old_code = cache.get(f"cache_code_{mobile}")
317         assert old_code == code or (settings.DEBUG and code == "8888"), ValidationError(
318             "验证码错误"
319         )
320         attrs["username"] = mobile
321         return attrs
322 
323     def create(self, validated_data):
324         user = User.objects.create_user(**validated_data)  # type: ignore
325         UserBalance.objects.create(balance=0, user=user)
326         return user
327 
328 
329 class CheckMessageSerializer(serializers.Serializer):
330     content = serializers.CharField(read_only=True)
331     send_time = serializers.CharField(read_only=True)
332     sender = serializers.CharField()
333     receiver = serializers.CharField()
334 
335 
336 class PetFeederSerializer(serializers.ModelSerializer):
337     gender = serializers.CharField(source="get_gender_display")
338     feed_type = serializers.CharField(source="get_feed_type_display")
339     icon = serializers.SerializerMethodField()
340 
341     class Meta:
342         model = PetFeeder
343         fields = [
344             "id",
345             "name",
346             "icon",
347             "gender",
348             "desc",
349             "service_duration",
350             "price",
351             "feed_type",
352         ]
353 
354     def get_icon(self, obj):
355         return settings.ICON_URL + obj.icon.url
356 
357 
358 class UserSerializer(serializers.ModelSerializer):
359     feeder = PetFeederSerializer(read_only=True)
360     gender = serializers.CharField(source="get_gender_display")
361 
362     class Meta:
363         model = User
364         fields = ["id", "username", "mobile", "icon", "gender", "age", "feeder"]
365 
366 
367 class MessageSerializer(serializers.Serializer):
368     content = serializers.CharField()
369     send_time = serializers.SerializerMethodField(read_only=True)
370     sender = serializers.CharField()
371     receiver = serializers.CharField()
372 
373     def create(self, validated_data):
374         # {'content': '123', 'sender': 'heart', 'receiver': '1'}
375         sender_name = validated_data.get("sender")
376         receiver_id = validated_data.get("receiver")
377         content = validated_data.get("content")
378         sender_obj = User.objects.filter(username=sender_name).first()
379         feeder_obj = User.objects.filter(feeder=receiver_id).first()
380         msg = Message.objects.create(
381             content=content, sender=sender_obj, receiver=feeder_obj
382         )
383         return msg
384 
385     def get_send_time(self, obj):
386         return obj.send_time.strftime("%Y-%m-%d %H:%M:%S")
387 
388 
389 # 地址序列化类
390 class AddressSerializer(serializers.ModelSerializer):
391     class Meta:
392         model = UserAddress
393         fields = ["id", "name", "mobile", "province", "city", "detail", "is_default"]
394 
395     def create(self, validated_data):
396         user_id = self.context
397         user_obj = User.objects.filter(pk=user_id).first()
398         address = UserAddress.objects.create(**validated_data, user=user_obj)
399         return address
400 
401     def update(self, instance, validated_data):
402         user = self.context
403         useraddr_obj = UserAddress.objects.filter(pk=instance.id).first()
404         for attr, value in validated_data.items():
405             setattr(useraddr_obj, attr, value)
406         useraddr_obj.user = user
407         useraddr_obj.save()
408         return useraddr_obj
409 
410 
411 class UserEditNameSerializer(serializers.Serializer):
412     username = serializers.CharField()
413     gender = serializers.CharField()
414     mobile = serializers.CharField()
415 
416     def update(self, instance, validated_data):
417         new_username = validated_data.get("username")
418         new_gender = validated_data.get("gender")
419         mobile = validated_data.get("mobile")
420         if new_gender == "":
421             gender = 1
422         elif new_gender == "":
423             gender = 0
424         user = User.objects.filter(mobile=mobile).update(
425             username=new_username, gender=gender, mobile=mobile
426         )
427         return user
428 
429 
430 class UserMsgListSerializer(serializers.Serializer):
431     id = serializers.CharField(read_only=True)
432     content = serializers.CharField(read_only=True)
433     send_time = serializers.SerializerMethodField(read_only=True)
434     sender = UserSerializer(read_only=True)
435     receiver = UserSerializer(read_only=True)
436 
437     def get_send_time(self, obj):
438         return obj.send_time.strftime("%Y-%m-%d %H:%M:%S")
439 
440 
441 class RegFeederSerializer(serializers.Serializer):
442     name = serializers.CharField()
443     gender = serializers.CharField()
444     desc = serializers.CharField()
445     service_duration = serializers.CharField()
446     price = serializers.CharField()
447     feed_type = serializers.CharField()
448 
449     def create(self, validated_data):
450         user = self.context
451         petfeeder = PetFeeder.objects.create(**validated_data)
452         user_obj = User.objects.filter(pk=user).first()
453         user_obj.is_pet_feeder = 1
454         user_obj.feeder_id = petfeeder
455         user_obj.save()
456         FeederRemuneration.objects.create(remuneration=0, feeder=petfeeder)
457         return petfeeder
458 
459 
460 class FeedbackSerializer(serializers.ModelSerializer):
461     class Meta:
462         model = Feedback
463         fields = "__all__"
464 
465     def create(self, validated_data):
466         feed_obj = Feedback.objects.create(**validated_data, image=self.context)
467         return feed_obj
468 
469 
470 # 查询余额序列化类
471 class UserBalanceSerializer(serializers.ModelSerializer):
472     amount = serializers.DecimalField(
473         max_digits=10, decimal_places=2, min_value=0.01, required=True
474     )
475 
476     class Meta:
477         model = UserBalance
478         fields = ["id", "amount", "balance"]
479 
480 ---------------------------------------------------------------------------------
481 urls.py
482 
483 from django.contrib import admin
484 from django.urls import path, include
485 from rest_framework.routers import DefaultRouter
486 from .views import (
487     UserRegisterView,
488     UserMobileView,
489     UserLoginView,
490     MessageView,
491     PetFeederView,
492     PetFeederFilterView,
493     AddressView,
494     UserAvatarView,
495     UserInfoView,
496     UserAllAddressView,
497     UserMsgListView,
498     RegisterFeederView,
499     FeedbackView,
500     UserBalanceView,
501 )
502 
503 router = DefaultRouter()
504 
505 router.register("register", UserRegisterView, "register")
506 router.register("mobile", UserMobileView, "mobile")
507 router.register("mul_login", UserLoginView, "mul_login")
508 router.register("pet_feeder", PetFeederView, "pet_feeder")
509 router.register("pet_feeder_filter", PetFeederFilterView, "pet_feeder_filter")
510 router.register("message", MessageView, "message")
511 router.register("addr", AddressView, "addr")
512 router.register("avatar", UserAvatarView, "avatar")
513 router.register("userinfo", UserInfoView, "userinfo")
514 router.register("all_addr", UserAllAddressView, "all_addr")
515 router.register("usermsglist", UserMsgListView, "usermsglist")
516 router.register("regfeeder", RegisterFeederView, "regfeeder")
517 router.register("feedback", FeedbackView, "feedback")
518 router.register("recharge", UserBalanceView, "recharge")
519 
520 urlpatterns = [
521     path("", include(router.urls)),
522 ]
523 
524 ----------------------------------------------------------------------------------
525 views.py
526 
527 from django.shortcuts import get_object_or_404, render
528 from rest_framework.mixins import CreateModelMixin
529 from utils.common_logger import logger
530 from utils.common_response import APIResponse
531 from rest_framework.viewsets import GenericViewSet, ViewSet, ModelViewSet
532 from rest_framework.decorators import action
533 from .models import User, PetFeeder, UserAddress, Feedback, UserBalance
534 from django.core.cache import cache
535 from libs.tencent_sms import get_code, send_sms as sms
536 from threading import Thread
537 from utils.common_mixin import (
538     APIListModelMixin,
539     APIRetrieveModelMixin,
540 )
541 from .serializer import (
542     RegisterSerializer,
543     LoginSerializer,
544     SMSLoginSerializer,
545     MessageSerializer,
546     PetFeederSerializer,
547     UserSerializer,
548     AddressSerializer,
549     UserEditNameSerializer,
550     UserMsgListSerializer,
551     RegFeederSerializer,
552     FeedbackSerializer,
553     UserBalanceSerializer,
554 )
555 from .models import User, Message
556 from rest_framework_simplejwt.authentication import JWTAuthentication
557 from rest_framework.permissions import IsAuthenticated
558 from rest_framework.decorators import action
559 from rest_framework.exceptions import APIException
560 from django.core.files.storage import default_storage
561 from django.core.files.base import ContentFile
562 from django.contrib import auth
563 from django.db.models import Q
564 import re
565 
566 
567 # 发送短信接口
568 class UserMobileView(GenericViewSet):
569     @action(methods=["GET"], detail=False)
570     def check_mobile(self, request, *args, **kwargs):
571         mobile = request.query_params.get("mobile")
572         if mobile:
573             if re.match(r"^1[3-9][0-9]{9}$", mobile):
574                 user = User.objects.filter(mobile=mobile).first()
575             else:
576                 return APIResponse(code=400, msg="手机号不符合!")
577             if user:
578                 return APIResponse(code=400, msg="手机号已存在!")
579             return APIResponse(msg="手机号不存在!")
580         return APIResponse(code=400, msg="还未填写手机号!")
581 
582     @action(methods=["GET"], detail=False)
583     def send_sms(self, request, *args, **kwargs):
584         mobile = request.query_params.get("mobile")
585         code = get_code()
586         cache.set(f"cache_code_{mobile}", code)
587         t = Thread(target=sms, args=[mobile, code])
588         t.start()
589         return APIResponse(msg="短信已发送")
590 
591 
592 # 多方式登录接口
593 class UserLoginView(GenericViewSet):
594     serializer_class = LoginSerializer
595 
596     def get_serializer_class(self):
597         if self.action == "sms_login":
598             return SMSLoginSerializer
599         else:
600             return LoginSerializer
601 
602     def _login(self, request, *args, **kwargs):
603         serializer = self.get_serializer(data=request.data)
604         serializer.is_valid(raise_exception=True)
605         token = serializer.context.get("token")
606         user = serializer.context.get("username")
607         icon = serializer.context.get("icon")
608         auth.login(request, user)
609         return APIResponse(
610             token=token, username=user.username, icon=icon, msg="登录成功!"
611         )
612 
613     @action(methods=["POST"], detail=False)
614     def multiple_login(self, request, *args, **kwargs):
615         return self._login(request, *args, **kwargs)
616 
617     @action(methods=["POST"], detail=False)
618     def sms_login(self, request, *args, **kwargs):
619         return self._login(request, *args, **kwargs)
620 
621 
622 # 用户注册接口
623 class UserRegisterView(GenericViewSet):
624     serializer_class = RegisterSerializer
625 
626     def create(self, request, *args, **kwargs):
627         serializer = self.get_serializer(data=request.data)
628         serializer.is_valid(raise_exception=True)
629         serializer.save()
630         return APIResponse(msg="注册成功!")
631 
632 
633 # 消息接口
634 class MessageView(GenericViewSet):
635     queryset = Message.objects.all()
636     serializer_class = MessageSerializer
637     authentication_classes = [JWTAuthentication]
638     permission_classes = [IsAuthenticated]
639 
640     def list(self, request, *args, **kwargs):
641         send_name = request.query_params.get("send_name")
642         recv_id = request.query_params.get("recv_id")
643         send_obj = User.objects.filter(username=send_name).first()
644         feeder_obj = User.objects.filter(feeder=recv_id).first()
645         if send_obj and feeder_obj:
646             qs = Message.objects.filter(
647                 Q(sender=send_obj, receiver=feeder_obj)
648                 | Q(sender=feeder_obj, receiver=send_obj)
649             ).order_by("send_time")
650         serializer = self.get_serializer(instance=qs, many=True)
651         return APIResponse(results=serializer.data)
652 
653     def create(self, request, *args, **kwargs):
654         serializer = self.get_serializer(data=request.data)
655         serializer.is_valid(raise_exception=True)
656         serializer.save()
657         return APIResponse(results=serializer.data)
658 
659 
660 # 查询所有喂养员
661 class PetFeederView(GenericViewSet, APIListModelMixin, APIRetrieveModelMixin):
662     queryset = PetFeeder.objects.all()
663     serializer_class = UserSerializer
664 
665     def get_serializer_class(self):
666         if self.action == "list":
667             return UserSerializer
668         elif self.action == "retrieve":
669             return PetFeederSerializer
670         else:
671             return PetFeederSerializer
672 
673     def get_object(self):
674         obj_id = self.kwargs.get("pk")
675         user = get_object_or_404(User, feeder=obj_id)
676         feeder_data = user.feeder
677         return feeder_data
678 
679     def get_queryset(self):
680         return User.objects.filter(is_pet_feeder=1)
681 
682 
683 class PetFeederFilterView(ViewSet):
684     def list(self, request, *args, **kwargs):
685         radio = int(request.GET.get("radio"))
686         if radio == 2:
687             queryset = PetFeeder.objects.all()
688         else:
689             queryset = PetFeeder.objects.filter(feed_type=int(radio))
690         serializer = PetFeederSerializer(queryset, many=True)
691         return APIResponse(results=serializer.data)
692 
693 
694 # 添加地址接口
695 from rest_framework.decorators import action
696 from rest_framework import status
697 
698 
699 class AddressView(GenericViewSet):
700     serializer_class = AddressSerializer
701     authentication_classes = [JWTAuthentication]
702     permission_classes = [IsAuthenticated]
703 
704     def create(self, request, *args, **kwargs):
705         user = self.request.user.id
706         serializer = self.get_serializer(data=request.data, context=user)
707         serializer.is_valid(raise_exception=True)
708         serializer.save()
709         return APIResponse(msg="添加地址成功!")
710 
711 
712 # 查询当前登录用户所有地址 all_addr
713 class UserAllAddressView(GenericViewSet):
714     authentication_classes = [JWTAuthentication]
715     permission_classes = [IsAuthenticated]
716     serializer_class = AddressSerializer
717     queryset = UserAddress.objects.all()
718 
719     def get_queryset(self):
720         # 获取当前登录的用户,只返回自己的地址
721         user = self.request.user
722         queryset = UserAddress.objects.filter(user=user)
723         return queryset
724 
725     def list(self, request, *args, **kwargs):
726         queryset = self.filter_queryset(self.get_queryset())
727         # 如果查询集为空,则返回一个带有自定义消息的响应
728         if not queryset.exists():
729             return APIResponse(detail="该用户没有地址")
730         # 序列化查询集并返回响应
731         else:
732             serializer = self.get_serializer(queryset, many=True)
733             return APIResponse(msg="获取地址列表成功!", results=serializer.data)
734 
735     # 修改地址
736     def update(self, request, *args, **kwargs):
737         qs = self.get_object()
738         serializer = self.get_serializer(
739             instance=qs, data=request.data, context=self.request.user
740         )
741         serializer = self.get_serializer(
742             instance=qs, data=request.data, context=self.request.user
743         )
744         serializer.is_valid(raise_exception=True)
745         serializer.save()
746         return APIResponse(msg="修改地址成功!")
747 
748     # 删除地址
749     @action(methods=["delete"], detail=True)
750     # def delete_address(self, request, pk=None):
751     def destroy_info(self, request, *args, **kwargs):
752         print("svi")
753         address = self.get_object()
754         if address.user != request.user:
755             return APIResponse(code=400, msg="无权删除他人地址")
756         address.delete()
757         return APIResponse(msg="删除地址成功!")
758 
759 
760 class UserAvatarView(GenericViewSet):
761     queryset = User.objects.all()
762 
763     def create(self, request, *args, **kwargs):
764         avatar = request.FILES.get("avatar")
765         username = request.data.get("user")
766         if avatar:
767             file_name = default_storage.save(
768                 f"user/{username}/" + str(avatar)[-15:], ContentFile(avatar.read())
769             )
770             # logger.info(file_name)  # logger.info(file_name)
771             file_url = default_storage.url(file_name).replace("/media/", "")
772             # print(file_url)  # /media/user/heart/517b8dc72d4.jpg
773             # logger.info(file_url)  # /user/heart/43aa2b8998c.jpg
774             user = User.objects.filter(username=username).first()
775             user.icon = file_url  # type: ignore
776             user.save()  # type: ignore
777             path = f"http://192.168.1.38:8000/media/{file_url}"
778             print(path)  # http://192.168.1.38:8000/media/user/heart/237f61825e8.jpg
779         else:
780             raise APIException("服务器异常!")
781         return APIResponse(msg="上传头像成功!", path=path)
782 
783 
784 class UserInfoView(GenericViewSet):
785     queryset = User.objects.all()
786     serializer_class = UserSerializer
787     permission_classes = [IsAuthenticated]
788     authentication_classes = [JWTAuthentication]
789 
790     def get_queryset(self):
791         return User.objects.filter(pk=self.request.user.id)  # type: ignore
792 
793     def get_serializer_class(self):
794         if self.action == "list":
795             return UserSerializer
796         elif self.action == "update":
797             return UserEditNameSerializer
798         else:
799             return UserEditNameSerializer
800 
801     def list(self, request, *args, **kwargs):
802         qs = self.get_queryset().first()
803         serializer = self.get_serializer(instance=qs)
804         return APIResponse(result=serializer.data)
805 
806     def put(self, request, *args, **kwargs):
807         serializer = self.get_serializer(data=request.data)
808         user = self.request.user
809         serializer = self.get_serializer(instance=user, data=request.data)
810         serializer.is_valid(raise_exception=True)
811         serializer.save()
812         return APIResponse(msg="修改成功!")
813 
814 
815 class UserMsgListView(GenericViewSet, APIListModelMixin):
816     queryset = Message.objects.all()
817     serializer_class = UserMsgListSerializer
818     permission_classes = [IsAuthenticated]
819     authentication_classes = [JWTAuthentication]
820 
821     def get_queryset(self):
822         user = self.request.user
823         instance = Message.objects.filter(Q(sender=user) | Q(receiver=user))
824         return instance
825 
826 
827 class RegisterFeederView(GenericViewSet):
828     serializer_class = RegFeederSerializer
829     permission_classes = [IsAuthenticated]
830     authentication_classes = [JWTAuthentication]
831 
832     def create(self, request, *args, **kwargs):
833         user = self.request.user.id
834         user_obj = User.objects.filter(pk=user).first()
835         if user_obj.is_pet_feeder == 1:
836             return APIResponse(code=400, msg="已是喂养员!请勿重复注册!")
837         else:
838             serializer = self.get_serializer(data=request.data, context=user)
839             serializer.is_valid(raise_exception=True)
840             serializer.save()
841             return APIResponse(msg="注册成功!")
842 
843 
844 class FeedbackView(GenericViewSet):
845     serializer_class = FeedbackSerializer
846 
847     def create(self, request, *args, **kwargs):
848         file = request.FILES.get("file")
849         if file:
850             file_name = default_storage.save(
851                 f"feedback/" + str(file)[-15:], ContentFile(file.read())
852             )
853             file_url = default_storage.url(file_name)  # /media/pet_icon/716f48749ef.jpg
854             path = "http://192.168.1.38:8000" + file_url
855         else:
856             raise APIException("服务器异常!")
857         return APIResponse(msg="上传图片成功!", file_name=file_name, file_url=path)
858 
859     @action(methods=["POST"], detail=False)
860     def feedback(self, request, *args, **kwargs):
861         image = request.data.pop("image")
862         serializer = self.get_serializer(data=request.data, context=image)
863         serializer.is_valid(raise_exception=True)
864         serializer.save()
865         return APIResponse(msg="反馈成功!")
866 
867 
868 # 查询用户余额
869 class UserBalanceView(GenericViewSet):
870     serializer_class = UserBalanceSerializer
871     permission_classes = [IsAuthenticated]
872     authentication_classes = [JWTAuthentication]
873 
874     def get_queryset(self):
875         return User.objects.filter(pk=self.request.user.id)
876 
877     @action(methods=["GET"], detail=False)
878     def get_balance(self, request):
879         user_balance = self.get_queryset().first()
880         if user_balance:
881             from django.forms.models import model_to_dict
882 
883             instance = UserBalance.objects.get(user_id=user_balance.id)
884             print(instance.balance)
885             return APIResponse(data=instance.balance)
886         return APIResponse(msg="暂无余额记录")
887 
888     @action(methods=["POST"], detail=False)
889     def recharge_balance(self, request, *args, **kwargs):
890         amount = request.data.get("amount")
891         print(amount)
892         obj = self.get_queryset().first()
893         if obj:
894             user_balance = UserBalance.objects.get(user_id=obj.id)
895             print(user_balance)
896             user_balance.balance += int(amount)
897             user_balance.save()
898             return APIResponse(data=user_balance.balance)
899         else:
900             return APIResponse(msg="充值金额未提供")

 

 1 settings.py
 2 
 3 # -*- coding: utf-8 -*-
 4 # author : heart
 5 # blog_url : https://www.cnblogs.com/ssrheart/
 6 # time : 2024/5/14
 7 
 8 SECRET_ID = 'AKIDrbEk9QZbR6Xq22vuo2A9wshMnBRjx8B1'
 9 SECRET_KEY = 'jDZnuunfR1UtEjFslgVG16Tp8JNJ6kCV'
10 SMS_SDK_APPID = "1400635776"
11 SIGN_NAME = '小猿取经公众号'
12 TEMPLATE_ID = "1049981"
13 
14 
15 ---------------------------------------------------------------------------------------
16 
17 sms.py
18 
19 # -*- coding: utf-8 -*-
20 # author : heart
21 # blog_url : https://www.cnblogs.com/ssrheart/
22 # time : 2024/5/14
23 import json
24 
25 from tencentcloud.common import credential
26 from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
27 from tencentcloud.sms.v20210111 import sms_client, models
28 from tencentcloud.common.profile.client_profile import ClientProfile
29 from tencentcloud.common.profile.http_profile import HttpProfile
30 from .settings import *
31 import random
32 
33 
34 # 生成n位数字的随机验证码
35 def get_code(num=4):
36     code = ''
37     for i in range(num):
38         r = random.randint(0, 9)
39         code += str(r)
40 
41     return code
42 
43 
44 # 发送短信函数
45 def send_sms(mobile, code):
46     try:
47         cred = credential.Credential(SECRET_ID, SECRET_KEY)
48         httpProfile = HttpProfile()
49         httpProfile.reqMethod = "POST"  # post请求(默认为post请求)
50         httpProfile.reqTimeout = 30  # 请求超时时间,单位为秒(默认60秒)
51         httpProfile.endpoint = "sms.tencentcloudapi.com"  # 指定接入地域域名(默认就近接入)
52 
53         # 非必要步骤:
54         # 实例化一个客户端配置对象,可以指定超时时间等配置
55         clientProfile = ClientProfile()
56         clientProfile.signMethod = "TC3-HMAC-SHA256"  # 指定签名算法
57         clientProfile.language = "en-US"
58         clientProfile.httpProfile = httpProfile
59 
60         # 实例化要请求产品(以sms为例)的client对象
61         # 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8
62         client = sms_client.SmsClient(cred, "ap-guangzhou", clientProfile)
63         req = models.SendSmsRequest()
64         # 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看
65         req.SmsSdkAppId = SMS_SDK_APPID
66         # 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名
67         # 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看
68         req.SignName = SIGN_NAME
69         # 模板 ID: 必须填写已审核通过的模板 ID
70         # 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看
71         req.TemplateId = TEMPLATE_ID
72         # 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空
73         req.TemplateParamSet = [code, '1']
74         # 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
75         req.PhoneNumberSet = [f"+86{mobile}"]
76         # 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回
77         req.SessionContext = ""
78         # 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手]
79         req.ExtendCode = ""
80         # 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。注:月度使用量达到指定量级可申请独立 SenderId 使用,详情请联系 [腾讯云短信小助手](https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81)。
81         req.SenderId = ""
82         resp = client.SendSms(req)
83         # 输出json格式的字符串回包
84         res = json.loads(resp.to_json_string(indent=2))
85         if res.get('SendStatusSet')[0].get('Code') == 'Ok':
86             return True
87         else:
88             return False
89 
90     except TencentCloudSDKException as err:
91         print(err)
92         return False
93 
94 
95 if __name__ == '__main__':
96     print(get_code(3))

 

 

  1 common_settings.py
  2 
  3 BANNER_COUNT = 3
  4 
  5 # ============== celery配置 ============== #
  6 CELERY_BROKER_URL = "redis://127.0.0.1:6379/3"
  7 # BACKEND配置,使用redis
  8 CELERY_RESULT_BACKEND = "redis://127.0.0.1:6379/4"
  9 CELERY_ACCEPT_CONTENT = ["json"]
 10 CELERY_TASK_SERIALIZER = "json"
 11 # 结果序列化方案
 12 CELERY_RESULT_SERIALIZER = "json"
 13 # 任务结果过期时间,秒
 14 CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24
 15 # 时区配置
 16 CELERY_TIMEZONE = "Asia/Shanghai"
 17 
 18 ----------------------------------------------------------------------
 19 dev.py
 20 
 21 #
 22 #      ┌─┐       ┌─┐ + +
 23 #   ┌──┘ ┴───────┘ ┴──┐++
 24 #   │                 │
 25 #   │       ───       │++ + + +
 26 #   ███████───███████ │+
 27 #   │                 │+
 28 #   │       ─┴─       │
 29 #   │                 │
 30 #   └───┐         ┌───┘
 31 #       │         │
 32 #       │         │   + +
 33 #       │         │
 34 #       │         └──────────────┐
 35 #       │                        │
 36 #       │                        ├─┐
 37 #       │                        ┌─┘
 38 #       │                        │
 39 #       └─┐  ┐  ┌───────┬──┐  ┌──┘  + + + +
 40 #         │ ─┤ ─┤       │ ─┤ ─┤
 41 #         └──┴──┘       └──┴──┘  + + + +
 42 #                神兽保佑
 43 #               代码无BUG!
 44 
 45 from datetime import timedelta
 46 from pathlib import Path
 47 import sys, os
 48 
 49 BASE_DIR = Path(__file__).resolve().parent.parent
 50 apps = os.path.join(BASE_DIR, "apps")
 51 sys.path.insert(0, apps)
 52 sys.path.insert(0, str(BASE_DIR))
 53 
 54 SECRET_KEY = "django-insecure-w^5($((r_4ug)s!k(0xymkhns%mu+4gc%lp_bi(x@yd+8mj1ym"
 55 
 56 DEBUG = True
 57 
 58 ALLOWED_HOSTS = ["*"]
 59 
 60 # ============== APP配置 ============== #
 61 INSTALLED_APPS = [
 62     "simpleui",
 63     "django.contrib.admin",
 64     "django.contrib.auth",
 65     "django.contrib.contenttypes",
 66     "django.contrib.sessions",
 67     "django.contrib.messages",
 68     "django.contrib.staticfiles",
 69     "corsheaders",  # 跨域
 70     "rest_framework",  # drf
 71     "home",
 72     "user",
 73     "pet",
 74     "order",
 75 ]
 76 # ============== 中间件配置 ============== #
 77 MIDDLEWARE = [
 78     "django.middleware.security.SecurityMiddleware",
 79     "django.contrib.sessions.middleware.SessionMiddleware",
 80     "django.middleware.common.CommonMiddleware",
 81     "django.middleware.csrf.CsrfViewMiddleware",
 82     "django.contrib.auth.middleware.AuthenticationMiddleware",
 83     "django.contrib.messages.middleware.MessageMiddleware",
 84     "django.middleware.clickjacking.XFrameOptionsMiddleware",
 85     "corsheaders.middleware.CorsMiddleware",  # 跨域
 86 ]
 87 
 88 ROOT_URLCONF = "puddingpet_api.urls"
 89 
 90 TEMPLATES = [
 91     {
 92         "BACKEND": "django.template.backends.django.DjangoTemplates",
 93         "DIRS": [],
 94         "APP_DIRS": True,
 95         "OPTIONS": {
 96             "context_processors": [
 97                 "django.template.context_processors.debug",
 98                 "django.template.context_processors.request",
 99                 "django.contrib.auth.context_processors.auth",
100                 "django.contrib.messages.context_processors.messages",
101             ],
102         },
103     },
104 ]
105 
106 WSGI_APPLICATION = "puddingpet_api.wsgi.application"
107 ASGI_APPLICATION = "puddingpet_api.asgi.application"
108 
109 # ============== 数据库配置 ============== #
110 USER_NAME = os.environ.get("MYSQL_USER", "puddingpet")
111 USER_PASSWORD = os.environ.get("MYSQL_PASSWORD", "Pudding123?")
112 
113 
114 DATABASES = {
115     "default": {
116         "ENGINE": "django.db.backends.mysql",
117         "NAME": "puddingpet",
118         "USER": USER_NAME,
119         "PASSWORD": USER_PASSWORD,
120         "HOST": "1.94.109.143",
121         "PORT": 3306,
122         "CHARSET": "utf8mb4",
123     }
124 }
125 
126 AUTH_PASSWORD_VALIDATORS = [
127     {
128         "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
129     },
130     {
131         "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
132     },
133     {
134         "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
135     },
136     {
137         "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
138     },
139 ]
140 
141 # ============== 时区配置 ============== #
142 LANGUAGE_CODE = "zh-hans"
143 TIME_ZONE = "Asia/Shanghai"
144 USE_I18N = True
145 USE_TZ = False
146 
147 # ============== 静态文件配置 ============== #
148 STATIC_URL = "static/"
149 
150 # ============== models配置 ============== #
151 # 用于指定模型中自动生成主键字段的默认类型
152 # 如果没有在模型中明确指定主键字段类型,Django 将使用 BigAutoField 作为默认类型。
153 DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
154 
155 # ============== 跨域配置 ============== #
156 CORS_ORIGIN_ALLOW_ALL = True
157 
158 CORS_ALLOW_HEADERS = (
159     "accept",
160     "accept-encoding",
161     "authorization",
162     "content-type",
163     "dnt",
164     "origin",
165     "user-agent",
166     "x-csrftoken",
167     "x-requested-with",
168     # 额外允许的请求头
169     "token",
170 )
171 
172 # ============== auth表 ============== #
173 AUTH_USER_MODEL = "user.User"
174 
175 # ============== media设置 ============== #
176 MEDIA_URL = "/media/"
177 MEDIA_ROOT = os.path.join(BASE_DIR, "media")
178 
179 # ============== 日志 ============== #
180 from utils import common_logger
181 
182 common_logger.configure_logger()
183 
184 
185 # ============== 异常捕获 ============== #
186 REST_FRAMEWORK = {
187     "EXCEPTION_HANDLER": "utils.common_exception.exception_handler",
188     "DEFAULT_AUTHENTICATION_CLASSES": (
189         "rest_framework.authentication.TokenAuthentication",
190     ),
191 }
192 from .common_settings import *
193 
194 # import socket
195 
196 # ============== 头像拼接路径 ============== #
197 # HOST = socket.gethostbyname(socket.gethostname())
198 BACKEND_URL = "http://192.168.1.38:8000/"
199 ICON_URL = "http://192.168.1.38:8000"
200 
201 # ============== JWT配置 ============== #
202 SIMPLE_JWT = {
203     "ACCESS_TOKEN_LIFETIME": timedelta(days=7),  # Access Token的有效期
204 }
205 # ============== django-redis/cache配置 ============== #
206 CACHES = {
207     "default": {
208         "BACKEND": "django_redis.cache.RedisCache",
209         "LOCATION": "redis://127.0.0.1:6379",
210         "OPTIONS": {
211             "CLIENT_CLASS": "django_redis.client.DefaultClient",
212             "CONNECTION_POOL_KWARGS": {"max_connections": 100},
213         },
214     }
215 }
216 
217 
218 ----------------------------------------------------------------------------------
219 pro.py
220 
221 #
222 #      ┌─┐       ┌─┐ + +
223 #   ┌──┘ ┴───────┘ ┴──┐++
224 #   │                 │
225 #   │       ───       │++ + + +
226 #   ███████───███████ │+
227 #   │                 │+
228 #   │       ─┴─       │
229 #   │                 │
230 #   └───┐         ┌───┘
231 #       │         │
232 #       │         │   + +
233 #       │         │
234 #       │         └──────────────┐
235 #       │                        │
236 #       │                        ├─┐
237 #       │                        ┌─┘
238 #       │                        │
239 #       └─┐  ┐  ┌───────┬──┐  ┌──┘  + + + +
240 #         │ ─┤ ─┤       │ ─┤ ─┤
241 #         └──┴──┘       └──┴──┘  + + + +
242 #                神兽保佑
243 #               代码无BUG!
244 
245 from datetime import timedelta
246 from pathlib import Path
247 import sys, os
248 
249 BASE_DIR = Path(__file__).resolve().parent.parent
250 apps = os.path.join(BASE_DIR, "apps")
251 sys.path.insert(0, apps)
252 sys.path.insert(0, str(BASE_DIR))
253 
254 SECRET_KEY = "django-insecure-w^5($((r_4ug)s!k(0xymkhns%mu+4gc%lp_bi(x@yd+8mj1ym"
255 
256 DEBUG = True
257 
258 ALLOWED_HOSTS = ["*"]
259 
260 # ============== APP配置 ============== #
261 INSTALLED_APPS = [
262     "simpleui",
263     "django.contrib.admin",
264     "django.contrib.auth",
265     "django.contrib.contenttypes",
266     "django.contrib.sessions",
267     "django.contrib.messages",
268     "django.contrib.staticfiles",
269     "corsheaders",  # 跨域
270     "rest_framework",  # drf
271     "home",
272 ]
273 # ============== 中间件配置 ============== #
274 MIDDLEWARE = [
275     "django.middleware.security.SecurityMiddleware",
276     "django.contrib.sessions.middleware.SessionMiddleware",
277     "django.middleware.common.CommonMiddleware",
278     "django.middleware.csrf.CsrfViewMiddleware",
279     "django.contrib.auth.middleware.AuthenticationMiddleware",
280     "django.contrib.messages.middleware.MessageMiddleware",
281     "django.middleware.clickjacking.XFrameOptionsMiddleware",
282     "corsheaders.middleware.CorsMiddleware",  # 跨域
283 ]
284 
285 ROOT_URLCONF = "puddingpet_api.urls"
286 
287 TEMPLATES = [
288     {
289         "BACKEND": "django.template.backends.django.DjangoTemplates",
290         "DIRS": [],
291         "APP_DIRS": True,
292         "OPTIONS": {
293             "context_processors": [
294                 "django.template.context_processors.debug",
295                 "django.template.context_processors.request",
296                 "django.contrib.auth.context_processors.auth",
297                 "django.contrib.messages.context_processors.messages",
298             ],
299         },
300     },
301 ]
302 
303 WSGI_APPLICATION = "puddingpet_api.wsgi.application"
304 
305 
306 # ============== 数据库配置 ============== #
307 USER_NAME = os.environ.get("MYSQL_USER", "puddingpet")
308 USER_PASSWORD = os.environ.get("MYSQL_PASSWORD", "Pudding123?")
309 
310 
311 DATABASES = {
312     "default": {
313         "ENGINE": "django.db.backends.mysql",
314         "NAME": "puddingpet",
315         "USER": USER_NAME,
316         "PASSWORD": USER_PASSWORD,
317         "HOST": "1.94.109.143",
318         "PORT": 3306,
319         "CHARSET": "utf8mb4",
320     }
321 }
322 
323 AUTH_PASSWORD_VALIDATORS = [
324     {
325         "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
326     },
327     {
328         "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
329     },
330     {
331         "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
332     },
333     {
334         "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
335     },
336 ]
337 
338 # ============== 时区配置 ============== #
339 LANGUAGE_CODE = "zh-hans"
340 TIME_ZONE = "Asia/Shanghai"
341 USE_I18N = True
342 USE_TZ = False
343 
344 # ============== 静态文件配置 ============== #
345 STATIC_URL = "static/"
346 
347 # ============== models配置 ============== #
348 # 用于指定模型中自动生成主键字段的默认类型
349 # 如果没有在模型中明确指定主键字段类型,Django 将使用 BigAutoField 作为默认类型。
350 DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
351 
352 # ============== 跨域配置 ============== #
353 CORS_ORIGIN_ALLOW_ALL = True
354 
355 CORS_ALLOW_HEADERS = (
356     "accept",
357     "accept-encoding",
358     "authorization",
359     "content-type",
360     "dnt",
361     "origin",
362     "user-agent",
363     "x-csrftoken",
364     "x-requested-with",
365     # 额外允许的请求头
366     "token",
367 )
368 
369 # 设置auth表
370 # AUTH_USER_MODEL = "user.User"
371 
372 # 开启media
373 MEDIA_URL = "/media/"
374 MEDIA_ROOT = os.path.join(BASE_DIR, "media")
375 
376 # 日志
377 # from utils import common_logger
378 
379 # common_logger.configure_logger()
380 
381 
382 # ============== 异常捕获 ============== #
383 REST_FRAMEWORK = {
384     "EXCEPTION_HANDLER": "utils.common_exception.exception_handler",
385 }
386 from .common_settings import *
387 
388 # ============== 头像拼接路径 ============== #
389 BACKEND_URL = "http://127.0.0.1:8000/"
390 
391 # ============== JWT配置 ============== #
392 SIMPLE_JWT = {
393     "ACCESS_TOKEN_LIFETIME": timedelta(days=7),  # Access Token的有效期
394 }

 

  1 common_exception.py
  2 
  3 from rest_framework.views import exception_handler as drf_exception_handler
  4 from rest_framework.response import Response
  5 from utils.common_response import APIResponse
  6 from utils.common_logger import logger
  7 
  8 
  9 # 自定义异常类
 10 class PasswordException(Exception):
 11     pass
 12 
 13 
 14 def exception_handler(exc, context):
 15     res = drf_exception_handler(exc, context)
 16     print(res)
 17     request = context.get("request")
 18     view = context.get("view")
 19     ip = request.META.get("REMOTE_ADDR")
 20     path = request.get_full_path()
 21     method = request.method
 22     user_id = request.user.id or "匿名用户"
 23     logger.error(
 24         f"操作出错!{str(exc)},视图类:{str(view)},ip:{ip},请求地址:{path},请求方式:{method},用户id:{user_id}"
 25     )
 26 
 27     if res:
 28         # drf异常
 29         if isinstance(res.data, dict):
 30             err = (
 31                 res.data.get("detail")
 32                 or res.data.get("non_field_errors")
 33                 or "请正确输入!"
 34             )
 35         elif isinstance(res.data, list):
 36             err = res.data[0]
 37         else:
 38             err = "服务异常,请稍后再尝试,[drf]"
 39         # print(res.data)
 40         response = APIResponse(code=4000, msg=err)
 41     else:
 42         # 非drf异常
 43         if isinstance(exc, ZeroDivisionError):
 44             err = "数据操作出错,除以0了"
 45             code = 4001
 46         elif isinstance(exc, PasswordException):
 47             err = "密码错误!"
 48             code = 4002
 49         else:
 50             err = f"{str(exc)}"
 51             code = 4004
 52         response = APIResponse(code=code, msg=err)
 53 
 54     return response
 55 
 56 ---------------------------------------------------------------------------------
 57 common_logger.py
 58 
 59 from loguru import logger
 60 import os
 61 
 62 LOG_PATH = os.path.join("logs", "puddingpet.log")
 63 
 64 
 65 def configure_logger():
 66     # logger.remove()  # 清除默认的日志处理器
 67     # logger.level("CRITICAL")
 68     logger.add(f"{LOG_PATH}", rotation="300 MB", level="ERROR")
 69 
 70 ----------------------------------------------------------------------------------
 71 common_mixin.py
 72 
 73 from rest_framework.mixins import (
 74     CreateModelMixin,
 75     ListModelMixin,
 76     UpdateModelMixin,
 77     DestroyModelMixin,
 78     RetrieveModelMixin,
 79 )
 80 from utils.common_response import APIResponse
 81 from django.core.cache import cache
 82 from utils.common_logger import logger
 83 from rest_framework.exceptions import APIException
 84 
 85 
 86 class APIListModelMixin(ListModelMixin):
 87     def list(self, request, *args, **kwargs):
 88         res = super().list(request, *args, **kwargs)
 89         return APIResponse(results=res.data)
 90 
 91 
 92 class CacheListModelMixin(ListModelMixin):
 93     cache_key = None
 94 
 95     def list(self, request, *args, **kwargs):
 96         assert self.cache_key, APIException(
 97             "如果继承CacheListModelMixin,必须要加cache_key!"
 98         )
 99         results = cache.get(self.cache_key)
100         if not results:
101             logger.info("走了数据库")
102             res = super().list(request, *args, **kwargs)
103             results = res.data
104             cache.set(self.cache_key, results)
105         return APIResponse(results=results)
106 
107 
108 class APIRetrieveModelMixin(RetrieveModelMixin):
109     def retrieve(self, request, *args, **kwargs):
110         res = super().retrieve(request, *args, **kwargs)
111         return APIResponse(result=res.data)
112 
113 --------------------------------------------------------------------------------------
114 conmmon_models.py
115 
116 from django.db import models
117 
118 
119 class BaseModel(models.Model):
120     created_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
121     updated_time = models.DateTimeField(auto_now=True, verbose_name="最后更新时间")
122     is_delete = models.BooleanField(default=False, verbose_name="是否删除")
123     is_show = models.BooleanField(default=True, verbose_name="是否上架")
124     orders = models.IntegerField(verbose_name="优先级")
125 
126     class Meta:
127         abstract = True  # 只用来继承,不在数据库中生成表
128 
129 ---------------------------------------------------------------------------------
130 common_response.py
131 
132 from rest_framework.response import Response
133 
134 
135 class APIResponse(Response):
136 
137     def __init__(self, code=100, msg="成功!", headers=None, status=None, **kwargs):
138         data = {"code": code, "msg": msg}
139         if kwargs:
140             data.update(kwargs)
141         super().__init__(data=data, status=status, headers=headers)

 

 

 

 

 

 

posted on 2024-06-11 15:57  认真的六六  阅读(14)  评论(0编辑  收藏  举报