首页 > 其他分享 >期终架构项目后端-----宠物上门喂养

期终架构项目后端-----宠物上门喂养

时间:2024-06-11 16:12:09浏览次数:11  
标签:name models self 宠物 request ----- user 期终 import

【目录结构】

 

 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)

 

 

 

 

 

 

标签:name,models,self,宠物,request,-----,user,期终,import
From: https://www.cnblogs.com/liuliu1/p/18242224

相关文章

  • RT-thread 运维方法选择(基于开源组件)
    方案选择,需要支持4G和WIFI模组链接工具包优点缺点备注rtty1.功能全,兼容linux1.需要搭建一个服务器2.无成熟软件包支持嵌入式设备 webclient1.兼容性好,代码少。1.需要搭建一个服务器2.基于客户端做业务 webnet1.官方支持,兼容性好。1.需......
  • 【神兵利器】One-Fox工具箱V7魔改版发布
    更新说明在6.0版本的基础上重新规划了工具箱去除了一些工具新增些许新工具以及旧工具的新版本修复部分已知BUG优化代码逻辑,修复界面无法根据电脑分辨率进行自适应问题新增鼠标移动到工具按钮上显示文本浮框功能美化框架UI(本次为简约风格)等此工具为python语言编写......
  • 深度学习 - CNN
    第一部分:基础知识1.什么是卷积神经网络(CNN)定义和基本概念卷积神经网络(CNN)是一种专门用于处理具有网格结构数据(如图像)的深度学习模型。它们在图像识别和计算机视觉领域表现尤为突出。与传统的全连接神经网络不同,CNN利用局部连接和共享权重的方式,能够有效减少参数数量,提高......
  • yolov5-7.0更改resnet主干网络
    参考链接ClearML教程:https://blog.csdn.net/qq_40243750/article/details/126445671b站教学视频:https://www.bilibili.com/video/BV1Mx4y1A7jy/spm_id_from=333.788&vd_source=b52b79abfe565901e6969da2a1191407开始github地址:https://github.com/z1069614715/objec......
  • ISE软件iMPACT - BIT生成MCS并固化
     1,打开菜单栏,Xilinx  DesignToos->ISEDesignSuite14.7->ISEDesignTools->64bitsTolls->iMPACT。或者直接搜索IMPACT双击打开2,选择CreatPROMFile(PROMFileFor...),选择SPIFlash->ConfigSingleFPGA(因为我的芯片只有一个FPGA芯片)。->选择"->"符号->Storaged......
  • json-server 快速搭建REST API 服务器
    json-server快速搭建RESTAPI服务器★认识json-server官方文档参考 json-server是一个非常流行的开源工具,用于快速搭建一个完整的RESTAPI服务器。它使用JSON文件作为数据源,通过简单的配置即可模拟复杂的服务器功能,非常适合前端开发者在没有后端支持的情况下进行开发和......
  • 软件工程-第七章第七节 组织
    工程理论其实是包含组织学的。然而我在上面的那张图中,将组织与工程分离开来,并在二者之间画下了一道纵向的线,如图所示。 工程关心的是“需求”、“配置”和“文档”等这样一些要素,那么这样的工程还是停留在技术层面的:关注的还是工程的实现细节,而非目标。从角色的角度来看,这是项......
  • 鸿蒙HarmonyOS实战-窗口管理
    ......
  • 安卓APK安装包arm64-v8a、armeabi-v7a、x86、x86_64有何区别?如何选择?
    https://www.cnblogs.com/yang-yz/p/17276615.html 在GitHub网站下载Android安装包,Actions资源下的APK文件通常有以下版本供选择:例如上图是某Android客户端的安装包文件,有以下几个版本可以选择:mobile-release.apk(通用版本,体积最大)mobile-universal-release.apkmobile-ar......
  • python-找第一个只出现一次的字符
    [题目描述]给定一个只包含小写字母的字符串,请你找到第一个仅出现一次的字符。如果没有,输出no。输入:一个字符串,长度小于1100。输出:输出第一个仅出现一次的字符,若没有则输出no。样例输入1abcabd样例输出1c来源/分类(难度系数:一星) 完整代码如下:a=list(input())b=[......