Django+Vue开发生鲜电商平台之9.个人中心功能开发

一个人想要成功,想要改变命运,有梦想是重要的。……我觉得每个人都应该心中有梦,有胸怀祖国的大志向,找到自己的梦想,认准了就去做,不跟风不动摇。同时,我们不仅仅要自己有梦想,你还应该用自己的梦想去感染和影响别人,因为成功者一定是用自己的梦想去点燃别人的梦想,是时刻播种梦想的人。 ——李彦宏

Github和Gitee代码同步更新https://github.com/PythonWebProject/Django_Fresh_Ecommercehttps://gitee.com/Python_Web_Project/Django_Fresh_Ecommerce

一、DRF的API文档自动生成和功能开发

现在已经定义了很多接口,为了可以更清晰地了解每个接口的功能和相关使用说明,现在实现API文档生成。

DRF自动实现了API文档生成,之前在urls.py这已经定义过文档路由为url(r'docs/', include_docs_urls(title='生鲜电商')),,进行访问测试如下: django personal center document preview

可以看到,文档均已自动生成,并且可以进行测试,生成了JS等代码可以直接提供给前端进行测试。

如果报错AttributeError: ‘AutoSchema’ object has no attribute ‘get_link’需要在settings.py中加入配置:

1# DRF配置 2REST_FRAMEWORK = { 3 ... 4 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.AutoSchema', 5 ... 6}

其中,API文档说明是在创建视图时定义的,如定义用户收藏视图如下:

1class UserFavViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): 2 ''' 3 list: 4 用户收藏列表 5 create: 6 创建用户收藏 7 retrieve: 8 用户收藏详情 9 destroy: 10 删除用户收藏 11 ''' 12 permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 13 serializer_class = UserFavSerializer 14 authentication_classes = [JSONWebTokenAuthentication, SessionAuthentication] 15 lookup_field = 'goods_id' 16 17 def get_queryset(self): 18 return UserFav.objects.filter(user=self.request.user, is_delete=False)

在注释中可以看到,对于每种类型的请求,都以固定的格式定义了说明; 并且如果在定义模型、序列化和过滤器时给字段指定了help_text属性,在文档中会显示Description。

文档不用手动更新,在后端代码逻辑实现之后就会自动更新,并且提供了Shell、JavaScript和Python等多种测试代码方式。 并且还提供了权限验证,对于需要验证后才能访问的接口,必须先进行验证,然后才能进行测试,演示如下: django personal center document permission

显然,只有有相关权限才能成功访问,只有存在数据,才会返回数据。

DRF框架为生成OpenAPI模式提供了内置支持,可以与允许构建API文档的工具一起使用。还有许多出色的第三方文档包。

二、用户个人信息修改功能实现

1.通过权限和序列化动态设置获取用户信息

在个人中心中可以修改姓名、出生日期、性别和电子邮件地址等,在修改之前,需要显示用户信息,所以需要定义获取用户信息的接口,并且需要进行权限验证,apps/users/views.py完善如下:

1class UserViewSet(CreateModelMixin, RetrieveModelMixin, viewsets.GenericViewSet): 2 ''' 3 用户 4 create: 5 新增用户 6 ''' 7 8 serializer_class = UserRegSerializer 9 queryset = User.objects.filter(is_delete=False) 10 authentication_classes = [SessionAuthentication, JSONWebTokenAuthentication] 11 12 def get_permissions(self): 13 '''动态设置权限''' 14 if self.action == 'retrieve': 15 return [IsAuthenticated] 16 elif self.action == 'create': 17 return [] 18 return [] 19 20 def get_serializer_class(self): 21 '''动态设置序列化''' 22 if self.action == 'retrieve': 23 return UserDetailSerializer 24 elif self.action == 'create': 25 return UserRegSerializer 26 return UserDetailSerializer 27 28 def create(self, request, *args, **kwargs): 29 serializer = self.get_serializer(data=request.data) 30 serializer.is_valid(raise_exception=True) 31 user = self.perform_create(serializer) 32 re_dict = serializer.data 33 payload = jwt_payload_handler(user) 34 re_dict['token'] = jwt_encode_handler(payload) 35 re_dict['name'] = user.name if user.name else user.username 36 headers = self.get_success_headers(re_dict) 37 return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers) 38 39 def perform_create(self, serializer): 40 return serializer.save() 41 42 def get_object(self): 43 return self.request.user

