左侧商品轮播图 & 商品详情 描述,运费,库存量
热门商品放在另外一个 url
只需要在继承的里面添加这个 mixins.RetrieveModelMixin 就可以了
class GoodsAllViewSet(CacheResponseMixin,
mixins.ListModelMixin,
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
查看Serializer,将其中的外键指向的Goodsimage
如何执行外键型的字段Serializer呢?进行嵌套的使用。
class GoodsImageSerializer(serializers.ModelSerializer):
class Meta:
model = GoodsImage
fields = ("image", )
class GoodsSerializer(serializers.ModelSerializer):
"""
list all goods
"""
category = CategorySerializer()
images = GoodsImageSerializer(many=True) #这里嵌套了商品图片
class Meta:
model = Goods
fields = "__all__"
将商品详情页完成后就可以来分析我们vue的源码。组件是productDetail productDetail.vue
created () {
this.productId = this.$route.params.productId;
var productId = this.productId
if(cookie.getCookie('token')){
getFav(productId).then((response)=> {
this.hasFav = true
}).catch(function (error) {
console.log(error);
});
}
this.getDetails();
},
列表页跳转到某一个详情页的时候,vue router里面有一个productId
会通过router里面的productdetail传递进来
src/router/index.js
实现:
path: 'productDetail/:productId',
name: 'productDetail',
component: productDetail,
meta: {
title: '商品详情',
need_log: false
}
商品goods中有一个字段是是否热销。获取热销产品,filter中加一个ishot
goods/filters.py
中可以看到已经添加了
src/views/productDetail/hotSales.vue
:
它在create的时候调用了getHotSales
getHotSales() { //请求热卖商品
getGoods({
is_hot:true
})
.then((response)=> {
console.log(response.data)
this.hotProduct = response.data.results;
}).catch(function (error) {
console.log(error);
});
}
实际上还是调用了getGoods接口,只是设置了参数is_hot为true而已
返回的json值会被放入response的data里面,而我们的数据放在result里面
返回的json格式:
{
"count": 3,
"next": null,
"previous": null,
"results": [
{
"id": 102,
"category": {
"id": 55,
"name": "方便速食",
"code": "方便速食",
"desc": "",
"category_type": 2,
"is_tab": false,
"add_time": "2018-02-14T03:45:05.659267",
"parent_category": 40
},
}
}
这属于用户操作的功能,所以我们将操作写在 user_operation 中
收藏的接口既要继承 viewset,添加收藏create,删除收藏destroy
user_operation/views.py
class UserFavViewSet(viewsets.GenericViewSet,
mixins.CreateModelMixin,
mixins.ListModelMixin,
mixins.DestroyModelMixin):
"""
list: 用户收藏功能
retrieve: 判断某个商品是否已经收藏
create: 收藏商品
"""
# queryset = UserFav.objects.all()
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
# serializer_class = UserFavSerializer
authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
lookup_field = "goods_id"
def get_queryset(self):
return UserFav.objects.filter(user=self.request.user)
def get_serializer_class(self):
if self.action == "list":
return UserFavDetailSerializer
elif self.action == "create":
return UserFavSerializer
return UserFavSerializer
user_operation/serializers.py
class UserFavDetailSerializer(serializers.ModelSerializer):
goods = GoodsSerializer()
class Meta:
model = UserFav
fields = ("goods", "id")
class UserFavSerializer(serializers.ModelSerializer):
"""
默认的用户收藏的序列化
"""
# 默认到当前用户 DRF官网:CurrentUserDefault
user = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)
class Meta:
model = UserFav
validators = [
UniqueTogetherValidator(
queryset=UserFav.objects.all(),
fields=("user", "goods"),
message="已收藏"
)
]
fields = ("user", "goods", "id")
配置相应的url等在urls.py中
# 配置用户收藏的url
router.register(r'userfavs', UserFavViewset, base_name="userfavs"),
如何让Serializer自动帮我们填充当前的user?
http://www.django-rest-framework.org/api-guide/validators/#currentuserdefault
官方文档中
REST框架包含一些在这种情况下可能有用的默认值。
CurrentUserDefault
可用于表示当前用户的默认类。为了使用它,在实例化序列化程序时,'request’必须作为上下文字典的一部分提供。
如果对于一个Serializer我们想为它添加删除的功能,就要将该条记录的id也返回回来
取消收藏就会变得容易。
restful api 删除时要用到的http里面的delete方法。
url格式为
userfavs/id
204代表删除成功,2开头的一般都是操作成功的。
用户反复的对一件商品进行收藏,理论上不应该生成两条收藏关系的记录。
这时候需要django model中的设置参数。
# 多个字段作为一个联合唯一索引
unique_together = ("user", "goods")
如果我们重复了,数据库会给我们抛出异常来
清空原有的表数据,进行makemigration 和 migrate
可以通过navicat查看到我们的唯一索引
{
"non_field_errors": [
"字段 user, goods 必须能构成唯一集合。"
]
}
实际上 validator 中也为我们提供了 UniqueTogetherValidator
在 Serializer 的 meta 信息中你那个自己定义
class Meta:
model = UserFav
validators = [
UniqueTogetherValidator(
queryset=UserFav.objects.all(),
fields=("user", "goods"),
message="已收藏"
)
]
fields = ("user", "goods", "id")
我们的 modelSerializer 和 modelform 一样与 model 紧密联系,所以 model 中的设置它会读取并配置。
这个validate是写在meta信息中的,是因为它不是作用于某一个字段之上了。
400错误,返回的错误消息存放在non_field_errors中。而具体的某一个字段出错,会指明字段的名称。