三、收货地址
3.4 修改地址前后端逻辑
1. 修改地址接口设计和定义
1.请求方式
选项 | 方案 |
---|---|
请求方法 | PUT |
请求地址 | /addresses/(?P<address_id>\d+)/ |
# 修改和删除地址
url(r'^addresses/(?P<address_id>\d+)/$', views.UpdateDestroyAddressView.as_view()),
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 | 否 | 固定电话 |
string | 否 | 邮箱 |
3.响应结果:JSON
字段 | 说明 |
---|---|
code | 状态码 |
errmsg | 错误信息 |
id | 地址ID |
receiver | 收货人 |
province | 省份名称 |
city | 城市名称 |
district | 区县名称 |
place | 收货地址 |
mobile | 手机号 |
tel | 固定电话 |
邮箱 |
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: '',
},
2.实现编辑
按钮对应的事件
show_edit_site(index){
this.is_show_edit = true;
this.clear_all_errors();
this.editing_address_index = index.toString();
},
<div class="down_btn">
<a v-if="address.id!=default_address_id">设为默认</a>
<a href="javascript:;" class="edit_icon">编辑</a>
</div>
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. 修改地址标题前端逻辑实现
<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: '',
},
// 展示地址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);
})
}
},