一、用户基本信息

1.1 用户基本信息逻辑分析

1. 用户基本信息逻辑分析

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_django

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_python_02

 

以下是要实现的后端逻辑

  1. 用户模型补充email_active字段
  2. 查询用户基本信息
  3. 添加邮箱
  4. 发送邮箱验证邮件
  5. 验证邮箱

1.2 查询用户基本信息

1. 接口设计和定义

1.请求方式

选项

方案

请求方法

GET

请求地址

/info/

2.请求参数

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

2. 用户模型补充email_active字段

  • 由于在渲染用户基本信息时,需要渲染用户邮箱验证的状态,所以需要给用户模型补充email_active字段
  • 补充完字段后,需要进行迁移。

python manage.py makemigrations python manage.py migrate

class User(AbstractUser):
    """自定义用户模型类"""
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    email_active = models.BooleanField(default=False, verbose_name='邮箱验证状态')

    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

3. 查询用户基本信息

from utils.views import LoginRequiredJSONMixin
class UserInfoView(LoginRequiredJSONMixin, View):
    """用户中心"""

    def get(self, request):
        """提供个人信息界面"""

        # 获取界面需要的数据,进行拼接
        info_data = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active
        }

        # 返回响应
        return JsonResponse({'code':0,
                                  'errmsg':'ok',
                                  'info_data':info_data})

二、添加和验证邮箱 

2.1 添加邮箱后端逻辑

1. 添加邮箱接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/emails/

2.请求参数

参数名

类型

是否必传

说明

email

string


邮箱

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

2. 添加邮箱后端逻辑实现

import json
import re
from django import http
class EmailView(View):
    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 校验参数
        if not email:
            return http.JsonResponse({'code': 400,
                                      'errmsg': '缺少email参数'})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.JsonResponse({'code': 400,
                                      'errmsg': '参数email有误'})


            # 赋值email字段
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400, 'errmsg': '添加邮箱失败'})

        # 响应添加邮箱结果
        return http.JsonResponse({'code':0, 'errmsg': '添加邮箱成功'})

2.2 Django发送邮件的配置

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_开发语言_03

 

1. Django发送邮件流程分析

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_django_04

send_mall()方法介绍

  • 位置:
  • django.core.mail模块提供了send_mail()来发送邮件。
  • 方法参数:
  • send_mail(subject, message, from_email, recipient_list, html_message=None)
subject 邮件标题
message 普通邮件正文,普通字符串
from_email 发件人
recipient_list 收件人列表
html_message 多媒体邮件正文,可以是html字符串

2. 准备发邮件服务器

1.点击进入《设置》界面

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_开发语言_05

 

 

2.点击进入《客户端授权密码》界面

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_邮箱验证_06

 

 

3.开启《授权码》,并完成验证短信

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_python_07

 

 

4.填写《授权码》

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_数据_08

 

 

5.完成《授权码》设置

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_django_09

 

 

6.配置邮件服务器

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 25
#发送邮件的邮箱
EMAIL_HOST_USER = 'qi_rui_hua@163.com'
#在邮箱中设置的客户端授权密码
EMAIL_HOST_PASSWORD = '123456abc'
#收件人看到的发件人
EMAIL_FROM = '美多商城<qi_rui_hua@163.com>'

2.3 发送邮箱验证邮件

重要提示:

  • 发送邮箱验证邮件是耗时的操作,不能阻塞美多商城的响应,所以需要异步发送邮件
  • 我们继续使用Celery实现异步任务。

1. 定义和调用发送邮件异步任务

1.定义发送邮件任务

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_django_10

 

 

import logging
from django.conf import settings
from django.core.mail import send_mail
from celery_tasks.main import celery_app 

logger = logging.getLogger('django')

@celery_app.task( name='send_verify_email')
def send_verify_email(to_email, verify_url):
    """
    发送验证邮箱邮件
    :param to_email: 收件人邮箱
    :param verify_url: 验证链接
    :return: None
    """
    subject = "美多商城邮箱验证"
    html_message = '<p>尊敬的用户您好!</p>' \
                   '<p>感谢您使用美多商城。</p>' \
                   '<p>您的邮箱为:%s 。请点击此链接激活您的邮箱:</p>' \
                   '<p><a href="%s">%s<a></p>' % (to_email, verify_url, verify_url)
    try:
        send_mail(subject, "", settings.EMAIL_FROM, [to_email], html_message=html_message)
    except Exception as e:
        logger.error(e)

