zoukankan      html  css  js  c++  java
  • Django商城项目笔记No.16用户部分-用户中心收货地址

    首先完成省市区三级联动

    新建areas应用

    python ../../manage.py startapp areas

    模型类代码

    class Area(models.Model):
        """
        行政区划
        """
        name = models.CharField(max_length=20, verbose_name='名称')
        parent = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='subs', null=True, blank=True, verbose_name='上级行政区划')
    
        class Meta:
            db_table = 'tb_areas'
            verbose_name = '行政区划'
            verbose_name_plural = '行政区划'
    
        def __str__(self):
            return self.name

    模型类代码说明:

    parent = models.ForeignKey('self', on_delete=models.SET_NULL, related_name='subs', null=True, blank=True, verbose_name='上级行政区划')

    self:自关联

    on_delete=models.SET_NULL 在删除父级的时候,自己的parent_id设置为空,这里就不在级联删除了,避免误删除,采集数据不容易。

    related_name=’subs’ 这个跟flaskbackref很类似。 意思为如果想找自己的子级,就可以通过area.subs找到自己下级所有的area区域。

    之后配置应用

    然后迁移数据库

    python manage.py makemigrations
    python manage.py migrate

    导入测试数据脚本

    增加执行权限

    返回省市区数据的后端视图集实现

     

    定义视图最终如下

    采用视图集

    序列化器

    定义路由

    DRF缓存的实现

     省市区的数据是经常被用户查询使用的,而且数据基本不变化,所以我们可以将省市区数据进行缓存处理,减少数据库的查询次数。

    在Django REST framework中使用缓存,可以通过drf-extensions扩展来实现。

    关于扩展使用缓存的文档,可参考链接http://chibisov.github.io/drf-extensions/docs/#caching

     安装

    pip install drf-extensions

    使用方法

    配置文件

    禁止分页

    前端代码

    <!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="css/reset.css">
        <link rel="stylesheet" type="text/css" href="css/main.css">
        <script type="text/javascript" src="js/host.js"></script>
        <script type="text/javascript" src="js/vue-2.5.16.js"></script>
        <script type="text/javascript" src="js/axios-0.18.0.min.js"></script>
        <script>
            var user_id = sessionStorage.user_id || localStorage.user_id;
            var token = sessionStorage.token || localStorage.token;
            if (!(user_id && token)) {
                location.href = '/login.html?next=/user_center_site.html';
            }
        </script>
    </head>
    <body>
        <div id="app" v-cloak>
        <div class="header_con">
            <div class="header">
                <div class="welcome fl">欢迎来到美多商城!</div>
                <div class="fr">
                    <div class="login_btn fl">
                        欢迎您:<em>{{ username }}</em>
                        <span>|</span>
                        <a @click="logout">退出</a>
                    </div>
                    <div class="user_link fl">
                        <span>|</span>
                        <a href="user_center_info.html">用户中心</a>
                        <span>|</span>
                        <a href="cart.html">我的购物车</a>
                        <span>|</span>
                        <a href="user_center_order.html">我的订单</a>
                    </div>
                </div>
            </div>        
        </div>
    
        <div class="search_bar clearfix">
            <a href="index.html" class="logo fl"><img src="images/logo.png"></a>
            <div class="sub_page_name fl">|&nbsp;&nbsp;&nbsp;&nbsp;用户中心</div>
            <form method="get" action="/search.html" class="search_con fr mt40">
                <input type="text" class="input_text fl" name="q" placeholder="搜索商品">
                <input type="submit" class="input_btn fr" name="" value="搜索">
            </form>
        </div>
    
        <div class="main_con clearfix">
            <div class="left_menu_con clearfix">
                <h3>用户中心</h3>
                <ul>
                    <li><a href="user_center_info.html">· 个人信息</a></li>
                    <li><a href="user_center_order.html">· 全部订单</a></li>
                    <li><a href="user_center_site.html" class="active">· 收货地址</a></li>
                    <li><a href="user_center_pass.html">· 修改密码</a></li>
                </ul>
            </div>
            <div class="right_content clearfix"> 
                    <div class="site_top_con">
                        <a @click="show_add">新增收货地址</a>
                        <span>您已创建了<b>{{addresses.length}}</b>个收货地址,最多可创建<b>{{ limit }}</b></span>
                    </div>
                    <div class="site_con" v-for="(address, index) in addresses">
                        <div class="site_title">
                            <div v-if="is_set_title[index]">
                                <input v-model="input_title" type="text" name="">
                                <input @click="save_title(index)" type="button" name="" value="保 存">
                                <input @click="cancel_title(index)" type="reset" name="" value="取 消">
                            </div>
                            <div v-else>
                                <h3>{{ address.title }}</h3>
                                <a @click="show_edit_title(index)"></a>
                            </div>    
                            <em v-if="address.id==default_address_id">默认地址</em>                        
                            <span @click="del_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" @click="set_default(index)">设为默认</a>
                            <a @click="show_edit(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 © 2016 北京美多商业股份有限公司 All Rights Reserved</p>
            <p>电话:010-****888    京ICP备*******8号</p>
        </div>
    
        <div class="pop_con" v-show="is_show_edit">
            <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" name="">
                            <span v-show="error_receiver" class="error_tip">请填写收件人</span>
                        </div>
                        <div class="form_group">
                            <label>*所在地区:</label>
                            <select v-model="form_address.province_id">
                                <option v-for="province in provinces" v-bind:value="province.id">{{ province.name }}</option>
                            </select>
                            <select v-model="form_address.city_id">
                                <option v-for="city in cities" v-bind:value="city.id">{{ city.name }}</option>
                            </select>
                            <select v-model="form_address.district_id">
                                <option v-for="district in districts" v-bind: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" name="">
                            <span v-show="error_place" class="error_tip">请填写地址信息</span>
                        </div>
                        <div class="form_group">
                            <label>*手机:</label>
                            <input v-model="form_address.mobile" @blur="check_mobile" type="text" name="">
                            <span v-show="error_mobile" class="error_tip">手机信息有误</span>
                        </div>
                        <div class="form_group">
                            <label>固定电话:</label>
                            <input v-model="form_address.tel" type="text" name="">
                        </div>
                        <div class="form_group">
                            <label>邮箱:</label>
                            <input v-model="form_address.email" @blur="check_email" type="text" name="">
                            <span v-show="error_email" class="error_tip">邮箱信息有误</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 class="mask"></div>
        </div>
        </div>
        <script type="text/javascript" src="js/user_center_site.js"></script>
    </body>
    </html>
    View Code

    js代码

    var vm = new Vue({
        el: '#app',
        data: {
            host: host,
            user_id: sessionStorage.user_id || localStorage.user_id,
            token: sessionStorage.token || localStorage.token,
            username: sessionStorage.username || localStorage.username,
            is_show_edit: false,
            provinces: [],
            cities: [],
            districts: [],
            addresses: [],
            limit: '',
            default_address_id: '',
            form_address: {
                receiver: '',
                province_id: '',
                city_id: '',
                district_id: '',
                place: '',
                mobile: '',
                tel: '',
                email: '',
            },
            error_receiver: false,
            error_place: false,
            error_mobile: false,
            error_email: false,
            editing_address_index: '', // 正在编辑的地址在addresses中的下标,''表示新增地址
            is_set_title: [],
            input_title: ''
        },
        mounted: function(){
            axios.get(this.host + '/areas/', {
                    responseType: 'json'
                })
                .then(response => {
                    this.provinces = response.data;
                })
                .catch(error => {
                    alert(error.response.data);
                });
        },
        watch: {
            'form_address.province_id': function(){
                if (this.form_address.province_id) {
                    axios.get(this.host + '/areas/'+ this.form_address.province_id + '/', {
                            responseType: 'json'
                        })
                        .then(response => {
                            this.cities = response.data.subs;
                        })
                        .catch(error => {
                            console.log(error.response.data);
                            this.cities = [];
                        });
                }
            },
            'form_address.city_id': function(){
                if (this.form_address.city_id){
                    axios.get(this.host + '/areas/'+ this.form_address.city_id + '/', {
                            responseType: 'json'
                        })
                        .then(response => {
                            this.districts = response.data.subs;
                        })
                        .catch(error => {
                            console.log(error.response.data);
                            this.districts = [];
                        });
                }
            }
        },
        methods: {
            // 退出
            logout: function(){
                sessionStorage.clear();
                localStorage.clear();
                location.href = '/login.html';
            },
            clear_all_errors: function(){
                this.error_receiver = false;
                this.error_mobile = false;
                this.error_place = false;
                this.error_email = false;
            },
            // 展示新增地址界面
            show_add: function(){
                this.clear_all_errors();
                this.editing_address_index = '';
                this.form_address.receiver = '';
                this.form_address.province_id = '';
                this.form_address.city_id = '';
                this.form_address.district_id = '';
                this.form_address.place = '';
                this.form_address.mobile = '';
                this.form_address.tel = '';
                this.form_address.email = '';
                this.is_show_edit = true;
            },
            // 展示编辑地址界面
            show_edit: function(index){
                this.clear_all_errors();
                this.editing_address_index = index;
                // 只获取数据,防止修改form_address影响到addresses数据
                this.form_address = JSON.parse(JSON.stringify(this.addresses[index]));
                this.is_show_edit = true;
            },
            check_receiver: function(){
                if (!this.form_address.receiver) {
                    this.error_receiver = true;
                } else {
                    this.error_receiver = false;
                }
            },
            check_place: function(){
                if (!this.form_address.place) {
                    this.error_place = true;
                } else {
                    this.error_place = false;
                }
            },
            check_mobile: function(){
                var re = /^1[345789]d{9}$/;
                if(re.test(this.form_address.mobile)) {
                    this.error_mobile = false;
                } else {
                    this.error_mobile = true;
                }
            },
            check_email: function(){
                if (this.form_address.email) {
                    var re = /^[a-z0-9][w.-]*@[a-z0-9-]+(.[a-z]{2,5}){1,2}$/;
                    if(re.test(this.form_address.email)) {
                        this.error_email = false;
                    } else {
                        this.error_email = true;
                    }
                }
            },
            // 保存地址
            save_address: function(){
    
            },
            // 删除地址
            del_address: function(index){
    
            },
            // 设置默认地址
            set_default: function(index){
    
            },
            // 展示编辑标题
            show_edit_title: function(index){
    
            } ,
            // 保存地址标题
            save_title: function(index){
    
            },
            // 取消保存地址
            cancel_title: function(index){
    
            }
        }
    })
    View Code

    测试

  • 相关阅读:
    C#内建接口:IComparable
    C#内建接口:IEnumerable
    WPF中使用资源
    WPF中的触发器(Trigger)
    一文详解 | 开放搜索兼容Elasticsearch做召回引擎
    阿里云李飞飞:中国数据库的时与势
    如何构建流量无损的在线应用架构 | 专题开篇
    如何构建一个流量无损的在线应用架构 | 专题中篇
    多任务学习模型之ESMM介绍与实现
    云原生时代的运维体系进化
  • 原文地址:https://www.cnblogs.com/blog-rui/p/9939856.html
Copyright © 2011-2022 走看看