美多商城之用户中心(收货地址3)

三、收货地址

3.4 修改地址前后端逻辑

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

1.请求方式

选项 方案
请求方法 PUT
请求地址 /addresses/(?P<address_id>\d+)/
    #  修改和删除地址
    url(r'^addresses/(?P<address_id>\d+)/$', views.UpdateDestroyAddressView.as_view()),

美多商城之用户中心(收货地址3)

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(LoginRequiredMixin, 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.HttpResponseForbidden('缺少必传参数')
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.HttpResponseForbidden('参数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.HttpResponseForbidden('参数tel有误')
        if email:
            if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
                return http.HttpResponseForbidden('参数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': RETCODE.DBERR, '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 http.JsonResponse({'code': RETCODE.OK, 'errmsg': '更新地址成功', 'address': address_dict})

3. 修改地址前端逻辑实现

1.添加修改地址的标记

  • 新增地址和修改地址的交互不同。
  • 为了区分用户是新增地址还是修改地址,我们可以选择添加一个变量,作为标记。
  • 为了方便得到正在修改的地址信息,我们可以选择展示地址时对应的序号作为标记。
data: {
    editing_address_index: '', 
},

美多商城之用户中心(收货地址3)

2.实现编辑按钮对应的事件

show_edit_site(index){
    this.is_show_edit = true;
    this.clear_all_errors();
    this.editing_address_index = index.toString();
},

美多商城之用户中心(收货地址3)

<div class="down_btn">
    <a v-if="address.id!=default_address_id">设为默认</a>
    <a href="javascript:;" class="edit_icon">编辑</a>
</div>

美多商城之用户中心(收货地址3)

3.展示要重新编辑的数据

show_edit_site(index){
    this.is_show_edit = true;
    this.clear_all_errors();
    this.editing_address_index = index.toString();
    // 只获取要编辑的数据
    this.form_address = JSON.parse(JSON.stringify(this.addresses[index]));
},

4.发送修改地址请求

  • 重要提示:
    • 0 == '' 返回true
    • 0 === '' 返回false
    • 为了避免第0个索引出错,我们选择this.editing_address_index === ''的方式进行判断
if (this.editing_address_index === '') {
    // 新增地址
    ......
} else {
    // 修改地址
    let url = '/addresses/' + this.addresses[this.editing_address_index].id + '/';
    axios.put(url, this.form_address, {
        headers: {
            'X-CSRFToken':getCookie('csrftoken')
        },
        responseType: 'json'
    })
        .then(response => {
            if (response.data.code == '0') {
                this.addresses[this.editing_address_index] = response.data.address;
                this.is_show_edit = false;
            } else if (response.data.code == '4101') {
                location.href = '/login/?next=/addresses/';
            } else {
                alert(response.data.errmsg);
            }
        })
        .catch(error => {
            alert(error.response);
        })
}

3.5 删除地址前后端逻辑

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

1.请求方式

选项 方案
请求方法 DELETE
请求地址 /addresses/(?P<address_id>\d+)/

2.请求参数:路径参数

参数名 类型 是否必传 说明
address_id string 要修改的地址ID(路径参数)

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息

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

提示:

  • 删除地址不是物理删除,是逻辑删除。
class UpdateDestroyAddressView(LoginRequiredMixin, 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': RETCODE.DBERR, 'errmsg': '删除地址失败'})

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

3. 删除地址前端逻辑实现

delete_address(index){
    let url = '/addresses/' + this.addresses[index].id + '/';
    axios.delete(url, {
        headers: {
            'X-CSRFToken':getCookie('csrftoken')
        },
        responseType: 'json'
    })
        .then(response => {
            if (response.data.code == '0') {
                // 删除对应的标签
                this.addresses.splice(index, 1);
            } else if (response.data.code == '4101') {
                location.href = '/login/?next=/addresses/';
            }else {
                alert(response.data.errmsg);
            }
        })
        .catch(error => {
            console.log(error.response);
        })
},
<div class="site_title">
    <h3>[[ address.title ]]</h3>
    <a href="javascript:;" class="edit_icon"></a>
    <em v-if="address.id===default_address_id">默认地址</em>
    <span @click="delete_address(index)" class="del_site">×</span>
</div>

3.6 设置默认地址

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

1.请求方式

选项 方案
请求方法 PUT
请求地址 /addresses/(?P<address_id>\d+)/default/
#  设置默认地址
    url(r'^addresses/(?P<address_id>\d+)/default/$', views.DefaultAddressView.as_view()),

2.请求参数:路径参数

参数名 类型 是否必传 说明
address_id string 要修改的地址ID(路径参数)

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息

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

class DefaultAddressView(LoginRequiredMixin, 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': RETCODE.DBERR, 'errmsg': '设置默认地址失败'})

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

3. 设置默认地址前端逻辑实现

set_default(index){
    let url = '/addresses/' + this.addresses[index].id + '/default/';
    axios.put(url, {}, {
        headers: {
            'X-CSRFToken':getCookie('csrftoken')
        },
        responseType: 'json'
    })
        .then(response => {
            if (response.data.code == '0') {
                // 设置默认地址标签
                this.default_address_id = this.addresses[index].id;
            } else if (response.data.code == '4101') {
                location.href = '/login/?next=/addresses/';
            } else {
                alert(response.data.errmsg);
            }
        })
        .catch(error => {
            console.log(error.response);
        })
},
<div class="down_btn">
    <a v-if="address.id!=default_address_id" @click="set_default(index)">设为默认</a>
    <a @click="show_edit_site(index)" class="edit_icon">编辑</a>
</div>

3.7 修改地址标题

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

1.请求方式

选项 方案
请求方法 PUT
请求地址 /addresses/(?P<address_id>\d+)/title/
#  设置地址标题
    url(r'^addresses/(?P<address_id>\d+)/title/$', views.UpdateTitleAddressView.as_view()),

2.请求参数:路径参数

参数名 类型 是否必传 说明
address_id string 要修改的地址ID(路径参数)

3.响应结果:JSON

字段 说明
code 状态码
errmsg 错误信息

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

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

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

        #  校验参数
        if not title:
            return http.HttpResponseForbidden('缺少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': RETCODE.DBERR, 'errmsg': '设置地址标题失败'})

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

3. 修改地址标题前端逻辑实现

美多商城之用户中心(收货地址3)

<div class="site_title">
    <div v-if="edit_title_index===index">
        <input v-model="new_title" type="text" name="">
        <input @click="save_title(index)" type="button" name="" value="保 存">
        <input @click="cancel_title(index)" type="reset" name="" value="取 消">
    </div>
    <div>
        <h3>[[ address.title ]]</h3>
        <a @click="show_edit_title(index)" class="edit_title"></a>
    </div>
    <em v-if="address.id===default_address_id">默认地址</em>
    <span @click="delete_address(index)">×</span>
</div>
data: {
    edit_title_index: '',
    new_title: '',
},

美多商城之用户中心(收货地址3)

// 展示地址title编辑框
show_edit_title(index){
    this.edit_title_index = index;
},
// 取消保存地址title
cancel_title(){
    this.edit_title_index = '';
    this.new_title = '';
},
// 修改地址title
save_title(index){
    if (!this.new_title) {
        alert("请填写标题后再保存!");
    } else {
        let url = '/addresses/' + this.addresses[index].id + '/title/';
        axios.put(url, {
            title: this.new_title
        }, {
            headers: {
                'X-CSRFToken':getCookie('csrftoken')
            },
            responseType: 'json'
        })
            .then(response => {
                if (response.data.code == '0') {
                    // 更新地址title
                    this.addresses[index].title = this.new_title;
                    this.cancel_title();
                } else if (response.data.code == '4101') {
                    location.href = '/login/?next=/addresses/';
                } else {
                    alert(response.data.errmsg);
                }
            })
            .catch(error => {
                console.log(error.response);
            })
    }
},
上一篇:关于linux系统CPU篇--->不容易发现的占用CPU较高进程


下一篇:(iOS) IPTools.h/m - 获取ip地址(ipv4/ipv6)