apps/users/serializers.py定义序列化如下:

1class UserDetailSerializer(serializers.ModelSerializer): 2 '''用户详情序列化''' 3 class Meta: 4 model = User 5 fields = ['name', 'gender', 'birthday', 'email', 'mobile']

可以看到,这里的权限验证与一般的权限验证又有不同: 在用户注册时,因为用户还没有账号,会执行create(request, *args, **kwargs)perform_create(serializer)方法,因此这些方法应该对所有用户开放,不进行全年验证; 而在用户注册之后,修改用户信息需要先获取用户信息,此时执行get_object()方法,因此需要对该方法进行权限验证。 所以不能采用原来的权限验证方法,即permission_classes = [IsAuthenticated],而是需要动态设置权限,即重写get_permissions()方法;除此之外,因为之前定义的用户序列化是针对用户注册功能的,而此时需要获取用户信息,包括name、gender、birthday、email等,与之前用户序列化的username、code、mobile、password等字段有区别,因此需要重新定义一个序列化类UserDetailSerializer,并且对于用户注册和获取信息,UserViewSet也需要实现动态设置序列化,即重写get_serializer_class()方法。

演示如下: django personal center getuserinfo dynamic permission serializer

显然,只有当用户成功登录后,才能访问到信息。

2.Vue接口实现用户信息显示

在前端,组件为src/views/member/userinfo.vue,如下:

