十日Python项目——第四日(用户中心—收货地址)

#前言:

在最近十天我会用Python做一个购物类项目,会用到Django+Mysql+Redis+Vue等。

今天是第四天,主要负责撰写用户中心部分的收货地址部分。若是有不懂大家可以先阅读我的前三篇博客以能够顺承

若是大家基础有不懂的,小编前面已经关于Django博客都更新完了,大家可以自行查看。若是有需要更改的地方欢迎大家指正,同时也欢迎大家关注点赞收藏等待后续,小编会尽力更新优质博客。

在此我会直接继承上一篇博客继续往下写。

九、用户中心(收货地址)

前提声明:

这是我们此篇幅博客要实现的终极目标,能够创建一个收获地址。

1、创捷视图接收路由:

在user应用下:

# 收货地址
path('address/' , views.AddressView.as_view() , name='address'),class AddressView(View):'''用户收货地址'''def get(self , request):return render(request , 'user_center_site.html')

2、创建应用:

当我们创建地址时候,面临的第一个问题就是我们要选择对应省——省对应的市——市对应的区。

因为,关于地区的信息和操作和其它操作关联性不强,所以我们单独创建注册一个areas应用。

(具体如何创建前面有很多很多次讲解,大家可以翻阅前几篇博客。)

3、创建模型类:

省——市——区。不难发现这其实是一个一对多的关系,但是由于数据量太庞大,创建多表的话占用内存太大,所以我们选择自关联,因为它省略磁盘空间,在一个表操作。

所以我们arear应用的模型类下创建:

from django.db import models# Create your models here.
class Area(models.Model):'''实现省市区名称:有个关联关系:省市区,分别都是一对多。
自关联:省略磁盘空间,在一个表操作'''name=models.CharField(max_length=20)#SET_NULL:删除被关联的数据,对应的数据字段就会被自动设置为NULLparent=models.ForeignKey('self',on_delete=models.SET_NULL,null=True,related_name='subs')#外键class Meta:db_table='areas'

这个表是什么意思,举个例子:

每个市、区都会有对应外键对应省、市。

'''
自关联id      name        parent_id1       广东省         null2       湖北省         null3       广州市         14       天河区         35       武汉市         26	    深圳市		   1
'''

而这个庞大的数据集要导入到数据库我已经将SQL语句写好了,大家可以到我网盘自行免费领取:

链接:https://pan.baidu.com/s/1A0wPS9cuPYG7zqM5wxau6w?pwd=ammd 
提取码:ammd

这个数据集大家也可以一直留着,以后也可以经常使用。

注意这个数据集你在运行SQL语句时候一定要选择按语句的顺序开始运行,不然会出现很多错误。

4、读取地区数据:

对于我们的数据,因为都是在读,对地区该的频率低,所以我们优先考虑缓存Cache,具体来说:可以把这些数据缓存到内存,cache 可以连接到配置文件中设置的默认缓存内存数据库。

在areas应用的视图下:

主要思路就是,先从内存中访问省市,若没有去Mysql数据库中找到并且存入Cache,需要注意的是访问的为什么是province_list等,是因为Json数据响应的变量名称是他们,剩下的代码中都有详细解释。

from django.shortcuts import render
from django.views import View
from django.http import JsonResponse
from areas.models import Area
from utils.response_code import RETCODE
from django.core.cache import cacheclass AreasView(View):'''读取省市区地区数据省市区:读频率高 , 写改的频率低的数据;可以把这些数据缓存到内存cache 可以连接到配置文件中设置的默认缓存内存数据库'''def get(self , request):area_id = request.GET.get('area_id')# 判断请求是否存在 area_id 的参数if not area_id:# 从内存中获取省份的数据province_list = cache.get('province_list')# 判断这个数据在内存中是否存在if not province_list:# 获取省份的名称数据(到MySQL数据库)province_model_list = Area.objects.filter(parent_id__isnull=True)'''响应 json 数据{'code' : 200'errmsg' : OK'province_list' : [{id:110000;name:北京市},{id:120000;name:天津市},{id:130000;name:河北省},……]}'''province_list = []for province_model in province_model_list:province_dict = {"id":province_model.id,"name":province_model.name}province_list.append(province_dict)# 将数据缓存到内存中cache.set('province_list' , province_list , 3600)return JsonResponse({'code':RETCODE.OK , 'errmsg':"OK" , 'province_list':province_list})else:# 获取市区的名称数据# area_id 要么是省的 id(要获取到市的数据) 要么是市的 id(要获取到区的数据)# 根据 area_id 的值进行获取对应关联该值的数据'''响应 json 数据{'code' : 200'errmsg' : OKsub_data = {id: 110000name: 北京市subs : [{id:110101;name:东城区},{id:110102;name:西城区},……]}}'''sub_data = cache.get('sub_data_%s'%area_id)if not sub_data:# 获取 area_id 对应的数据parent_model = Area.objects.get(id=area_id)# 获取到关联 parent_model 这个对象的所有数据sub_model_list = parent_model.subs.all()subs = []for sub_model in sub_model_list:sub_dict = {"id": sub_model.id,"name": sub_model.name}subs.append(sub_dict)sub_data = {"id": parent_model.id,"name" : parent_model.name,"subs" : subs}cache.set('sub_data_%s'%area_id , sub_data , 3600)return JsonResponse({'code': RETCODE.OK, 'errmsg': "OK", 'sub_data': sub_data})