2.注册发邮件的任务:main.py

  • 在发送邮件的异步任务中,我们用到了Django的配置文件。
  • 所以我们需要修改celery的启动文件main.py。
  • 在其中指明celery可以读取的Django配置文件。
  • 最后记得注册新添加的email的任务
# celery启动文件
from celery import Celery


# 为celery使用django配置文件进行设置
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "meiduo_mall.settings")

# 创建celery实例
celery_app = Celery('celery_tasks')

# 加载celery配置
celery_app.config_from_object('celery_tasks.config')

# 自动注册celery任务
celery_app.autodiscover_tasks(['celery_tasks.sms', 'celery_tasks.email'])

3.调用发送邮件异步任务

# 赋值email字段
try:
    request.user.email = email
    request.user.save()
except Exception as e:
    logger.error(e)
    return http.JsonResponse({'code': 0, 'errmsg': '添加邮箱失败'})

# 异步发送验证邮件
from celery_tasks.email.tasks import send_verify_email
verify_url = '邮件验证链接'
send_verify_email.delay(email, verify_url)

# 响应添加邮箱结果
return http.JsonResponse({'code': 0, 'errmsg': '添加邮箱成功'})

4.启动Celery

$ celery -A celery_tasks.main worker -l info

2. 生成邮箱验证链接

1.定义生成邮箱验证链接方法

在users.utils.py中添加生成认证的url方法

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer
from django.conf import settings

def generate_verify_email_url(user):
    """
    生成邮箱验证链接
    :param user: 当前登录用户
    :return: verify_url
    """
    serializer = Serializer(settings.SECRET_KEY, expires_in=3600)
    data = {'user_id': user.id, 'email': user.email}
    token = serializer.dumps(data).decode()
    verify_url = settings.EMAIL_VERIFY_URL + '?token=' + token
    return verify_url

2.配置相关参数

# 邮箱验证链接
EMAIL_VERIFY_URL = 'http://www.meiduo.site:8080/success_verify_email.html'

3.使用邮箱验证链接

verify_url = generate_verify_email_url(request.user)
send_verify_email.delay(email, verify_url)

 2.4 验证邮箱后端逻辑

1. 验证邮箱接口设计和定义

1.请求方式

选项

方案

请求方法

GET

请求地址

/emails/verification/

2.请求参数:查询参数

参数名

类型

是否必传

说明

token

string


邮箱激活链接

3.响应结果:HTML

字段

说明

邮箱验证失败

响应错误提示

邮箱验证成功

重定向到用户中心

2. 验证链接提取用户信息

在users.utils.py中添加生成认证的url方法

from itsdangerous import TimedJSONWebSignatureSerializer as Serializer,BadData
from django.conf import settings
from apps.users.models import User

def check_verify_email_token(token):
    """
    验证token并提取user
    :param token: 用户信息签名后的结果
    :return: user, None
    """
    serializer = Serializer(settings.SECRET_KEY, expires_in=3600)
    try:
        data = serializer.loads(token)
    except BadData:
        return None
    else:
        user_id = data.get('user_id')
        email = data.get('email')
        try:
            user = User.objects.get(id=user_id, email=email)
        except User.DoesNotExist:
            return None
        else:
            return user

3. 验证邮箱后端逻辑实现

验证邮箱的核心:就是将用户的email_active字段设置为True

class VerifyEmailView(View):
    def put(self, request):
        # - 1.接收 token
        token = request.GET.get('token')

        if not token:
            return JsonResponse({'code': 400, 'errmsg': 'token缺少'})

        # - 2.解密
        data_dict = check_verify_email_token(token)

        # - 4.去数据库对比 user_id,email
        try:
            user = User.objects.get(pk=data_dict.get('user_id'), email=data_dict.get('email'))
        except Exception as e:
            print(e)
            return JsonResponse({'code': 400, 'errmsg': '参数有误!'})

        # - 5.修改激活状态
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            return JsonResponse({'code': 0, 'errmsg': '激活失败!'})

三、收获地址

省市区三级联动

1. 准备省市区模型和数据

创建areas子应用

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_django_11

 

 

from django.db import models

class Area(models.Model):
    """省市区"""
    name = models.CharField(max_length=20, verbose_name='名称')
    parent = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='subs', null=True, blank=True, verbose_name='上级行政区划')

    class Meta:
        db_table = 'tb_areas'
        verbose_name = '省市区'
        verbose_name_plural = '省市区'

    def __str__(self):
        return self.name

模型说明:

  • 安装子应用之后,需要迁移
python manage.py makemigrations
  python manage.py migrate
  • 自关联字段的外键指向自身,所以models.ForeignKey('self')
  • 使用related_name指明父级查询子级数据的语法
  • 默认Area模型类对象.area_set语法
  • related_name='subs'
  • 现在Area模型类对象.subs语法

导入省市区数据

mysql -h数据库ip地址 -u数据库用户名 -p数据库密码 数据库 < areas.sql
mysql -h127.0.0.1 -uroot -pmysql meiduo_mall < areas.sql

总路由

# areas
path('', include('apps.areas.urls')),

子路由

from django.conf.urls import url
from . import views
urlpatterns = [


]

3. 查询省数据

1.请求方式

选项

方案

请求方法

GET

请求地址

/areas/

2.请求参数:查询参数

3.响应结果:JSON

  • 省份数据
{
  "code":"0",
  "errmsg":"OK",
  "province_list":[
      {
          "id":110000,
          "name":"北京市"
      },
      {
          "id":120000,
          "name":"天津市"
      },
      {
          "id":130000,
          "name":"河北省"
      },
      ......
  ]
}
  • 市或区数据
{
  "code":"0",
  "errmsg":"OK",
  "sub_data":{
      "id":130000,
      "name":"河北省",
      "subs":[
          {
              "id":130100,
              "name":"石家庄市"
          },
          ......
      ]
  }
}

4.查询省数据后端逻辑实现

from django.http import JsonResponse
from django.views import View
from apps.areas.models import Area
import logging

logger = logging.getLogger('django')

class AreasView(View):
    """省市区数据"""

    def get(self, request):
        """提供省市区数据"""

        # 提供省份数据
        try:
            # 查询省份数据
            province_model_list = Area.objects.filter(parent__isnull=True)

            # 序列化省级数据
            province_list = []
            for province_model in province_model_list:
                province_list.append({'id': province_model.id, 'name': province_model.name})
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '省份数据错误'})

        # 响应省份数据
        return JsonResponse({'code': 0, 'errmsg': 'OK', 'province_list': province_list})

4. 查询市区县数据

1.请求方式

选项

方案

请求方法

GET

请求地址

/areas/(?P<pk>[1-9]\d+)/

2.请求参数:查询参数

3.响应结果:JSON

  • 市或区数据
{
  "code":"0",
  "errmsg":"OK",
  "sub_data":{
      "id":130000,
      "name":"河北省",
      "subs":[
          {
              "id":130100,
              "name":"石家庄市"
          },
          ......
      ]
  }
}

4.查询市区数据后端逻辑实现

class SubAreasView(View):
    """省市区数据"""

    def get(self, request,pk):
        """提供省市区数据"""

        # 提供市或区数据
        try:
            parent_model = Area.objects.get(id=pk)  # 查询市或区的父级
            sub_model_list = parent_model.subs.all()

            # 序列化市或区数据
            sub_list = []
            for sub_model in sub_model_list:
                sub_list.append({'id': sub_model.id, 'name': sub_model.name})

            sub_data = {
                'id': parent_model.id,  # 父级pk
                'name': parent_model.name,  # 父级name
                'subs': sub_list  # 父级的子集
            }
        except Exception as e:
            logger.error(e)
            return JsonResponse({'code': 400, 'errmsg': '城市或区数据错误'})

        # 响应市或区数据
        return JsonResponse({'code': 0, 'errmsg': 'OK', 'sub_data': sub_data})

5. 缓存省市区数据

提示:

  • 省市区数据是我们动态查询的结果。
  • 但是省市区数据不是频繁变化的数据,所以没有必要每次都重新查询。
  • 所以我们可以选择对省市区数据进行缓存处理。

1.缓存工具

  • from django.core.cache import cache
  • 存储缓存数据:cache.set('key', 内容, 有效期)
  • 读取缓存数据:cache.get('key')
  • 删除缓存数据:cache.delete('key')
  • 注意:存储进去和读取出来的数据类型相同,所以读取出来后可以直接使用。

2.缓存逻辑

 

美多商城项目之用户中心:基本信息、邮箱验证、收货地址_邮箱验证_12

 

3.缓存逻辑实现

  • 省份缓存数据
  • cache.set('province_list', province_list, 3600)
  • 市或区缓存数据
  • cache.set('sub_area_' + area_id, sub_data, 3600)

 3.2 新增地址前后端逻辑

1. 定义用户地址模型类

1.用户地址模型类

from utils.models import BaseModel

class Address(BaseModel):
    """用户地址"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='addresses', verbose_name='用户')
    title = models.CharField(max_length=20, verbose_name='地址名称')
    receiver = models.CharField(max_length=20, verbose_name='收货人')
    province = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='province_addresses', verbose_name='省')
    city = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='city_addresses', verbose_name='市')
    district = models.ForeignKey('areas.Area', on_delete=models.PROTECT, related_name='district_addresses', verbose_name='区')
    place = models.CharField(max_length=50, verbose_name='地址')
    mobile = models.CharField(max_length=11, verbose_name='手机')
    tel = models.CharField(max_length=20, null=True, blank=True, default='', verbose_name='固定电话')
    email = models.CharField(max_length=30, null=True, blank=True, default='', verbose_name='电子邮箱')
    is_deleted = models.BooleanField(default=False, verbose_name='逻辑删除')

    class Meta:
        db_table = 'tb_address'
        verbose_name = '用户地址'
        verbose_name_plural = verbose_name
        ordering = ['-update_time']

2.Address模型类说明

  • Address模型类中的外键指向areas/models里面的Area 。指明外键时,可以使用应用名.模型类名来定义。
  • ordering表示在进行Address查询时,默认使用的排序方式。
  • ordering = ['-update_time']: 根据更新的时间倒叙。

3.补充用户模型默认地址字段

class User(AbstractUser):
    """自定义用户模型类"""
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
    email_active = models.BooleanField(default=False, verbose_name='邮箱验证状态')
    default_address = models.ForeignKey('Address', related_name='users', null=True, blank=True, on_delete=models.SET_NULL, verbose_name='默认地址')

    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

需要进行迁移。

python manage.py makemigrations python manage.py migrate

2. 新增地址接口设计和定义

1.请求方式

选项

方案

请求方法

POST

请求地址

/addresses/create/

2.请求参数:JSON

参数名

类型

是否必传

说明

receiver

string


收货人

province_id

string


省份ID

city_id

string


城市ID

district_id

string


区县ID

place

string


收货地址

mobile

string


手机号

tel

string


固定电话

email

string


邮箱

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

id

地址ID

receiver

收货人

province

省份名称

city

城市名称

district

区县名称

place

收货地址

mobile

手机号

tel

固定电话

email

邮箱

3. 新增地址后端逻辑实现

提示:

  • 用户地址数量有上限,最多20个,超过地址数量上限就返回错误信息
class CreateAddressView(LoginRequiredJSONMixin, View):
    """新增地址"""

    def post(self, request):
        """实现新增地址逻辑"""
        # 判断是否超过地址上限:最多20个
        # Address.objects.filter(user=request.user).count()
        count = request.user.addresses.count()
        if count >= constants.USER_ADDRESS_COUNTS_LIMIT:
            return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '超过地址数量上限'})

        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.HttpResponseBadRequest('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseBadRequest('参数mobile有误')
        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.HttpResponseBadRequest('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseBadRequest('参数email有误')

        # 保存地址信息
        try:
            address = Address.objects.create(
                user=request.user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel,
                email = email
            )

            # 设置默认地址
            if not request.user.default_address:
                request.user.default_address = address
                request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '新增地址失败'})

        # 新增地址成功,将新增的地址响应给前端实现局部刷新
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应保存结果
        return JsonResponse({'code': 0, 'errmsg': '新增地址成功', 'address':address_dict})

3.3 展示地址逻辑

1. 展示地址接口设计和定义

1.请求方式

选项

方案

请求方法

GET

请求地址

/addresses/

2.请求参数

2. 展示地址后端逻辑实现

class AddressView(View):
    """用户收货地址"""

    def get(self, request):
        """提供地址管理界面
        """
        # 获取所有的地址:
        addresses = Address.objects.filter(user=request.user,
                                           is_deleted=False)

        # 创建空的列表
        address_dict_list = []
        # 遍历
        for address in addresses:
            address_dict = {
                "id": address.id,
                "title": address.title,
                "receiver": address.receiver,
                "province": address.province.name,
                "city": address.city.name,
                "district": address.district.name,
                "place": address.place,
                "mobile": address.mobile,
                "tel": address.tel,
                "email": address.email
            }

            # 将默认地址移动到最前面
            default_address = request.user.default_address
            if default_address.id == address.id:
                # 查询集 addresses 没有 insert 方法
                address_dict_list.insert(0, address_dict)
            else:
                address_dict_list.append(address_dict)

        default_id = request.user.default_address_id

        return JsonResponse({'code': 0,
                             'errmsg': 'ok',
                             'addresses': address_dict_list,
                             'default_address_id': default_id})

3.4 修改地址前后端逻辑

1. 修改地址接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/addresses/(?P<address_id>\d+)/

2.请求参数:路径参数 和 JSON

参数名

类型

是否必传

说明

address_id

string


要修改的地址ID(路径参数)

receiver

string


收货人

province_id

string


省份ID

city_id

string


城市ID

district_id

string


区县ID

place

string


收货地址

mobile

string


手机号

tel

string


固定电话

email

string


邮箱

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

id

地址ID

receiver

收货人

province

省份名称

city

城市名称

district

区县名称

place

收货地址

mobile

手机号

tel

固定电话

email

邮箱

2. 修改地址后端逻辑实现

提示

  • 删除地址后端逻辑和新增地址后端逻辑非常的相似。
  • 都是更新用户地址模型类,需要保存用户地址信息。
class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):
    """修改和删除地址"""

    def put(self, request, address_id):
        """修改地址"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        receiver = json_dict.get('receiver')
        province_id = json_dict.get('province_id')
        city_id = json_dict.get('city_id')
        district_id = json_dict.get('district_id')
        place = json_dict.get('place')
        mobile = json_dict.get('mobile')
        tel = json_dict.get('tel')
        email = json_dict.get('email')

        # 校验参数
        if not all([receiver, province_id, city_id, district_id, place, mobile]):
            return http.JsonResponse({'code': 400, 
                                      'errmsg': '缺少必传参数'})


        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': 400, 
                                      'errmsg': '参数mobile有误'})

        if tel:
            if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):
                return http.JsonResponse({'code': 400, 
                                          'errmsg': '参数tel有误'})
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.JsonResponse({'code': 400, 
                                          'errmsg': '参数email有误'})

        # 判断地址是否存在,并更新地址信息
        try:
            Address.objects.filter(id=address_id).update(
                user = request.user,
                title = receiver,
                receiver = receiver,
                province_id = province_id,
                city_id = city_id,
                district_id = district_id,
                place = place,
                mobile = mobile,
                tel = tel,
                email = email
            )
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400, 'errmsg': '更新地址失败'})

        # 构造响应数据
        address = Address.objects.get(id=address_id)
        address_dict = {
            "id": address.id,
            "title": address.title,
            "receiver": address.receiver,
            "province": address.province.name,
            "city": address.city.name,
            "district": address.district.name,
            "place": address.place,
            "mobile": address.mobile,
            "tel": address.tel,
            "email": address.email
        }

        # 响应更新地址结果
        return JsonResponse({'code': 0, 'errmsg': '更新地址成功', 'address': address_dict})