1created () { 2 this.getUserInfo(); 3}, 4 5getUserInfo () { //请求用户信息 6 getUserDetail().then((response)=> { 7 this.userInfo = response.data; 8 }).catch(function (error) { 9 console.log(error); 10 }); 11},

调用了getUserInfo接口,在api.js中修改如下:

1//获取用户信息 2export const getUserDetail = () => { return axios.get(`${local_host}/users/1/`) } 3

示意如下: django personal center getuserinfo add and show

显然,已经可以同步获取信息。

3.用户资料修改实现

要实现修改用户信息,只需要使UserViewSet继承自UpdateModelMixin即可,如下:

1class UserViewSet(CreateModelMixin, UpdateModelMixin, RetrieveModelMixin, viewsets.GenericViewSet): 2 ''' 3 用户 4 create: 5 新增用户 6 update: 7 修改用户 8 partial_update: 9 部分修改 10 retrieve: 11 用户详情 12 ''' 13 14 serializer_class = UserRegSerializer 15 queryset = User.objects.filter(is_delete=False) 16 authentication_classes = [SessionAuthentication, JSONWebTokenAuthentication]

userinfo.vue如下:

1<button class="btn_blue_1" style="border:none;" @click="confirmModify">确认修改</button> 2 3confirmModify () { // 确认修改 4 updateUserInfo(this.userInfo).then((response)=> { 5 alert('修改成功'); 6 }).catch(function (error) { 7 console.log(error); 8 }); 9}

调用了updateUserInfo接口,api.js中修改如下:

1//修改用户信息 2export const updateUserInfo = params => { return axios.patch(`${local_host}/users/1/`, params) }

先查询当前用户数据如下:

1+----+--------------------------------------------------------------------------------+----------------------------+--------------+----------+------------+-----------+----------+-----------+----------------------------+--------+------------+--------+-------------+-------------+-----------+ 2| id | password | last_login | is_superuser | username | first_name | last_name | is_staff | is_active | date_joined | name | birthday | gender | mobile | email | is_delete | 3+----+--------------------------------------------------------------------------------+----------------------------+--------------+----------+------------+-----------+----------+-----------+----------------------------+--------+------------+--------+-------------+-------------+-----------+ 4| 1 | pbkdf2_sha256$180000$wpfCm77Dcpee$rHfFjBNZ2SzLLHdd0ZtbiIRqNB86VvgwTJv6ZCXTbfk= | 2020-07-30 16:12:00.000000 | 1 | admin | Corley | XXX | 1 | 1 | 2020-07-20 10:12:00.000000 | Corley | 2020-07-15 | female | 13311111111 | 123@123.com | 0 | 5+----+--------------------------------------------------------------------------------+----------------------------+--------------+----------+------------+-----------+----------+-----------+----------------------------+--------+------------+--------+-------------+-------------+-----------+ 61 row in set (0.01 sec) 7

此时修改数据演示如下: django personal center update userinfo

显然,刷新页面,数据已经修改,再查询数据据库,如下:

1+----+--------------------------------------------------------------------------------+----------------------------+--------------+----------+------------+-----------+----------+-----------+----------------------------+---------+------------+--------+-------------+-------------+-----------+ 2| id | password | last_login | is_superuser | username | first_name | last_name | is_staff | is_active | date_joined | name | birthday | gender | mobile | email | is_delete | 3+----+--------------------------------------------------------------------------------+----------------------------+--------------+----------+------------+-----------+----------+-----------+----------------------------+---------+------------+--------+-------------+-------------+-----------+ 4| 1 | pbkdf2_sha256$180000$wpfCm77Dcpee$rHfFjBNZ2SzLLHdd0ZtbiIRqNB86VvgwTJv6ZCXTbfk= | 2020-07-30 16:12:00.000000 | 1 | admin | Corley | XXX | 1 | 1 | 2020-07-20 10:12:00.000000 | Corley2 | 2020-07-30 | male | 13311111111 | 124@123.com | 0 | 5+----+--------------------------------------------------------------------------------+----------------------------+--------------+----------+------------+-----------+----------+-----------+----------------------------+---------+------------+--------+-------------+-------------+-----------+ 61 row in set (0.00 sec) 7

也印证了数据已经被修改。

说明: 之前在前端测试时,发现用户登录后5分钟左右后登录状态就失效,需要重新登录才能正常访问,我就很郁闷了,明明已经设置JWT过期时间为7天了,怎么没效果啊,今天再去仔细看了看设置,看来确实是我错了,我设置的是JWT_REFRESH_EXPIRATION_DELTA为7天,也就是在这个时间段内刷新JWT可以保持登录状态,而不是我所认为的过期时间,我需要设置的是JWT_EXPIRATION_DELTA,这才是真正的JWT过期的时间,JWT过期后,只要还在设置的刷新过期时间之内,就可以刷新JWT以继续保持登录状态,具体可参考博文https://www.jianshu.com/p/a60efb8bac35,现在我的JWT配置如下:

1# JWT配置 2JWT_AUTH = { 3 # 过期时间 4 'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), 5 # 刷新过期时间 6 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=30), 7 # 请求头前缀 8 'JWT_AUTH_HEADER_PREFIX': 'JWT', 9}

三、用户收藏功能完成

之前在商品详情页已经实现了用户收藏的部分功能,即在商品详情页添加和删除收藏,这里在用户中心完善用户收藏功能。

为了在用户中心显示已收藏商品的具体信息,在apps/user_operation/serializers.py中定义嵌套序列化如下:

1class UserFavDetailSerializer(serializers.ModelSerializer): 2 goods = GoodsSerializer() 3 4 class Meta: 5 model = UserFav 6 fields = ['id', 'goods']

视图完善如下:

1class UserFavViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): 2 ''' 3 list: 4 用户收藏列表 5 create: 6 创建用户收藏 7 retrieve: 8 用户收藏详情 9 destroy: 10 删除用户收藏 11 ''' 12 permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 13 serializer_class = UserFavSerializer 14 authentication_classes = [JSONWebTokenAuthentication, SessionAuthentication] 15 lookup_field = 'goods_id' 16 17 def get_queryset(self): 18 return UserFav.objects.filter(user=self.request.user, is_delete=False) 19 20 def get_serializer_class(self): 21 '''动态设置序列化''' 22 if self.action == 'list': 23 return UserFavDetailSerializer 24 elif self.action == 'create': 25 return UserFavSerializer 26 return UserFavSerializer

进行测试如下: django personal center favs api

前端src/views/member/collection.vue如下:

1<tr v-for="(item,index) in collections"> 2 <td bgcolor="#ffffff"> 3 <router-link :to="'/app/home/productDetail/'+item.goods.id" class="f6" target="_blank">{{item.goods.name}}</router-link> 4 </td> 5 <td bgcolor="#ffffff">本店价<span class="goods-price">¥{{item.goods.shop_price}}元</span> 6 </td> 7 <td align="center" bgcolor="#ffffff"> 8 <a class="f6" @click="deletePro(index, item.goods.id)">删除</a> 9 </td> 10</tr> 11 12created () { 13 this.getCollection(); 14}, 15 16getCollection () { //获取收藏列表 17 getAllFavs().then((response)=> { 18 this.collections = response.data; 19 }).catch(function (error) { 20 console.log(error); 21 }); 22}, 23 24deletePro (index, id) { //删除收藏商品 25 alert('您确定要从收藏夹中删除选定的商品吗?'); 26 delFav(id).then((response)=> { 27 this.collections.splice(index,1); 28 alert('已删除商品'); 29 }).catch(function (error) { 30 console.log(error); 31 }); 32}

可以看到,初始化时先调用getCollection()方法获取收藏,调用了getAllFavs接口,得到数据之后通过for循环显示出来;在删除时调用deletePro(index, item.goods.id)方法,调用了delFav接口,api.js修改如下:

1//收藏 2export const addFav = params => { return axios.post(`${local_host}/userfavs/`, params) } 3 4//取消收藏 5export const delFav = goodsId => { return axios.delete(`${local_host}/userfavs/`+goodsId+'/') } 6 7export const getAllFavs = () => { return axios.get(`${local_host}/userfavs/`) } 8 9//判断是否收藏 10export const getFav = goodsId => { return axios.get(`${local_host}/userfavs/`+goodsId+'/') }

演示如下: django personal center favs operate

再查询数据库如下:

1+----+----------------------------+-----------+----------+---------+ 2| id | add_time | is_delete | goods_id | user_id | 3+----+----------------------------+-----------+----------+---------+ 4| 1 | 2020-07-29 17:02:39.893993 | 0 | 25 | 1 | 5| 2 | 2020-07-29 17:02:49.268221 | 0 | 15 | 1 | 6| 3 | 2020-07-29 17:02:57.410071 | 0 | 5 | 1 | 7| 6 | 2020-07-29 18:23:00.000000 | 0 | 3 | 1 | 8+----+----------------------------+-----------+----------+---------+ 94 rows in set (0.01 sec) 10

显然,收藏数据同步。

四、用户留言功能实现

用户留言包括添加、获取和删除等功能。

先实现添加功能,序列化apps/user_operation/serializers.py如下:

1class LeavingMessageSerializer(serializers.ModelSerializer): 2 user = serializers.HiddenField(default=serializers.CurrentUserDefault()) 3 4 class Meta: 5 model = UserLeavingMessage 6 fields = ['id', 'user', 'message_type', 'subject', 'message', 'file']

视图定义如下:

1class LeavingMessageViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet): 2 ''' 3 list: 4 留言列表 5 create: 6 添加留言 7 delete: 8 删除留言 9 ''' 10 11 permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 12 authentication_classes = [JSONWebTokenAuthentication, SessionAuthentication] 13 serializer_class = LeavingMessageSerializer 14 15 def get_queryset(self): 16 return UserLeavingMessage.objects.filter(user=self.request.user, is_delete=False)

配置路由如下:

1# 配置留言路由 2router.register(r'messages', LeavingMessageViewSet, basename='messages')

进行测试如下: django personal center message api

显然,添加留言成功,再查看数据库:

1+----+--------------+--------------+--------------------------------------+------------------+----------------------------+-----------+---------+ 2| id | message_type | subject | message | file | add_time | is_delete | user_id | 3+----+--------------+--------------+--------------------------------------+------------------+----------------------------+-----------+---------+ 4| 1 | 4 | 售后服务 | 售后服务售后服务售后服务 | 客户服务.jpg | 2020-07-30 17:51:15.337881 | 0 | 1 | 5+----+--------------+--------------+--------------------------------------+------------------+----------------------------+-----------+---------+ 61 row in set (0.00 sec) 7

留言还有一个add_time字段,但是希望不手动输入时间、而是自动生成,因此需要定义覆盖add_time字段,并且需要设置read_only属性,表示add_time字段只返回而不提交,如下:

1class LeavingMessageSerializer(serializers.ModelSerializer): 2 user = serializers.HiddenField(default=serializers.CurrentUserDefault()) 3 add_time = serializers.DateTimeField(read_only=True) 4 5 class Meta: 6 model = UserLeavingMessage 7 fields = ['id', 'user', 'message_type', 'subject', 'message', 'file', 'add_time']

read_only属性包含在API输出中,但在创建或更新操作期间不应包含在输入中,设置为True以确保序列化表示形式时使用该字段,而在反序列化期间创建或更新实例时不使用该字段。

此时再进行测试如下: django personal center message api addtime

可以看到,此时显示出add_time字段,但是并不需要提交时间。

前端src/views/member/message.vue如下:

1<li v-for="(item,index) in messageAll"> 2 <div> 3 <span v-if="item.message_type===1">留言:</span> 4 <span v-if="item.message_type===2">投诉:</span> 5 <span v-if="item.message_type===3">询问:</span> 6 <span v-if="item.message_type===4">售后:</span> 7 <span v-if="item.message_type===5">求购:</span> 8 <span>{{item.subject}}</span> 9 <span>({{item.add_time}})</span> 10 </div> 11 <div> 12 {{item.message}} 13 </div> 14 <div> 15 <a @click="deleteMessage(index, item.id)">删除</a> 16 <a :href="(item.file)">查看上传的文件</a> 17 18 </div> 19 20</li> 21 22<form action="" method="post" enctype="multipart/form-data" name="formMsg"> 23 <table width="100%" border="0" cellpadding="3"> 24 <tbody><tr> 25 <td align="right">留言类型:</td> 26 <td> 27 <input type="radio" id="one" value="1" v-model="message_type"> 28 <label for="one">留言</label> 29 <input type="radio" id="two" value="2" v-model="message_type"> 30 <label for="two">投诉</label> 31 <input type="radio" id="three" value="3" v-model="message_type"> 32 <label for="three">询问</label> 33 <input type="radio" id="four" value="4" v-model="message_type"> 34 <label for="four">售后</label> 35 <input type="radio" id="five" value="5" v-model="message_type"> 36 <label for="five">求购</label> 37 38 <!-- <input name="msg_type" type="radio" value="0" checked="checked"> 39 留言 <input type="radio" name="msg_type" value="1"> 40 投诉 <input type="radio" name="msg_type" value="2"> 41 询问 <input type="radio" name="msg_type" value="3"> 42 售后 <input type="radio" name="msg_type" value="4"> 43 求购 --> 44 </td> 45 </tr> 46 <tr> 47 <td align="right">主题:</td> 48 <td><input name="msg_title" type="text" size="30" class="inputBg" v-model="subject"></td> 49 </tr> 50 <tr> 51 <td align="right" valign="top">留言内容:</td> 52 <td><textarea name="msg_content" cols="50" rows="4" wrap="virtual" class="B_blue" v-model="message"></textarea></td> 53 </tr> 54 <tr> 55 <td align="right">上传文件:</td> 56 <td><input type="file" name="message_img" size="45" class="inputBg" @change="preview"></td> 57 </tr> 58 <tr> 59 <td>&nbsp;</td> 60 <td><input type="hidden" name="act" value="act_add_message"> 61 <!-- <input type="submit" value="提 交" class="bnt_bonus"> --> 62 <a class="btn_blue_1" @click="submitMessage">提交</a> 63 </td> 64 </tr> 65 <tr> 66 <td>&nbsp;</td> 67 <td> 68 <font color="red">小提示:</font><br> 69 您可以上传以下格式的文件:<br>gif、jpg、png、word、excel、txt、zip、ppt、pdf </td> 70 </tr> 71 </tbody></table> 72</form> 73 74created () { 75 this.getMessage(); 76}, 77 78submitMessage () { //提交留言 79 const formData = new FormData(); 80 formData.append('file',this.file); 81 formData.append('subject',this.subject); 82 formData.append('message',this.message); 83 formData.append('message_type',this.message_type); 84 addMessage(formData).then((response)=> { 85 this.getMessage(); 86 87 }).catch(function (error) { 88 console.log(error); 89 }); 90}, 91getMessage () { //获取留言 92 getMessages().then((response)=> { 93 console.log(response.data); 94 this.messageAll = response.data; 95 }).catch(function (error) { 96 console.log(error); 97 }); 98}, 99deleteMessage (index, id) { // 删除留言 100 delMessages(id).then((response)=> { 101 alert("删除成功") 102 this.messageAll.splice(index,1); 103 }).catch(function (error) { 104 console.log(error); 105 }); 106},

可以看到,在初始化时调用getMessage()方法,并调用getMessage接口,获取到数据后头盖骨for循环展示出来;在新增留言时,调用submitMessage()方法,并调用addMessage接口提交;删除留言时调用deleteMessage(index, id)方法,调用delMessages接口实现,api.js修改如下:

1//获取留言 2export const getMessages = () => {return axios.get(`${local_host}/messages/`)} 3 4//添加留言 5export const addMessage = params => {return axios.post(`${local_host}/messages/`, params, {headers:{ 'Content-Type': 'multipart/form-data' }})} 6 7//删除留言 8export const delMessages = messageId => {return axios.delete(`${local_host}/messages/`+messageId+'/')}

在新增留言时,需要上传文件,从API中可以看到,提交新增的留言时,在Header中增加了Content-Type为multipart/form-data,来支持上传文件,同时DRF提供了MultiPartParser类,来解析多部分HTML表单内容,支持文件上传。

进行测试如下: django personal center message add delete

显然,操作成功。

五、用户收货地址功能开发

在user_operation中开发收货地址功能。

先在models.py中修改UserAddress模型如下:

1class UserAddress(models.Model): 2 '''用户收货地址''' 3 user = models.ForeignKey(User, verbose_name='用户', null=True, on_delete=models.SET_NULL) 4 province = models.CharField(max_length=50, default='', verbose_name='省份') 5 city = models.CharField(max_length=50, default='', verbose_name='城市') 6 district = models.CharField(max_length=80, default='', verbose_name='区域') 7 address = models.CharField(max_length=100, default='', verbose_name='详细地址') 8 signer_name = models.CharField(max_length=20, default='', verbose_name='签收人') 9 signer_mobile = models.CharField(max_length=11, default='', verbose_name='联系电话') 10 11 add_time = models.DateTimeField(default=datetime.now, verbose_name=u'添加时间') 12 is_delete = models.BooleanField(default=False, verbose_name='是否删除') 13 14 class Meta: 15 verbose_name = '收货地址' 16 verbose_name_plural = verbose_name 17 18 def __str__(self): 19 return self.address

修改之后映射数据库,然后定义序列化如下:

1class AddressSerializer(serializers.ModelSerializer): 2 user = serializers.HiddenField(default=serializers.CurrentUserDefault()) 3 add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M') 4 5 class Meta: 6 model = UserAddress 7 fields = ['id', 'user', 'province', 'city', 'district', 'address', 'signer_name', 'add_time', 'signer_mobile']

再定义视图如下:

1class AddressViewSet(viewsets.ModelViewSet): 2 ''' 3 收货地址管理 4 list: 5 收货地址列表 6 create: 7 新建收货地址 8 update: 9 更新收货地址 10 delete: 11 删除收货地址 12 ''' 13 14 permission_classes = [IsAuthenticated, IsOwnerOrReadOnly] 15 authentication_classes = [JSONWebTokenAuthentication, SessionAuthentication] 16 serializer_class = AddressSerializer 17 18 def get_queryset(self): 19 return UserAddress.objects.filter(user=self.request.user, is_delete=False)

可以看到,AddressViewSet继承自viewsets.ModelViewSet,大大减少了之前继承自mixins.ListModelMixin, mixins.CreateModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet的代码量,但是可以达到一样的效果。

配置路由如下:

1# 配置收货地址路由 2router.register(r'address', AddressViewSet, basename='address')

进行测试如下: django personal center address api

创建数据成功。

前端src/views/member/receive.vue如下:

1<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#dddddd" v-for="(item, index) in receiveInfoArr"> 2 <tbody> 3 <tr> 4 <td align="right" bgcolor="#ffffff">配送区域:</td> 5 <td colspan="3" align="left" bgcolor="#ffffff"> 6 <div class="addr" @click="bubble(index)"> 7 <v-distpicker :province="item.province" :city="item.city" :area="item.district" @province="updateProvince" @city="updateCity" @area="updateArea"></v-distpicker> 8 </div> 9 </td> 10 </tr> 11 <tr> 12 <td align="right" bgcolor="#ffffff">收货人姓名:</td> 13 <td align="left" bgcolor="#ffffff"><input name="consignee" type="text" class="inputBg" id="consignee_0" value="ssss" v-model="item.signer_name"> 14 <span :class = "{error:item.signer_name==''}">(必填)</span> 15 </td> 16 17 </tr> 18 <tr> 19 <td align="right" bgcolor="#ffffff">详细地址:</td> 20 <td align="left" bgcolor="#ffffff"><input name="address" type="text" class="inputBg" id="address_0" v-model="item.address"> 21 <span :class = "{error:item.address==''}">(必填)</span></td> 22 </tr> 23 <tr> 24 25 <td align="right" bgcolor="#ffffff">手机:</td> 26 <td align="left" bgcolor="#ffffff"><input name="mobile" type="text" class="inputBg" id="mobile_0" v-model="item.signer_mobile"><span :class = "{error:item.signer_mobile==''}">(必填)</span></td> 27 </tr> 28 <tr> 29 <td align="right" bgcolor="#ffffff">&nbsp;</td> 30 <td colspan="3" align="center" bgcolor="#ffffff"> 31 <!-- <input type="submit" name="submit" class="bnt_blue_2" value="新增收货地址"> --> 32 33 <button class="bnt_blue_2" @click="confirmUpdate(item.id, index)">确定修改</button> 34 <button class="bnt_blue_2" @click="deleteInfo(item.id)">删除</button> 35 <!-- <input type="hidden" name="act" value="act_edit_address"> 36 <input name="address_id" type="hidden" value="320"> --> 37 </td> 38 </tr> 39 </tbody> 40</table> 41 42<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#dddddd"> 43 <tbody> 44 <tr> 45 <td align="right" bgcolor="#ffffff">配送区域:</td> 46 <td colspan="3" align="left" bgcolor="#ffffff"> 47 <div class="addr"> 48 <!-- <v-distpicker :placeholder="newInfo.dist" @province="getProvince" @city="getCity" @selected="getArea"></v-distpicker> --> 49 <v-distpicker :province="newInfo.province" :city="newInfo.city" :area="newInfo.district" @province="getProvince" @city="getCity" @area="getArea"></v-distpicker> 50 </div> 51 </td> 52 </tr> 53 <tr> 54 <td align="right" bgcolor="#ffffff">收货人姓名:</td> 55 <td align="left" bgcolor="#ffffff"><input name="consignee" type="text" class="inputBg" id="consignee_0" value="ssss" v-model="newInfo.signer_name"> 56 <span :class = "{error:newInfo.signer_name==''}">(必填)</span> </td> 57 58 </tr> 59 <tr> 60 <td align="right" bgcolor="#ffffff">详细地址:</td> 61 <td align="left" bgcolor="#ffffff"><input name="address" type="text" class="inputBg" id="address_0" v-model="newInfo.address"> 62 <span :class = "{error:newInfo.address==''}">(必填)</span></td> 63 </tr> 64 <tr> 65 66 <td align="right" bgcolor="#ffffff">手机:</td> 67 <td align="left" bgcolor="#ffffff"><input name="mobile" type="text" class="inputBg" id="mobile_0" v-model="newInfo.signer_mobile"><span :class = "{error:newInfo.signer_mobile==''}">(必填)</span></td> 68 </tr> 69 <tr> 70 <td align="right" bgcolor="#ffffff">&nbsp;</td> 71 <td colspan="3" align="center" bgcolor="#ffffff"> 72 <!-- <input type="submit" name="submit" class="bnt_blue_2" value="新增收货地址"> --> 73 <button class="bnt_blue_2" @click="addReceive">新增收货地址</button> 74 75 <!-- <input type="hidden" name="act" value="act_edit_address"> 76 <input name="address_id" type="hidden" value="320"> --> 77 </td> 78 </tr> 79 </tbody> 80</table> 81 82created () { 83 this.getReceiveInfo(); 84}, 85 86updateProvince (data) { 87 this.receiveInfoArr[this.currentIndex].province = data.value; 88}, 89updateCity (data) { 90 this.receiveInfoArr[this.currentIndex].city = data.value; 91}, 92updateArea (data) { 93 this.receiveInfoArr[this.currentIndex].district = data.value; 94}, 95 96 97getProvince (data) { 98 this.newInfo.province = data.value; 99}, 100getCity (data) { 101 this.newInfo.city = data.value; 102}, 103getArea (data) { 104 this.newInfo.district = data.value; 105}, 106getReceiveInfo() { //获取收件人信息 107 getAddress().then((response)=> { 108 console.log(response.data); 109 this.receiveInfoArr = response.data; 110 111 }).catch(function (error) { 112 console.log(error); 113 }); 114 115}, 116 117addReceive () { //提交收获信息 118 addAddress(this.newInfo).then((response)=> { 119 alert('添加成功'); 120 // 重置新的 121 this.getReceiveInfo(); 122 this.newInfo = Object.assign({}, this.newInfoEmpty); 123 124 }).catch(function (error) { 125 console.log(error); 126 }); 127}, 128confirmUpdate (id, index) { // 更新收获信息 129 updateAddress(id, this.receiveInfoArr[index]).then((response)=> { 130 alert('修改成功'); 131 this.getReceiveInfo(); 132 }).catch(function (error) { 133 console.log(error); 134 }); 135 136}, 137deleteInfo (id, index) { // 删除收获人信息 138 delAddress(id).then((response)=> { 139 alert('删除成功'); 140 this.getReceiveInfo(); 141 }).catch(function (error) { 142 console.log(error); 143 }); 144}

可以看到,在初始化时调用getReceiveInfo()方法获取收货地址信息,调用了getAddress接口,获取到数据后通过for循环显示到前端;修改每个字段分别调用相应的update方法,并调用confirmUpdate (id, index)方法更新数据,最后调用updateAddress接口实现更新;增加收货地址调用addReceive()方法,并调用updateAddress接口实现新增数据;删除数据调用deleteInfo(id, index)方法,并通过delAddress接口实现删除。

api.js中对应接口修改如下:

1//添加收货地址 2export const addAddress = params => {return axios.post(`${local_host}/address/`, params)} 3 4//删除收货地址 5export const delAddress = addressId => {return axios.delete(`${local_host}/address/`+addressId+'/')} 6 7//修改收货地址 8export const updateAddress = (addressId, params) => {return axios.patch(`${local_host}/address/`+addressId+'/', params)} 9 10//获取收货地址 11export const getAddress = () => {return axios.get(`${local_host}/address/`)}

演示如下: django personal center address add delete update get 显然,已经可以正常增、删、改、查收货地址。

本文原文首发来自博客专栏Python Web开发实战,由本人转发至https://www.helloworld.net/p/690vHrDTw9Ig9,其他平台均属侵权,可点击https://blog.csdn.net/CUFEECR/article/details/107699905查看原文,也可点击https://blog.csdn.net/CUFEECR浏览更多优质原创内容。

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )

KVM调整cpu和内存

一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid