【愚公系列】2022年01月 Django商城项目16-用户中心-地址管理之省市三联动功能实现
【摘要】 一、创建数据库表结构为:id:主键name:省市名称parent_id:自关联主键id 二、后端处理逻辑代码class AreasView(View): def get(self,request): # parent_id = request.GET.get('parent_id') parent_id = request.GET.get('area_id...
一、创建数据库
表结构为:
id:主键
name:省市名称
parent_id:自关联主键id
二、后端处理逻辑代码
class AreasView(View):
def get(self,request):
# parent_id = request.GET.get('parent_id')
parent_id = request.GET.get('area_id')
if parent_id is None:
# 先获取缓存
provience_list = cache.get('pro')
if provience_list is None:
# 查询 省的信息
proviences = Area.objects.filter(parent_id=None)
provience_list = []
for item in proviences:
provience_list.append({
'id':item.id,
'name':item.name
})
# 把转换的数据保存到缓存中
# cache.set(key,value,expire)
cache.set('pro',provience_list,24*3600)
return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','province_list':provience_list})
else:
# 查询 市/区县信息
sub_list = cache.get('sub_%s'%parent_id)
if sub_list is None:
sub_areas = Area.objects.filter(parent_id=parent_id)
# [Area,Area,Area]
sub_list = []
for sub in sub_areas:
sub_list.append({
'id':sub.id,
'name':sub.name
})
cache.set('sub_%s'%parent_id,sub_list,24*3600)
return http.JsonResponse({'code':RETCODE.OK,'errmsg':'ok','sub_data':sub_list})
三、前端相关代码和页面设计
html代码
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title>小徐商城-用户中心</title>
<link rel="stylesheet" type="text/css" href="{{ static('css/reset.css') }}" />
<link rel="stylesheet" type="text/css" href="{{ static('css/main.css') }}" />
<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script type="text/javascript">
let addresses = {{ addresses | safe }};
let default_address_id = "{{ default_address_id }}";
</script>
</head>
<body>
<div id="app" v-cloak>
<div class="header_con">
<div class="header">
<div class="welcome fl">欢迎来到小徐商城!</div>
<div class="fr">
<div v-if="username" class="login_btn fl">
欢迎您:<em>[[ username ]]</em>
<span>|</span>
{# url 本质是 reverse#}
<a href="{{ url('users:logout') }}">退出</a>
</div>
<div v-else=v-else class="login_btn fl">
<a href="{{ url('users:login') }}">登录</a>
<span>|</span>
<a href="{{ url('users:register') }}">注册</a>
</div>
<div class="user_link fl">
<span>|</span>
<a href="{{ url('users:center') }}">用户中心</a>
<span>|</span>
<a href="../static/cart.html">我的购物车</a>
<span>|</span>
<a href="../static/user_center_order.html">我的订单</a>
</div>
</div>
</div>
</div>
<div class="search_bar clearfix">
<a href="index.html" class="logo fl"><img src="{{ static('images/logo.png') }}" /></a>
<div class="search_wrap fl">
<form method="get" action="/search/" class="search_con">
<input type="text" class="input_text fl" name="q" placeholder="搜索商品">
<input type="submit" class="input_btn fr" name="" value="搜索">
</form>
<ul class="search_suggest fl">
<li><a href="#">索尼微单</a></li>
<li><a href="#">优惠15元</a></li>
<li><a href="#">美妆个护</a></li>
<li><a href="#">买2免1</a></li>
</ul>
</div>
</div>
<div class="main_con clearfix">
<div class="left_menu_con clearfix">
<h3>用户中心</h3>
<ul>
<li><a href="{{ url('users:center') }}">· 个人信息</a></li>
<li><a href="../static/user_center_order.html">· 全部订单</a></li>
<li><a href="{{ url('users:showaddress') }}" class="active">· 收货地址</a></li>
<li><a href="../static/user_center_pass.html">· 修改密码</a></li>
</ul>
</div>
<div class="right_content clearfix" v-cloak>
<div class="site_top_con">
<a @click="show_add_site">新增收货地址</a>
<span>你已创建了<b>[[ addresses.length ]]</b>个收货地址,最多可创建<b>20</b>个</span>
</div>
<div class="site_con" v-for="(address, index) in addresses">
<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 class="del_site" @click="delete_address(index)">×</span>
</div>
<ul class="site_list">
<li><span>收货人:</span><b>[[ address.receiver ]]</b></li>
<li><span>所在地区:</span><b>[[ address.province ]] [[address.city]] [[ address.district ]]</b></li>
<li><span>地址:</span><b>[[ address.place ]]</b></li>
<li><span>手机:</span><b>[[ address.mobile ]]</b></li>
<li><span>固定电话:</span><b>[[ address.tel ]]</b></li>
<li><span>电子邮箱:</span><b>[[ address.email ]]</b></li>
</ul>
<div class="down_btn">
<a v-if="address.id!=default_address_id">设为默认</a>
<a href="javascript:;" class="edit_icon" @click="show_edit_site(index)">编辑</a>
</div>
</div>
</div>
</div>
<div class="footer">
<div class="foot_link">
<a href="#">关于我们</a>
<span>|</span>
<a href="#">联系我们</a>
<span>|</span>
<a href="#">招聘人才</a>
<span>|</span>
<a href="#">友情链接</a>
</div>
<p>CopyRight © 2022 福建小徐网络科技有限公司 All Rights Reserved</p>
<p>电话:13960699696 闽ICP备*******8号</p>
</div>
<div class="pop_con" v-show="is_show_edit" v-cloak>
<div class="site_con site_pop">
<div class="site_pop_title">
<h3 v-if="editing_address_index">编辑收货地址</h3>
<h3 v-else>新增收货地址</h3>
<a @click="is_show_edit=false">×</a>
</div>
<form>
<div class="form_group">
<label>*收货人:</label>
<input v-model="form_address.receiver" @blur="check_receiver" type="text" class="receiver">
<span v-show="error_receiver" class="receiver_error">请填写收件人</span>
</div>
<div class="form_group">
<label>*所在地区:</label>
<select v-model="form_address.province_id">
<option v-for="province in provinces" :value="province.id">[[ province.name ]]</option>
</select>
<select v-model="form_address.city_id">
<option v-for="city in cities" :value="city.id">[[ city.name ]]</option>
</select>
<select v-model="form_address.district_id">
<option v-for="district in districts" :value="district.id">[[ district.name ]]</option>
</select>
</div>
<div class="form_group">
<label>*详细地址:</label>
<input v-model="form_address.place" @blur="check_place" type="text" class="place">
<span v-show="error_place" class="place_error">请填写地址信息</span>
</div>
<div class="form_group">
<label>*手机:</label>
<input v-model="form_address.mobile" @blur="check_mobile" type="text" class="mobile">
<span v-show="error_mobile" class="mobile_error">手机信息有误</span>
</div>
<div class="form_group">
<label>固定电话:</label>
<input v-model="form_address.tel" @blur="check_tel" type="text" class="tel">
<span v-show="error_tel" class="tel_error">固定电话有误</span>
</div>
<div class="form_group">
<label>邮箱:</label>
<input v-model="form_address.email" @blur="check_email" type="text" class="email">
<span v-show="error_email" class="email_error">邮箱信息有误</span>
</div>
<input @click="save_address" type="button" name="" value="新 增" class="info_submit">
<input @click="is_show_edit=false" type="reset" name="" value="取 消" class="info_submit info_reset">
</form>
</div>
</div>
<div class="pop_con2">
<div class="confirm_pop">
<div class="confirm_pop_title">
<h3>确认删除</h3>
<a href="javascript:;">×</a>
</div>
<p>您确认删除当前地址吗?</p>
<input type="button" value="确 定" class="confirm_submit" />
<input type="button" value="取 消" class="confirm_submit confirm_cancel" />
</div>
<div class="mask"></div>
</div>
</div>
<script type="text/javascript" src="{{ static('js/host.js') }}"></script>
<script type="text/javascript" src="{{ static('js/common.js') }}"></script>
<script type="text/javascript" src="{{ static('js/user_center_site.js') }}"></script>
</body>
</html>
相关vue代码
var vm = new Vue({
el: '#app',
// 修改Vue变量的读取语法
delimiters: ['[[', ']]'],
data: {
host,
is_show_edit: false,
provinces: [],
cities: [],
districts: [],
form_address: {
title: '',
receiver: '',
province_id: '',
city_id: '',
district_id: '',
place: '',
mobile: '',
tel: '',
email: '',
},
error_receiver: false,
error_place: false,
error_mobile: false,
error_tel: false,
error_email: false,
addresses: [],
editing_address_index: '',
default_address_id: '',
edit_title_index: '',
input_title: '',
add_title: '新 增',
username: '',
},
mounted() {
this.username = getCookie('username');
// 获取省份数据
this.get_provinces();
},
watch: {
// 监听到省份id变化
'form_address.province_id': function () {
if (this.form_address.province_id) {
var url = this.host + '/areas/?area_id=' + this.form_address.province_id;
axios.get(url, {
responseType: 'json'
})
.then(response => {
if (response.data.code == '0') {
this.cities = response.data.sub_data;
console.log(this.cities)
} else {
console.log(response.data);
this.cities = [];
}
})
.catch(error => {
console.log(error.response);
this.cities = [];
});
}
},
// 监听到城市id变化
'form_address.city_id': function () {
if (this.form_address.city_id) {
var url = this.host + '/areas/?area_id=' + this.form_address.city_id;
axios.get(url, {
responseType: 'json'
})
.then(response => {
if (response.data.code == '0') {
this.districts = response.data.sub_data;
} else {
console.log(response.data);
this.districts = [];
}
})
.catch(error => {
console.log(error.response);
this.districts = [];
});
}
}
},
methods: {
// 获取省份数据
get_provinces(){
var url = this.host + '/areas/';
axios.get(url, {
responseType: 'json'
})
.then(response => {
if (response.data.code == '0') {
this.provinces = response.data.province_list;
} else {
console.log(response.data);
this.provinces = [];
}
})
.catch(error => {
console.log(error.response);
this.provinces = [];
});
},
}
});
四、页面效果
总结
省市三联动,注意的逻辑点:
1.事先获取省级数据,在根据省级数据的选择触发vue在watch方法,获取其他地市和区县数据。
2.数据库设计采用一张树形表自关联。
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)