美多商城之用户中心(收货地址1)

三、收货地址

用户地址的主要业务逻辑有:

  1. 展示省市区数据
  2. 用户地址的增删改查处理
  3. 设置默认地址
  4. 设置地址标题

3.1 省市区三级联动

1. 展示收货地址界面

提示:

  • 省市区数据是在收货地址界面展示的,所以我们先渲染出收货地址界面。
  • 收货地址界面中基础的交互已经提前实现。
class AddressView(LoginRequiredMixin, View):
    """用户收货地址"""

    def get(self, request):
        """提供收货地址界面"""
        return render(request, 'user_center_site.html')

把.html和.js文件复制到响应的位置。

urls.py

    #  展示用户收货地址
    url(r'^addresses/$', views.AddressView.as_view(), name='address'),

2. 准备省市区模型和数据

新建子应用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

模型说明:

  • 自关联字段的外键指向自身,所以 models.ForeignKey('self')
  • 使用related_name指明父级查询子级数据的语法
    • 默认Area模型类对象.area_set语法
  • related_name='subs'
    • 现在Area模型类对象.subs语法

导入省市区数据:

mysql -h数据库ip地址 -u数据库用户名 -p数据库密码 数据库 < areas.sql
mysql -h127.0.0.1 -uroot -pmysql meiduo_mall < areas.sql

将areas.sql文件导入到数据库中

3. 查询省市区数据

1.请求方式

选项方案
请求方法GET
请求地址/areas/

总路由:

    #  areas
    url(r'^', include('areas.urls')),

子路由:

from django.conf.urls import url
from . import views

urlpatterns = [
    #  省市区三级联动
    url(r'^areas/$', views.AreasView.as_view()),
]

2.请求参数:查询参数

  • 如果前端没有传入area_id,表示用户需要省份数据
  • 如果前端传入了area_id,表示用户需要市或区数据
参数名类型是否必传说明
area_idstring地区ID

3.响应结果:JSON

  • 省份数据

    {
      "code":"0",
      "errmsg":"OK",
      "province_list":[
          {
              "id":110000,
              "name":"北京市"
          },
          {
              "id":120000,
              "name":"天津市"
          },
          {
              "id":130000,
              "name":"河北省"
          },
          ......
      ]
    }
    
  • 市或区数据

    {
      "code":"0",
      "errmsg":"OK",
      "sub_data":{
          "id":130000,
          "name":"河北省",
          "subs":[
              {
                  "id":130100,
                  "name":"石家庄市"
              },
              ......
          ]
      }
    }
    

4.查询省市区数据后端逻辑实现

  • 如果前端没有传入area_id,表示用户需要省份数据
  • 如果前端传入了area_id,表示用户需要市或区数据
from django.shortcuts import render
from django.views import View
from .models import Area
from django import http
from meiduo_mall.utils.response_code import RETCODE
import logging


#  创建日志输出器
logger = logging.getLogger('django')


# Create your views here.
class AreasView(View):
    """省市区数据"""

    def get(self, request):
        """提供省市区数据"""
        area_id = request.GET.get('area_id')

        if not area_id:
            # 提供省份数据
            try:
                # 查询省份数据
                province_model_list = Area.objects.filter(parent__isnull=True)

                # 序列化省级数据
                province_list = []
                for province_model in province_model_list:
                    province_list.append({'id': province_model.id, 'name': province_model.name})
            except Exception as e:
                logger.error(e)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '省份数据错误'})

            # 响应省份数据
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'province_list': province_list})
        else:
            # 提供市或区数据
            try:
                parent_model = Area.objects.get(id=area_id)  # 查询市或区的父级
                sub_model_list = parent_model.subs.all()

                # 序列化市或区数据  , 将子级模型列表转成字典列表
                sub_list = []
                for sub_model in sub_model_list:
                    sub_list.append({'id': sub_model.id, 'name': sub_model.name})

                #  构造子集json数据
                sub_data = {
                    'id': parent_model.id,  # 父级pk
                    'name': parent_model.name,  # 父级name
                    'subs': sub_list  # 父级的子集
                }
            except Exception as e:
                logger.error(e)
                return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '城市或区数据错误'})

            # 响应市或区数据
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'sub_data': sub_data})

4. Vue渲染省市区数据

1.user_center_site.js

mounted() {
    // 获取省份数据
    this.get_provinces();
},
// 获取省份数据
get_provinces(){
    let url = '/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 = [];
        })
},
watch: {
    // 监听到省份id变化
    'form_address.province_id': function(){
        if (this.form_address.province_id) {
            let url = '/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.subs;
                    } 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){
            let url = '/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.subs;
                    } else {
                        console.log(response.data);
                        this.districts = [];
                    }
                })
                .catch(error => {
                    console.log(error.response);
                    this.districts = [];
                })
        }
    }
},

2.user_center_site.html

<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>

5. 缓存省市区数据

提示:

  • 省市区数据是我们动态查询的结果。
  • 但是省市区数据不是频繁变化的数据,所以没有必要每次都重新查询。
  • 所以我们可以选择对省市区数据进行缓存处理。

1.缓存工具

  • from django.core.cache import cache
  • 存储缓存数据:cache.set('key', 内容, 有效期)
  • 读取缓存数据:cache.get('key')
  • 删除缓存数据:cache.delete('key')
  • 注意:存储进去和读取出来的数据类型相同,所以读取出来后可以直接使用。

2.缓存逻辑

3.缓存逻辑实现

  • 省份缓存数据
    • cache.set('province_list', province_list, 3600)
  • 市或区缓存数据
    • cache.set('sub_area_' + area_id, sub_data, 3600)

from django.shortcuts import render
from django.views import View
from .models import Area
from django import http
from meiduo_mall.utils.response_code import RETCODE
from django.core.cache import cache
import logging


#  创建日志输出器
logger = logging.getLogger('django')


# Create your views here.
class AreasView(View):
    """省市区数据"""

    def get(self, request):
        """提供省市区数据"""
        area_id = request.GET.get('area_id')

        if not area_id:
            #  读取省份缓存数据
            province_list = cache.get('province_list')

            if not province_list:
                # 提供省份数据
                try:
                    # 查询省份数据
                    province_model_list = Area.objects.filter(parent__isnull=True)

                    # 序列化省级数据
                    province_list = []
                    for province_model in province_model_list:
                        province_list.append({'id': province_model.id, 'name': province_model.name})
                except Exception as e:
                    logger.error(e)
                    return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '省份数据错误'})
                #  存储省份缓存数据
                cache.set('province_list', province_list, 3600)

            # 响应省份数据
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'province_list': province_list})
        else:
            #  读取市或区缓存数据
            sub_data = cache.get('sub_area_' + area_id)
            if not sub_data:
                # 提供市或区数据
                try:
                    parent_model = Area.objects.get(id=area_id)  # 查询市或区的父级
                    sub_model_list = parent_model.subs.all()
    
                    # 序列化市或区数据  , 将子级模型列表转成字典列表
                    sub_list = []
                    for sub_model in sub_model_list:
                        sub_list.append({'id': sub_model.id, 'name': sub_model.name})
    
                    #  构造子集json数据
                    sub_data = {
                        'id': parent_model.id,  # 父级pk
                        'name': parent_model.name,  # 父级name
                        'subs': sub_list  # 父级的子集
                    }
                except Exception as e:
                    logger.error(e)
                    return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '城市或区数据错误'})
                #  存储市或区缓存数据
                cache.set('sub_area_' + area_id, sub_data, 3600)

            # 响应市或区数据
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'sub_data': sub_data})

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值