01收货地址模型类和视图定义_哔哩哔哩_bilibili 本博客借鉴至大佬的视频学习笔记
地址信息的管理:增删改查的实现
# 序列化器配置
class AddrSerializer(serializers.ModelSerializer):
"""收货地址的模型序列化器"""
class Meta:
model = Addr
fields = '__all__'
# view 视图信息
class AddrView(GenericViewSet,
mixins.ListModelMixin,
mixins.CreateModelMixin,
mixins.DestroyModelMixin,
mixins.UpdateModelMixin):
"""收货地址管理视图"""
queryset = Addr.objects.all()
serializer_class = AddrSerializer
permission_classes = [IsAuthenticated,AddrPermissions]
# filterset_fields = ('user',)
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
# 通过请求过来的用户进行过滤
queryset = queryset.filter(user=request.user)
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
# url 配置
# 添加地址和获取地址列表的路由
path('address/', AddrView.as_view({'post':'create','get':'list'}), name='address'),
# 删除和修改地址
path('address/<int:pk>/', AddrView.as_view({'delete':'destroy','put':'update'}), name='address'),
# 注册过滤器
'django_filters'
# 配置过滤器
REST_FRAMEWORK = {
# 过滤器信息配置
'DEFAULT_FILTER_BACKENDS':['django_filters.rest_framework.DjangoFilterBackend',]
}
默认收货地址的设置
# 如上 AddrView视图中增加默认地址函数
def set_default_addr(self,request,*args,**kwargs):
"""设置默认收货地址"""
# 将获取的地址设置为默认
obj =self.get_object()
obj.is_default =True
obj.save()
# 将其他地址进行遍历为非默认
queryset = self.get_queryset().filter(user=request.user)
for item in queryset:
if item !=obj:
item.is_default =False
item.save()
return Response({'message':'设置成功'},status=status.HTTP_200_OK)
# url 文件配置
path('address/<int:pk>/default/', AddrView.as_view({'put': 'set_default_addr'}), name='address'),
云短信使用:网址云通信精选特惠
购买成功后进入控制台,搜索短信服务:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台
点击当前的SDK信息,安装依赖
找到控制台的快捷操作,创建access_key_id 和access_key_secret
根据上面提供的demo代码优化结果: 参考博客:Django+DRF发送短信验证码--阿里云_django对接阿里云短信-CSDN博客
# -*- coding: utf-8 -*-
import json
from alibabacloud_dysmsapi20170525.client import Client
from alibabacloud_tea_openapi.models import Config
from alibabacloud_dysmsapi20170525.models import SendSmsRequest
from alibabacloud_tea_util.models import RuntimeOptions
class Sample:
def create_client(self, access_key_id: str, access_key_secret: str):
# 1. 创建一个配置对象
"""
LTAI5tMLfxMgiu6gPycNcyTC
H8LokjVLN50rDUCBqMss2juKpSownF
"""
config = Config(
# 必填,您的 AccessKey ID,
access_key_id='xxx',
# 必填,您的 AccessKey Secret,
access_key_secret='xxx',
endpoint=f'dysmsapi.aliyuncs.com'
)
# 2. 创建一个客服端
client = Client(config)
# 3. 创建短信对象
send_sms_request = SendSmsRequest(
sign_name='阿里云短信测试',
template_code='SMS_154950909',
phone_numbers='XXX',
template_param='{"code":"1234"}'
)
# 4. 设置允许时间选项
runtime = RuntimeOptions()
# 5. 发送短信
client.send_sms_with_options(send_sms_request, runtime)
class Send_SMS():
# access_key_id和 access_key_secret 为你的账号值
access_key_id = 'access_key_id'
access_key_secret = 'access_key_secret'
endpoint = 'dysmsapi.aliyuncs.com'
sign_name = '阿里云短信测试'
template_code = 'SMS_154950909'
def __init__(self):
self.config = Config(
# 必填,您的 AccessKey ID,
access_key_id=self.access_key_id,
# 必填,您的 AccessKey Secret,
access_key_secret=self.access_key_secret,
endpoint=self.endpoint
)
def send(self, mobile: str, code: str):
"""
mobile: 手机号
code:验证码
"""
# 1. 创建一个客服端
client = Client(self.config)
send_sms_request = SendSmsRequest(
phone_numbers=mobile,
template_param=json.dumps({"code": code}),
sign_name=self.sign_name,
template_code=self.template_code,
)
# 2. 创建短信对象
# 3. 设置允许时间选项
runtime = RuntimeOptions()
# 4. 发送短信
client.send_sms_with_options(send_sms_request, runtime)
if __name__ == '__main__':
# mobile为你的手机号
# code 为你想要发到手机的验证码
Send_SMS().send(mobile='xxx', code='1234')
验证码发送短信接口实现
# view 视图配置
class SendSmsView(APIView):
"""发送短信验证码"""
def post(self,request):
mobile = request.data.get('mobile','')
pattern = '^(13\d|14[5|7]|15\d|166|17[3|6|7]|18\d)\d{8}$'
if not re.match(pattern,mobile):
return Response({'error': '无效的手机号码'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)
code = self.get_random_code()
result = Send_SMS().send(mobile,code)
print(result)
if result['code'] == 'OK':
# 短信入库
obj = VerifyCode.objects.create(mobile=mobile,code=code)
result['codeID']=obj.id
return Response(result,status=status.HTTP_200_OK)
else:
return Response({'error':'发送短信失败'},status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def get_random_code(self):
"""随机生成一个六位验证码"""
code = ''
for i in range(6):
n= random.choice(range(9))
code+=str(n)
return code
# url 文件配置
path('sendsms/', SendSmsView.as_view(), name='sms'),
运行结果:
发送短信验证码限流配置
# view
from rest_framework.throttling import UserRateThrottle,AnonRateThrottle
# Create your views here.
class SendSmsView(APIView):
"""发送短信验证码"""
# 设置限流,每分钟发送短信一次
throttle_classes = (AnonRateThrottle,)
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
# 时间周期 second/minute/hour/day
'anon': '1/minute', # 未认证的用户 10/day sms
'user': '1/minute' # 认证的用户 100/day
},
}
运行结果:
绑定手机接口实现 - 要求: 权限认证、防止越权、验证码三分钟(通过后三分钟从后天清除)
class UserView(GenericViewSet,mixins.RetrieveModelMixin):
"""用户相关的操作视图集"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated,UserPermissions] # 设置权限认证
def bind_mobile(self,request,*args,**kwargs):
code =request.data.get('code') # 验证码
codeID = request.data.get('codeID') # 验证码id
mobile =request.data.get('mobile')
if not code:
return Response({'error':"验证码不可为空"},status=status.HTTP_400_BAD_REQUEST)
if not codeID:
return Response({'error':"验证码ID不可为空"},status=status.HTTP_400_BAD_REQUEST)
if not mobile:
return Response({'error':"手机号不可为空"},status=status.HTTP_400_BAD_REQUEST)
if VerifyCode.objects.filter(id=codeID,code=code,mobile=mobile).exists():
# 检验验证码是否过期,过期时间3分钟
c_obj = VerifyCode.objects.get(id=codeID,code=code,mobile=mobile)
# 获取验证码的创建的时间
ct = c_obj.create_time.timestamp()
# 当前时间的时间戳
et = time.time()
# 删除验证码,避免同一个验证码重复请求
c_obj.delete()
if ct + 180 < et:
return Response({'error': "验证码已过期"}, status=status.HTTP_400_BAD_REQUEST)
# else:
# return Response({'error': "无效的验证码,请重新获取验证码"}, status=status.HTTP_400_BAD_REQUEST)
if User.objects.filter(mobile=mobile).exists():
return Response({'error':"该手机号已被其他用户绑定"},status=status.HTTP_400_BAD_REQUEST)
# 绑定手机号
user = request.user
user.mobile = mobile
user.save()
return Response({'error':"绑定成功"},status=status.HTTP_200_OK)
# 绑定手机号
path('<int:pk>/mobile/bind/', UserView.as_view({'put': 'bind_mobile'}), name='avatar_post'),
解绑手机号接口实现
@staticmethod
def verify_code(code,codeID,mobile):
if not code:
return {'error': "验证码不可为空"}
if not codeID:
return {'error': "验证码ID不可为空"}
if not mobile:
return {'error': "手机号不可为空"}
if VerifyCode.objects.filter(id=codeID, code=code, mobile=mobile).exists():
# 检验验证码是否过期,过期时间3分钟
c_obj = VerifyCode.objects.get(id=codeID, code=code, mobile=mobile)
# 获取验证码的创建的时间
ct = c_obj.create_time.timestamp()
# 当前时间的时间戳
et = time.time()
# 删除验证码,避免同一个验证码重复请求
c_obj.delete()
if ct + 180 < et:
return {'error': "验证码已过期"}
else:
return {'error': "无效的验证码,请重新获取验证码"}
def ubind_mobile(self,request,*args,**kwargs):
code = request.data.get('code') # 验证码
codeID = request.data.get('codeID') # 验证码id
mobile = request.data.get('mobile')
result = self.verify_code(code,codeID,mobile)
if result:
return Response(result,status=status.HTTP_400_BAD_REQUEST)
# 解绑手机号,验证用户已绑定手机号
user = request.user
if user.mobile ==mobile:
user.mobile = ''
user.save()
return Response({'error': "解帮成功"}, status=status.HTTP_200_OK)
else:
return Response({"error":"当前用户未绑定该号码"},status=status.HTTP_400_BAD_REQUEST)
# url
# 解绑手机号
path('<int:pk>/mobile/ubind/', UserView.as_view({'put': 'ubind_mobile'}), name='ubind_mobile'), # 检验token
修改昵称接口的实现 - 要求: 权限校验、防止越权
class UserView(GenericViewSet,mixins.RetrieveModelMixin):
"""用户相关的操作视图集"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAuthenticated,UserPermissions] # 设置权限认证
def update_name(self,request,*args,**kwargs):
last_name = request.data.get('last_name')
if not last_name:
return Response({'error':"参数last_name 不可为空"},status=status.HTTP_400_BAD_REQUEST)
user = self.get_object()
user.last_name = last_name
user.save()
return Response({'message': "修改成功"}, status=status.HTTP_200_OK)
# url
# 修改用户昵称
path('<int:pk>/name/', UserView.as_view({'put': 'update_name'}), name='update_name'), # 检验token
修改用户邮箱接口
# view
def update_email(self,request,*args,**kwargs):
email = request.data.get('email')
if not email:
return Response({'error':"邮箱参数不可为空"},status=status.HTTP_400_BAD_REQUEST)
pattern = '^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$'
if not re.match(pattern,email):
return Response({'error':"邮箱格式错误"},status=status.HTTP_400_BAD_REQUEST)
user = self.get_object()
# 检验是否新旧一致
if user.email ==email:
return Response({'error':"不能和旧邮箱保持一致"},status=status.HTTP_200_OK)
if User.objects.filter(email=email).exists():
return Response({'error':"邮箱已被其他用户绑定"},status=status.HTTP_400_BAD_REQUEST)
user.email = email
user.save()
return Response({'message': "修改成功"}, status=status.HTTP_200_OK)
# url
# 修改用户邮箱
path('<int:pk>/email/', UserView.as_view({'put': 'update_email'}), name='update_email'),
用户密码接口修改与重置接口实现
要求:权限认证、防止越权、检验验证码、验证过期3分钟检验并通过后删除
# view
def update_password(self,request,*args,**kwargs):
password = request.data.get('password')
password_confirmation = request.data.get('password_confirmation')
code = request.data.get('code') # 验证码
codeID = request.data.get('codeID') # 验证码id
mobile = request.data.get('mobile')
result = self.verify_code(code,codeID,mobile)
if result:
return Response(result,status=status.HTTP_400_BAD_REQUEST)
email = request.data.get('email')
if not email:
return Response({'error':"邮箱参数不可为空"},status=status.HTTP_400_BAD_REQUEST)
user = self.get_object()
# 检验是否新旧一致
if user.mobile !=mobile:
return Response({'error':"验证码有误"},status=status.HTTP_400_BAD_REQUEST)
if not password:
return Response({'error':"密码参数不可为空"},status=status.HTTP_400_BAD_REQUEST)
if password !=password_confirmation:
return Response({'error':"两次输入的密码不一致"},status=status.HTTP_400_BAD_REQUEST)
# 修改用户密码 set_password 密码在数据中是加密的
user.set_password(password)
user.save()
return Response({'message': "修改成功"}, status=status.HTTP_200_OK)
# url
# 修改用户密码
path('<int:pk>/password/', UserView.as_view({'put': 'update_password'}), name='update_password'),