3.5 删除地址前逻辑

1. 删除地址接口设计和定义

1.请求方式

选项

方案

请求方法

DELETE

请求地址

/addresses/(?P<address_id>\d+)/

2.请求参数:路径参数

参数名

类型

是否必传

说明

address_id

string


要修改的地址ID(路径参数)

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

2. 删除地址后端逻辑实现

提示:

  • 删除地址不是物理删除,是逻辑删除。
class UpdateDestroyAddressView(LoginRequiredJSONMixin, View):
    """修改和删除地址"""

    def put(self, request, address_id):
        """修改地址"""
        ......

    def delete(self, request, address_id):
        """删除地址"""
        try:
            # 查询要删除的地址
            address = Address.objects.get(id=address_id)

            # 将地址逻辑删除设置为True
            address.is_deleted = True
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400, 'errmsg': '删除地址失败'})

        # 响应删除地址结果
        return http.JsonResponse({'code': 0, 'errmsg': '删除地址成功'})

  3.6 设置默认地址

1. 设置默认地址接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/addresses/(?P<address_id>\d+)/default/

2.请求参数:路径参数

参数名

类型

是否必传

说明

address_id

string


要修改的地址ID(路径参数)

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

2. 设置默认地址后端逻辑实现

class DefaultAddressView(LoginRequiredJSONMixin, View):
    """设置默认地址"""

    def put(self, request, address_id):
        """设置默认地址"""
        try:
            # 接收参数,查询地址
            address = Address.objects.get(id=address_id)

            # 设置地址为默认地址
            request.user.default_address = address
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400, 'errmsg': '设置默认地址失败'})

        # 响应设置默认地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置默认地址成功'})

