专题:Vue+Django REST framework前后端分离生鲜电商
Vue+Django REST framework 打造前后端分离的生鲜电商项目(慕课网视频)。
Github地址:https://github.com/xyliurui/DjangoOnlineFreshSupermarket ;
Django版本:2.2、djangorestframework:3.9.2。
更多内容请点击 我的博客 查看,欢迎来访。
对于收货地址,需要实现收货地址的增、删、改、查,所以需要继承的类有mixins.ListModelMixin, mixins.UpdateModelMixin, mixins.DestroyModelMixin, mixins.CreateModelMixin, viewsets.GenericViewSet
,而这些类也可以合并为一个viewsets.ModelViewSet
,点击去就可以看到继承关系:
编辑 apps/user_operation/views.py
class AddressViewSet(viewsets.ModelViewSet):
"""
收货地址管理
list:
获取收货地址
create:
添加收货地址
update:
更新收货地址
delete:
删除收货地址
"""
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) # 用户必须登录才能访问
authentication_classes = (JWTAuthentication, SessionAuthentication) # 配置登录认证:支持JWT认证和DRF基本认证
permission_classes
和authentication_classes
直接复制上面的即可,因为也需要用户登录认证才能完成的。
在前端上,用户的收货地址分为省市区
而之前我们定义的models中定义是不够的,原来的models为:
class UserAddress(models.Model):
"""
用户收货地址
"""
user = models.ForeignKey(User, verbose_name='用户', help_text='用户', on_delete=models.CASCADE, related_name='addresses')
district = models.CharField(max_length=100, default='', verbose_name='区域', help_text='区域')
address = models.CharField(max_length=200, default='', verbose_name='收货地址', help_text='收货地址')
signer_name = models.CharField(max_length=20, default='', verbose_name='签收人', help_text='签收人')
signer_mobile = models.CharField(max_length=11, verbose_name='联系电话', help_text='联系电话')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
class Meta:
verbose_name_plural = verbose_name = '收货地址'
def __str__(self):
return self.address
所以需要进行修改,添加province
和city
两个字段
class UserAddress(models.Model):
"""
用户收货地址
"""
user = models.ForeignKey(User, verbose_name='用户', help_text='用户', on_delete=models.CASCADE, related_name='addresses')
province = models.CharField(max_length=100, default='', verbose_name='省份', help_text='省份')
city = models.CharField(max_length=100, default='', verbose_name='城市', help_text='城市')
district = models.CharField(max_length=100, default='', verbose_name='区域', help_text='区域')
address = models.CharField(max_length=200, default='', verbose_name='收货地址', help_text='收货地址')
signer_name = models.CharField(max_length=20, default='', verbose_name='签收人', help_text='签收人')
signer_mobile = models.CharField(max_length=11, verbose_name='联系电话', help_text='联系电话')
add_time = models.DateTimeField(auto_now_add=True, verbose_name='添加时间')
class Meta:
verbose_name_plural = verbose_name = '收货地址'
def __str__(self):
return self.address
添加完成后一定要执行makemigrations
和migrate
。
编写收货地址序列化类,编辑 apps/user_operation/serializers.py 添加
from .models import UserFav, UserLeavingMessage, UserAddress
class AddressSerializer(serializers.ModelSerializer):
user = serializers.HiddenField(
default=serializers.CurrentUserDefault() # 表示user为隐藏字段,默认为获取当前登录用户
)
class Meta:
model = UserAddress
fields = ('id', 'user', 'province', 'city', 'district', 'address', 'signer_name', 'signer_mobile')
添加序列化类AddressSerializer
from .serializers import UserFavSerializer, UserFavListSerializer, UserLeavingMessageSerializer, AddressSerializer
from .models import UserFav, UserLeavingMessage, UserAddress
class AddressViewSet(viewsets.ModelViewSet):
"""
收货地址管理
list:
获取收货地址
create:
添加收货地址
update:
更新收货地址
delete:
删除收货地址
"""
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) # 用户必须登录才能访问
authentication_classes = (JWTAuthentication, SessionAuthentication) # 配置登录认证:支持JWT认证和DRF基本认证
queryset = UserAddress.objects.all()
serializer_class = AddressSerializer
def get_queryset(self):
return self.queryset.filter(user=self.request.user)
编辑 DjangoOnlineFreshSupermarket/urls.py ,注册address
这个url
from user_operation.views import UserFavViewSet, UserLeavingMessageViewSet, AddressViewSet
router.register(r'address', AddressViewSet, base_name='address') # 用户收货地址
查看Server是否已经重启。
访问 http://127.0.0.1:8000/docs/#address 可以看到新增的API
在create
中创建一个收货地址
添加完信息后,点击Send Request,就可以在右上角看到返回的数据
在list
中点击Send Request就可以看到返回的列表信息
api放在 src/api/api.js 中
//添加收货地址
export const addAddress = params => {
return axios.post(`${local_host}/address/`, params)
};
//删除收货地址
export const delAddress = addressId => {
return axios.delete(`${local_host}/address/` + addressId + '/')
};
//修改收货地址
export const updateAddress = (addressId, params) => {
return axios.patch(`${local_host}/address/` + addressId + '/', params)
};
//获取收货地址
export const getAddress = () => {
return axios.get(`${local_host}/address/`)
};
Vue收获地址管理的页面在 src/views/member/receive.vue 中
当进入这个组件后,会调用getReceiveInfo()
created() {
this.getReceiveInfo();
},
然后调用getAddress()
,也就是请求getAddress
的api
getReceiveInfo() { //获取收件人信息
getAddress().then((response) => {
//console.log(response.data);
this.receiveInfoArr = response.data;
}).catch(function (error) {
console.log(error);
});
},
获取到数据之后,传递给receiveInfoArr
,然后遍历得到所有地址列表
<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#dddddd" v-for="(item, index) in receiveInfoArr">
<tbody>
<tr>
<td align="right" bgcolor="#ffffff">配送区域:td>
<td colspan="3" align="left" bgcolor="#ffffff">
<div class="addr" @click="bubble(index)">
<v-distpicker :province="item.province" :city="item.city" :area="item.district" @province="updateProvince" @city="updateCity" @area="updateArea">v-distpicker>
div>
td>
tr>
<tr>
<td align="right" bgcolor="#ffffff">收货人姓名:td>
<td align="left" bgcolor="#ffffff"><input name="consignee" type="text" class="inputBg" id="consignee_0" value="ssss" v-model="item.signer_name">
<span :class="{error:item.signer_name==''}">(必填)span>
td>
tr>
<tr>
<td align="right" bgcolor="#ffffff">详细地址:td>
<td align="left" bgcolor="#ffffff"><input name="address" type="text" class="inputBg" id="address_0" v-model="item.address">
<span :class="{error:item.address==''}">(必填)span>td>
tr>
<tr>
<td align="right" bgcolor="#ffffff">手机:td>
<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>
tr>
<tr>
<td align="right" bgcolor="#ffffff"> td>
<td colspan="3" align="center" bgcolor="#ffffff">
<button class="bnt_blue_2" @click="confirmUpdate(item.id, index)">确定修改button>
<button class="bnt_blue_2" @click="deleteInfo(item.id)">删除button>
td>
tr>
tbody>
table>
访问 http://127.0.0.1:8080/#/app/home/member/receive 可以看到前端展示的收货地址
添加完成之后,可以看到列表自动刷新了
<table width="100%" border="0" cellpadding="5" cellspacing="1" bgcolor="#dddddd">
<tbody>
<tr>
<td align="right" bgcolor="#ffffff">配送区域:td>
<td colspan="3" align="left" bgcolor="#ffffff">
<div class="addr">
<v-distpicker :province="newInfo.province" :city="newInfo.city" :area="newInfo.district" @province="getProvince" @city="getCity" @area="getArea">v-distpicker>
div>
td>
tr>
<tr>
<td align="right" bgcolor="#ffffff">收货人姓名:td>
<td align="left" bgcolor="#ffffff"><input name="consignee" type="text" class="inputBg" id="consignee_0" value="ssss" v-model="newInfo.signer_name">
<span :class="{error:newInfo.signer_name==''}">(必填)span>td>
tr>
<tr>
<td align="right" bgcolor="#ffffff">详细地址:td>
<td align="left" bgcolor="#ffffff"><input name="address" type="text" class="inputBg" id="address_0" v-model="newInfo.address">
<span :class="{error:newInfo.address==''}">(必填)span>td>
tr>
<tr>
<td align="right" bgcolor="#ffffff">手机:td>
<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>
tr>
<tr>
<td align="right" bgcolor="#ffffff"> td>
<td colspan="3" align="center" bgcolor="#ffffff">
<button class="bnt_blue_2" @click="addReceive">新增收货地址button>
td>
tr>
tbody>
table>
当用户点击 新增收货地址 ,会调用addReceive()
函数
addReceive() { //提交收获信息
addAddress(this.newInfo).then((response) => {
alert('添加成功');
// 重置新的
this.getReceiveInfo();
this.newInfo = Object.assign({}, this.newInfoEmpty);
}).catch(function (error) {
console.log(error);
});
},
然后请求addAddress
api,请求成功后,请求getReceiveInfo()
刷新收货地址列表,清空输入框
当用户点击删除时,调用
deleteInfo(id, index)
函数
deleteInfo(id, index) { // 删除收获人信息
delAddress(id).then((response) => {
alert('删除成功');
this.getReceiveInfo();
}).catch(function (error) {
console.log(error);
});
}
之后调用delAddress(id)
api进行地址删除,删除成功后弹框提示,并刷新收货地址列表。
当用户点击会调用
confirmUpdate(id, index)
函数
confirmUpdate(id, index) { // 更新收获信息
updateAddress(id, this.receiveInfoArr[index]).then((response) => {
alert('修改成功');
this.getReceiveInfo();
}).catch(function (error) {
console.log(error);
});
},
之后调用updateAddress(id, this.receiveInfoArr[index])
api进行地址更新,更新成功后弹框提示,并刷新收货地址列表。