三、收货地址
3.2 新增地址前后端逻辑
1. 定义用户地址模型类
2. 新增地址接口设计和定义
4. 新增地址前端逻辑实现
3. 展示地址前端逻辑实现
1.用户地址模型类
from meiduo_mall.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

数据库迁移:

1.请求方式
选项方案请求方法POST请求地址/addresses/create/2.请求参数:JSON 【用户收货地址都是以局部刷新的形式来做的】
参数名类型是否必传说明receiverstring是收货人province_idstring是省份IDcity_idstring是城市IDdistrict_idstring是区县IDplacestring是收货地址mobilestring是手机号telstring否固定电话emailstring否邮箱3.响应结果:JSON
字段说明code状态码errmsg错误信息id地址IDreceiver收货人province省份名称city城市名称district区县名称place收货地址mobile手机号tel固定电话email邮箱 3. 新增地址后端逻辑实现提示:
- 用户地址数量有上限,最多20个,超过地址数量上限就返回错误信息
from . import constants
from .models import Address
class CreateAddressView(LoginRequiredMixin, 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.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 = Address.objects.create( # create方法中封装了save()方法
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 http.JsonResponse({'code': RETCODE.OK, 'errmsg': '新增地址成功', 'address': address_dict})





save_address(){
if (this.error_receiver || this.error_place || this.error_mobile || this.error_email || !this.form_address.province_id || !this.form_address.city_id || !this.form_address.district_id ) {
alert('信息填写有误!');
} else {
// 新增地址
let url = '/addresses/create/';
axios.post(url, this.form_address, {
headers: {
'X-CSRFToken':getCookie('csrftoken')
},
responseType: 'json'
})
.then(response => {
if (response.data.code == '0') {
// 局部刷新界面:展示所有地址信息
} else if (response.data.code == '4101') {
location.href = '/login/?next=/addresses/';
} else {
alert(response.data.errmsg);
}
})
.catch(error => {
console.log(error.response);
})
}
},
1.请求方式
选项方案请求方法GET请求地址/addresses/2.请求参数
无
3.响应结果:HTML
user_center_site.html
2. 展示地址后端逻辑实现
class AddressView(LoginRequiredMixin, View):
"""用户收货地址"""
def get(self, request):
"""提供收货地址界面"""
# 获取用户地址列表
login_user = request.user
addresses = Address.objects.filter(user=login_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
}
address_dict_list.append(address_dict)
context = {
'default_address_id': login_user.default_address_id,
'addresses': address_dict_list,
}
return render(request, 'user_center_site.html', context)


1.将后端模板数据传递到Vue.js
let addresses = {{ addresses | safe }};
let default_address_id = "{{ default_address_id }}";
data: {
addresses: JSON.parse(JSON.stringify(addresses)),
default_address_id: default_address_id,
},
2.user_center_site.html
中渲染地址信息
新增收货地址
你已创建了[[ addresses.length ]]个收货地址,最多可创建20个
[[ address.title ]]
默认地址
×
- 收货人:[[ address.receiver ]]
- 所在地区:[[ address.province ]] [[address.city]] [[ address.district ]]
- 地址:[[ address.place ]]
- 手机:[[ address.mobile ]]
- 固定电话:[[ address.tel ]]
- 电子邮箱:[[ address.email ]]
设为默认
编辑
3.完善user_center_site.js
中成功新增地址后的局部刷新
if (response.data.code == '0') {
// 局部刷新界面:展示所有地址信息,将新的地址添加到头部
this.addresses.splice(0, 0, response.data.address);
this.is_show_edit = false;
}