3.7 修改地址标题

1. 修改地址标题接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/addresses/(?P<address_id>\d+)/title/

2.请求参数:路径参数

参数名

类型

是否必传

说明

address_id

string


要修改的地址ID(路径参数)

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

2. 修改地址标题后端逻辑实现

class UpdateTitleAddressView(LoginRequiredJSONMixin, View):
    """设置地址标题"""

    def put(self, request, address_id):
        """设置地址标题"""
        # 接收参数:地址标题
        json_dict = json.loads(request.body.decode())
        title = json_dict.get('title')

        try:
            # 查询地址
            address = Address.objects.get(id=address_id)

            # 设置新的地址标题
            address.title = title
            address.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': 400, 'errmsg': '设置地址标题失败'})

        # 4.响应删除地址结果
        return JsonResponse({'code': 0, 'errmsg': '设置地址标题成功'})

四、修改密码

修改密码接口设计和定义

1.请求方式

选项

方案

请求方法

PUT

请求地址

/password/

2.请求参数:JSON

参数名

类型

是否必传

说明

old_password

string


老密码

new_password

string


新密码

new_password2

string


确认的新密码

3.响应结果:JSON

字段

说明

code

状态码

errmsg

错误信息

1. 修改密码后端逻辑

提示:

  • 修改密码前需要校验原始密码是否正确,以校验修改密码的用户身份。
  • 如果原始密码正确,再将新的密码赋值给用户。
  • 我们在 users.views.py 文件中添加如下代码:
class ChangePasswordView(LoginRequiredMixin, View):
    """修改密码"""

  def put(self, request):
        """实现修改密码逻辑"""
        # 接收参数
        dict = json.loads(request.body.decode())
        old_password = dict.get('old_password')
        new_password = dict.get('new_password')
        new_password2 = dict.get('new_password2')

        # 校验参数
        if not all([old_password, new_password, new_password2]):
           return http.JsonResponse({'code':400,
                                     'errmsg':'缺少必传参数'})


        result = request.user.check_password(old_password)
        if not result:
            return http.JsonResponse({'code':400,
                                      'errmsg':'原始密码不正确'})

        if not re.match(r'^[0-9A-Za-z]{8,20}$', new_password):
            return http.JsonResponse({'code':400,
                                      'errmsg':'密码最少8位,最长20位'})

        if new_password != new_password2:
            return http.JsonResponse({'code':400,
                                      'errmsg':'两次输入密码不一致'})

        # 修改密码
        try:
            request.user.set_password(new_password)
            request.user.save()
        except Exception as e:

            return http.JsonResponse({'code':400,
                                      'errmsg':'修改密码失败'})

        # 清理状态保持信息
        logout(request)

        response = http.JsonResponse({'code':0,
                                      'errmsg':'ok'})

        response.delete_cookie('username')

        # # 响应密码修改结果:重定向到登录界面
        return response