【愚公系列】2022年01月 Django商城项目16-用户中心-地址管理之省市三联动功能实现

举报
愚公搬代码 发表于 2022/01/24 00:50:08 2022/01/24
【摘要】 一、创建数据库表结构为: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="#">21</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>电话:13960699696ICP*******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

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。