5、响应到前端:

修改前端中 user_center_site.html 中对应标签的内容。

<div class="form_group"><label>*所在地区:</label><select v-model="form_address.province_id"><option value="0">请选择</option><option :value="province.id" v-for="province in provinces">[[ province.name ]]</option></select><select v-model="form_address.city_id"><option value="0">请选择</option><option :value="city.id" v-for="city in cities">[[ city.name ]]</option></select><select v-model="form_address.district_id"><option value="0">请选择</option><option :value="district.id" v-for="district in districts">[[ district.name ]]</option></select>
</div>

6、创建时间模型类:

关于创建地址,或者说后面对货物上架我们都会用到关于时间以及时间更新的数据,所以我们创建一个专门争对时间的model类。

让其他模型可以共用时间字段,在utils 包中创建一个 model 文件。

from django.db import modelsclass BaseModel(models.Model):# 创建时间create_time = models.DateTimeField(auto_now_add=True)# 更新时间update_time = models.DateTimeField(auto_now=True)class Meta:# 让该模型类在迁移数据库的时候不为其单独创建一张表,必须依赖于其它模型类abstract = True

当其他模型类需要使用到该字段的时候,直接继承即可。

7、创建用户收货地址模型类:

在areas的模型下创建。

class Address(BaseModel):# 用户收货地址# 关联用户 , 要知道对应的数据是那个用户地址user = models.ForeignKey(User , on_delete=models.CASCADE , related_name='address')receiver = models.CharField(max_length=20)# models.PROTECT:如果要删除的数据,有被其他数据关联,那么删除的操作失败。province = models.ForeignKey('areas.Area' , on_delete=models.PROTECT , related_name='province_address')city = models.ForeignKey('areas.Area' , on_delete=models.PROTECT , related_name='city_address')district = models.ForeignKey('areas.Area' , on_delete=models.PROTECT , related_name='district_address')palce = models.CharField(max_length=50) # 详细地址mobile = models.CharField(max_length=11)tel = models.CharField(max_length=20 , null=True , blank=True , default='')email = models.CharField(max_length=20 , null=True , blank=True , default='')class Meta:db_table = 'address'

对标的正好是这些属性,值得一说的是关于固定电话以及邮箱这是非必填的内容,模型类中设置是可以为空。

而我们的用户地址到时候会有一个默认地址,所以我们是在用户个人数据模型类中保存默认收货地址 , 默认地址只能有一个。

注意:这是在原有模型类上面只加了一行代码,并不是重新定义的模型类。

class User(AbstractUser):'''用户数据认证模型类'''mobile=models.CharField(max_length=11,unique=True)email = models.EmailField(blank=True, null=True)  # 允许为空#默认收获地址:关联收货地址模型类的数据default_address=models.ForeignKey('Address',on_delete=models.SET_NULL,null=True,related_name='users')class Meta:db_table='user'

8、新增用户收货地址:

注意数据是Json数据类型的所以相对数据进行解码,然后接收数据,校验是否合法,然后将它保存到数据库(因为是地址,不具有唯一性,所以不进行数据库校验)。

# 新增收货地址
path('addresses/create/' , views.AddressCreateView.as_view()),class AddressCreateView(View):'''用户新增收货地址'''def post(self , request):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 HttpResponseForbidden('缺少必要的数据')if not re.match(r'^1[3-9]\d{9}$' , mobile):return HttpResponseForbidden('手机号有误')if tel:if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$' , tel):return HttpResponseForbidden('固定电话有误')if email:if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$' , email):return HttpResponseForbidden('邮箱有误')# 将数据保存到数据库中address = Address.objects.create(user=request.user,receiver=receiver,province_id = province_id,city_id = city_id,district_id = district_id,palce = place,mobile = mobile,tel = tel,email = email)address_dict = {"id" : address.id,'receiver': address.receiver,'province': address.province.name,'city': address.city.name,'district': address.district.name,'place': address.palce,'mobile': address.mobile,'tel': address.tel,'email': address.email,}return JsonResponse({"code":RETCODE.OK , 'errmsg':"新增地址成功" , "address":address_dict})

注意:address_dict 变量用于构造一个包含新创建的收货地址详细信息的字典。这些信息随后会作为 JSON 响应的一部分返回给前端。这个字典的结构便于前端展示新地址的详细信息,并且能够直接用于界面更新或数据处理。

9、渲染收货地址:

渲染收获地址说白了就是能将收货地址响应到页面:

我们 要做的就是获取用户登录信息,然后去数据库获取相应的用户信息,最后获取地址信息,然后由后端接收返回到前端页面。

class AddressView(View):'''用户收货地址'''def get(self , request):# 获取当前登录的用户信息login_user = request.user# 根据当前登录的用户信息 , 获取对应的收货地址数据addresses = Address.objects.filter(user=login_user)address_list = []for address in addresses:address_dict = {"id": address.id,'receiver': address.receiver,'province': address.province.name,'city': address.city.name,'district': address.district.name,'place': address.palce,'mobile': address.mobile,'tel': address.tel,'email': address.email,}address_list.append(address_dict)context = {'addresses' : address_list,# 获取用户默认收货地址'default_address_id': login_user.default_address_id,# 用户收货地址个数'count' : addresses.count()}return render(request , 'user_center_site.html' , context=context)

此时的前端:

修改 user_center_site.html 页面中对应标签的内容:

将数据接收到Js里面了,所以HTML的内容也要和JS对应。

<script type="text/javascript">let addresses = {{ addresses | safe }};let default_address_id = {{ default_address_id|default:0 }};
</script>

注意:我们按照JS不仅接收参数,而且得接收索引。也就是( v-for="(address , index) in addresses"),最后按照参数和索引一起来相应到前端。

<div class="right_content clearfix" v-cloak><div class="site_top_con"><a @click="show_add_site">新增收货地址</a><span>你已创建了<b>{{ count }}</b>个收货地址,最多可创建<b>20</b>个</span></div><div class="site_con" v-for="(address , index) in addresses"><div class="site_title"><h3>[[ address.receiver ]]</h3><a @click="show_edit_title(index)" 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" @click="set_default(index)"> 设置默认地址</a><a @click="show_edit_site(index)" class="edit_icon">编辑</a></div></div>
</div>

10、设置默认收货地址:

要设置默认收获地址前我们先用前端网页抓取来判断一下默认收货地址的请求类型和响应路由。

我们由此的得到是put请求和路由所以我们就可以开始写视图和路由。

# 默认收货地址
re_path('^addresses/(?P<address_id>\d+)/default/$'  , views.DefaultAddressView.as_view()),class DefaultAddressView(View):'''设置默认收获地址'''def put(self,request,address_id):#去网页抓取一下就能发现接受的参数和为什么是put请求了address=Address.objects.get(id=address_id)request.user.default_address=addressrequest.user.save()#将数据保存到数据库中return JsonResponse({'code':'RETCODE.OK','errmsg':"默认收获地址设置成功"})

前面HTML代码中已经包括了默认地址响应的代码。

11、删除/修改收货地址:

同样的要设前我们先用前端网页抓取来判断一下默认收货地址的请求类型和响应路由。

我们发现修改是delete请求、删除是put请求,而路由两个的一致,所以我们只需要创建一个分发路由即可。

和上面的操作一致,我们开始写类视图与分发路由。

写类视图的思路为:删除很简单,就是由地址id直接从数据库删除。而修改的思路和前面新增地址的基本一致,先解码json数据,再获取地址信息(自己输入前端页面的信息,也就是get请求),校验数据完整性,然后获取原先地址id,将原先输入的地址信息修改为刚刚输入的信息,最后将新地址信息保存到数据库。

# 修改/删除收货地址
re_path('^addresses/(?P<address_id>\d+)/$'  , views.UpdateAddressView.as_view()),class UpdateAddressView(View):'''修改/删除收货地址'''def delete(self , request , address_id):# 删除收货地址Address.objects.get(id=address_id).delete()return JsonResponse({"code": RETCODE.OK, 'errmsg': "地址删除成功"})def put(self , request , address_id):# 修改收货地址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 HttpResponseForbidden('缺少必要的数据')if not re.match(r'^1[3-9]\d{9}$', mobile):return HttpResponseForbidden('手机号有误')if tel:if not re.match(r'^(0[0-9]{2,3}-)?([2-9][0-9]{6,7})+(-[0-9]{1,4})?$', tel):return HttpResponseForbidden('固定电话有误')if email:if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):return HttpResponseForbidden('邮箱有误')Address.objects.filter(id=address_id).update(user=request.user,receiver=receiver,province_id=province_id,city_id=city_id,district_id=district_id,palce=place,mobile=mobile,tel=tel,email=email)address = Address.objects.get(id=address_id)address_dict = {"id": address.id,'receiver': address.receiver,'province': address.province.name,'city': address.city.name,'district': address.district.name,'place': address.palce,'mobile': address.mobile,'tel': address.tel,'email': address.email,}return JsonResponse({"code": RETCODE.OK, 'errmsg': "地址修改成功", "address": address_dict})

#总结:

该篇博客详细的介绍的Python项目中关于用户中心收货地址的讲解,主要是前后端和数据库来回获取数据,来回调用,响应,增删改查。内容完整详细,若是各位大佬发现需要修改的地方欢迎前来批评指正。同时,我后续还会继续更新后面项目内容,欢迎大家关注!您的关注与点赞将是小编变强路上最强的动力!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/387364.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

01、爬虫学习入门

爬虫&#xff1a;通过编写程序&#xff0c;来获取获取互联网上的资源 需求&#xff1a;用程序模拟浏览器&#xff0c;输入一个网址&#xff0c;从该网址获取到资源或内容 一、入门程序 #使用urlopen来进行爬取 from urllib.request import urlopen url "http://www.ba…

我们的网站被狗爬了!

大家好&#xff0c;我是程序员鱼皮。 世风日下&#xff0c;人心不古。我们的程序员面试刷题网站 《面试鸭》 才刚刚上线了一个多月&#xff0c;就由于过于火爆&#xff0c;被不少同行和小人发起网络攻击。 而且因为我们已经有 4500 多道人工整理的企业高频面试题、100 多个各…

【JavaScript】函数的动态传参

Javacript&#xff08;简称“JS”&#xff09;是一种具有函数优先的轻量级&#xff0c;解释型或即时编译型的编程语言。虽然它是作为开发Web页面的脚本语言而出名&#xff0c;但是它也被用到了很多非浏览器环境中&#xff0c;JavaScript基于原型编程、多范式的动态脚本语言&…

第六周:机器学习周报

机器学习周报 摘要Abstract机器学习——类神经网络训练不起来怎么办&#xff1f;1. 自动调整学习率&#xff08;learning rate&#xff09;1.1 特制化的Learning Rate——parameter dependent1.1.1 Root Mean Square&#xff08;RMS&#xff0c;均方根&#xff09;1.1.2 RMSPro…

Qt Creator使用git管理代码

1.在GitHub中新建仓库&#xff0c;设置好仓库名后&#xff0c;其它的设置默认即可。 2.打开git bash&#xff0c;输入以下命令&#xff1a; git config --global user.name "xxxxx" #设置你的GitHub用户名 git config --global user.email "xxxxxxxxx.…

DMB,DSB,ISB三个指令区别

此部分说明三个指令的具体区别&#xff08;在指令流水线上说明&#xff09;&#xff0c;这三个指令主要目的在于确保程序在多处理器环境下的稳定性和一致性&#xff0c;避免由于指令乱序和内存操作重排引起的不可预测行为 一个简化的流水线&#xff0c;包含以下阶段&#xff1…

[Docker][Docker Registry]详细讲解

目录 1.什么是Docker Registry&#xff1f;2.镜像源配置3.镜像仓库命令1.命令清单2.docker login2.docker pull3.docker push4.docker search5.docker logout 1.什么是Docker Registry&#xff1f; 镜像仓库(Docker Registry) 功能&#xff1a;负责存储、管理和分发镜像&#x…

腾讯云网站/域名备案操作流程

目录 一、备案服务授权二、备案 一、备案服务授权 二、备案 在“我的备案”页面&#xff0c;点击【去备案】&#xff1a; 点击【新增备案】&#xff1a; 点击【同意并继续】&#xff1a; 选择省份&#xff0c;点击【开始备案】&#xff1a; 输入备案相关信息后点击【提交】…

vue给数组对象赋值改变对象里面的数据,数据没有更新this.$set

替换数组startTime的值&#xff1a; 原数据 this.serviceTimeList.push({serviceTimeName: 服务时间段,startTime: this.startTime,endTime: this.endTime,currentDateStart: this.currentDate,currentDateEnd: this.currentDate}) this.$set(this.array, index, newValue); …

笑谈“八股文”,人生不成文

一、“八股文”在实际工作中是助力、阻力还是空谈&#xff1f; 作为现在各类大中小企业面试程序员时的必问内容&#xff0c;“八股文”似乎是很重要的存在。但“八股文”是否能在实际工作中发挥它“敲门砖”应有的作用呢&#xff1f;有IT人士不禁发出疑问&#xff1a;程序员面试…

计算机系统操作系统简介

目录 1.计算机系统简介 1.1组成结构 1.2系统软件 1.3冯诺依曼计算机特点 1.4硬件构架 2.硬件的进一步认识 2.1存储器 2.2输入设备 2.3输出设备 2.4CPU组成 2.5线的概念引入 3.操作系统 3.1操作系统简介 3.2操作系统如何管理 3.3库函数和系统调用 1.计算机系统简介…

Linux shell编程学习笔记67: tracepath命令 追踪数据包的路由信息

0 前言 网络信息是电脑网络信息安全检查中的一块重要内容&#xff0c;Linux和基于Linux的操作系统&#xff0c;提供了很多的网络命令&#xff0c;今天我们研究tracepath命令。 Tracepath 在大多数 Linux 发行版中都是可用的。如果在你的系统中没有预装&#xff0c;请根据你的…

一下午连续故障两次,谁把我们接口堵死了?!

唉。。。 大家好&#xff0c;我是程序员鱼皮。又来跟着鱼皮学习线上事故的处理经验了喔&#xff01; 事故现场 周一下午&#xff0c;我们的 编程导航网站 连续出现了两次故障&#xff0c;每次持续半小时左右&#xff0c;现象是用户无法正常加载网站&#xff0c;一直转圈圈。 …

android前台服务

关于作者&#xff1a;CSDN内容合伙人、技术专家&#xff0c; 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 &#xff0c;擅长java后端、移动开发、商业变现、人工智能等&#xff0c;希望大家多多支持。 未经允许不得转载 目录 一、导读二、使用2.1 添加权限2.2 新建…

基于SpringBoot+Vue的档案管理系统(带1w+文档)

基于SpringBootVue的档案管理系统(带1w文档) 基于SpringBootVue的档案管理系统(带1w文档) 随着信息化的不断发展&#xff0c;科技的进步也越来越大。软件编程是一个不断发展的行业&#xff0c;每个行业都必须进行适合自身特点的系统开发&#xff0c;才能在机构中生存和发展。当…

大模型算法面试题(十七)

本系列收纳各种大模型面试题及答案。 1、LoRA权重是否可以合入原模型 LoRA权重可以合入原模型。LoRA&#xff08;Low-Rank Adaptation of Large Language Models&#xff09;是一种用于微调大型语言模型的低秩适应技术。它通过训练低秩矩阵&#xff0c;并将这些参数注入到原始…

大数据-56 Kafka SpringBoot与Kafka 基础简单配置和使用

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 目前已经更新到了&#xff1a; Hadoop&#xff08;已更完&#xff09;HDFS&#xff08;已更完&#xff09;MapReduce&#xff08;已更完&am…

支持AI的好用的编辑器aieditor

一、工具概述 AiEditor 是一个面向 AI 的下一代富文本编辑器&#xff0c;她基于 Web Component&#xff0c;因此支持 Layui、Vue、React、Angular 等几乎任何前端框架。她适配了 PC Web 端和手机端&#xff0c;并提供了 亮色 和 暗色 两个主题。除此之外&#xff0c;她还提供了…

【Django5】内置Admin系统

系列文章目录 第一章 Django使用的基础知识 第二章 setting.py文件的配置 第三章 路由的定义与使用 第四章 视图的定义与使用 第五章 二进制文件下载响应 第六章 Http请求&HttpRequest请求类 第七章 会话管理&#xff08;Cookies&Session&#xff09; 第八章 文件上传…

聚观早报 | 华为nova Flip官宣;苹果iOS 17.6正式版发布

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 7月31日消息 华为nova Flip官宣 苹果iOS 17.6正式版发布 方程豹豹5全系降价 vivo X200 Pro主摄参数 谷歌Pixel …