完整项目地址:https://gitee.com/dadadaliuliuliiu/ShopProject
1.报错:连接不上[2020/4/2 19:36] Upload to shop failed: could not resolve file “sftp://47.105.62.144/”. (Exhausted available authentication methods)
解决:
顶行tools–>development–>configuration–>里面有两个,一个是应用shop,一个是ip47.105.62.144,进行检测Test_Connection,我的是密码不对
2.报错说函数中没有某个方法,点进函数查看,方法是否更新,更改方法名。
3.[Errno 2] No such file or directory: ‘/data/www/ShopProject/app/trade/keys/private_daliu.txt’
原因:可能是写的代码文件没有上传服务器,这里的文件是我从文件夹中直接建立的目录,所以可能不会自动上传。
解决:在pycharm的目录中找到报错文件,右击文件点development–>upload to shop,在运行
4. File “/data/www/ShopProject/app/trade/serializers.py”, line 116, in get_alipay_url
return_url=“http://47.105.62.144:8000/alipay/return/”
ValueError: Not a valid PEM pre boundary
原因:Pycryptodome进行RSA签名,读取文件内的私钥和公钥出错,这里在应用私钥文件、应用公钥文件、支付宝公钥文件里面 内容前后要加上-----BEGIN PUBLIC KEY-----,-----END PUBLIC KEY-----(注意是五个-),我这里出错就是因为写了六个-。
5.问题:在代码没问题运行起来之后,浏览器端访问不了,显示无法访问此网站,可能时阿里云服务器的安全端口没有设置。
解决:登陆阿里云在实例安全组设置8000端口的安全规则,在运行。
序列化
class BannerSerializer(serializers.ModelSerializer):
'''
轮播图
'''
class Meta:
model = Banner
fields = "__all__"
视图类
class BannerViewset(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
首页轮播图
"""
queryset = Banner.objects.all().order_by("index")
serializer_class = BannerSerializer
url配置
# 配置首页轮播图的url
router.register(r'banners', BannerViewset, basename="banners")
测试
tools里面连接服务器后测试:
[root@todolist-server ~]# cd /data/www/ShopProject/
[root@todolist-server ShopProject]# ls
app manage.py
db.sqlite3 media
Django+Vue网上购物商城(七) 用户交易API接口.pdf requirements.txt
Django+Vue网上购物商城(九) 项目细节完善.pdf ShopProject
Django+Vue网上购物商城(八) 项目部署.pdf venv
doc
[root@todolist-server ShopProject]# source venv/bin/activate
(venv) [root@todolist-server ShopProject]# python manage.py runserver 0.0.0.0:8000
此时轮播图为空,去后台添加轮播图来测试
在查看banners信息,轮播图添加成功
1.在首页轮播图API接口完善代码时,TypeError: str returned non-string (type ImageFieldFile)
原因:这里要返回一个图片的名称的字符串 不能是image对象
解决:去goods.models中,修改友好字符串的返回类型:images对象改为返回字符串:return self.image.name
2.如果访问不到可能是本地代码没有上传服务器,访问结果不对可能服务没有更新,需要重启一下服务
在设计Goods model时候有一个字段is_new, 实现这个接口只要在goods/filters/GoodsFilter里面添加一个过滤就可以了。
class GoodsFilter(django_filters.rest_framework.FilterSet):
'''
商品过滤的类
'''
class Meta:
model = Goods
# http://xxxx/goods/?price_min=10&price_max=100
fields = ['price_min', 'price_max','is_hot', 'is_new']
测试
在后台设置几个商品 is_new, 前台访问http://IP/goods进行过滤查看新品
GoodsListViewSet其中继承了mixins.RetrieveModelMixin(获取商品详情), 当用户浏览该商品详情页信息时,商品点击数+1。
我们只要重写他的retrieve方法就可以了。
# app/goods/views.py
class GoodsListViewSet(.....):
# 商品点击数 + 1
def retrieve(self, request, *args, **kwargs):
"""重写retrieve方法, 查看伤情时不仅仅返回商品序列化的信息,还需要修改商品的点击数"""
instance = self.get_object()
# ***************** 增加点击数**************************
instance.click_num += 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
前面已经写了UserFavViewset,其中继承mixins.CreateModelMixin,添加收藏实际就是创建数据库。这里重写它的perform_create方法就可以了。
class UserFavViewset(viewsets.GenericViewSet, mixins.ListModelMixin,
mixins.CreateModelMixin, mixins.DestroyModelMixin):
'''
用户收藏
'''
def perform_create(self, serializer):
# 对象: UserFav商品收藏的对象
instance = serializer.save()
# 获取用户收藏的商品对象
goods = instance.goods
# 更新收藏商品的收藏数
goods.fav_num += 1
# 商品信息修改后保存到数据库中
goods.save()
测试
收藏id=1的商品,然后去goods/1查看此商品的收藏数,收藏数加1
收藏数加1
库存数变化:
1.在购物车中没有这个商品时,增加购物车商品后,goods/ 商品库存减少,
2.在购物车中已经添加了商品时,进入详情页shopcarts/1 更新购物车中的商品,库存也更新。
# app/trade/views.py
'''
# 销售量变化:
# 1. 增加订单并支付成功:
# 库存数变化:
# 1. 购物车添加商品信息: 库存量-购物车数量
# 2. 购物车更新商品数量: - 10 +
# 3. 删除购物车的商品: 库存量增加
'''
class ShoppingCartViewset(viewsets.ModelViewSet):
# ..........
# 库存数-1
def perform_create(self, serializer):
"""重写perform_create方法,商品加入购物车, 存储购物车的商品信息,还要更新商品的库存信息 """
# serializer.save存储的是购物车的数据库模型对象
shopcarts = serializer.save()
# 获取当前购物车的商品对象.
goods = shopcarts.goods
goods.goods_num -= shopcarts.nums
goods.save()
def perform_destroy(self, instance):
# serializer.save存储的是购物车的数据库模型对象 商品名称 - 10 +
shopcarts = instance
# 获取当前购物车的商品对象.
goods = shopcarts.goods
# 购物车里面商品删除, 增加商品的库存量
goods.goods_num += shopcarts.nums
# 一定要将更改的信息存储到数据库中.
goods.save()
# 将购物车对象删除.
instance.delete()
def perform_update(self, serializer):
"""
当购物车商品数量更新时, 更新商品的库存量(可能增加也可能减少)
1. 先获取购物车之前商品的数量. 10
2. 获取购物车现在商品的数量. 9
3. 发现购物车数量减少1 update_nums = 现在的购物车数量-原先的购物车数量 -1
4. 100 更新商品库存量加1 100 - (-1) = 101
"""
# get方法返回的是符合条件的对象, filter返回的是符合条件的列表信息。
old_shopcart_nums = ShoppingCart.objects.get(id=serializer.instance.id).nums # 10
shopcart = serializer.save()
new_shopcart_nums = shopcart.nums # 9
update_nums = new_shopcart_nums - old_shopcart_nums # -1
goods = shopcart.goods # 库存量100
goods.goods_num -= update_nums # 库存量100-(-1) = 101
goods.save()
当原库存为100,加入购物车20个,查看商品库存变为80
进入id=1详情页,删除购物车id=1的商品,查看good商品看库存,增加了20,变为100
1.在服务器上安装redis
这里用阿里的镜像源可以直接yum安装
(venv) [root@todolist-server ShopProject]# yum install redis -y
2.修改redis配置文件
默认绑定的是本机的回环地址127.0.0.1,我们修改为bind 0.0.0.0
这里要注意,配置文件中可能原先有绑定,要先屏蔽掉,一般是后面的会掩盖前面的
(venv) [root@todolist-server ShopProject]#rpm -qc redis #查询redis配置文件位置
/etc/redis.conf
(venv) [root@todolist-server ShopProject]# vim /etc/redis.conf
3.启动redis服务
(venv) [root@todolist-server ShopProject]# systemctl start redis
(venv) [root@todolist-server ShopProject]# systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.
(venv) [root@todolist-server ShopProject]# systemctl status redis
● redis.service - Redis persistent key-value database
Loaded: loaded (/usr/lib/systemd/system/redis.service; enabled; vendor preset: disabled)
Drop-In: /etc/systemd/system/redis.service.d
└─limit.conf
Active: active (running) since Sun 2020-04-05 15:32:28 CST; 24s ago
Main PID: 1729 (redis-server)
CGroup: /system.slice/redis.service
└─1729 /usr/bin/redis-server 0.0.0.0:6379
Apr 05 15:32:28 todolist-server systemd[1]: Starting Redis persistent key-value database...
Apr 05 15:32:28 todolist-server systemd[1]: Started Redis persistent key-value database.
4.查看redis的端口号和绑定的ip
(venv) [root@todolist-server ShopProject]# netstat -antlpe | grep redis
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 996 866105 1729/redis-server 0
5.客户端指令测试redis服务器是否连通
(venv) [root@todolist-server ShopProject]# redis-cli -h 47.105.62.144
47.105.62.144:6379> ping
PONG
47.105.62.144:6379>
为了加速网站的访问速度,将一些数据放到缓存当中,取数据的时候首先去缓存中去,然后再去数据库中取。我们用Redis来实现缓存。
使用django-redis第三方库:http://django-redis-chs.readthedocs.io/zh_CN/latest/#id8 (文档说明)
(venv) [root@todolist-server ShopProject]# pip install django-redis
为了使用django-redis,修改django cache setting
# 跨域
CORS_ORIGIN_ALLOW_ALL = True
# Redis缓存的配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://47.105.62.144:6379/1", # 1,代表数据库名为1
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
(venv) [root@todolist-server ShopProject]# redis-cli -h 47.105.62.144
47.105.62.144:6379> select 1
OK
47.105.62.144:6379[1]> keys *
(empty list or set)
47.105.62.144:6379[1]> keys *
1) ":1:throttle_user_1"
2) ":1:xadmin_themes"
Throttle可以对接口访问的频次进行限制,以减轻服务器的压力。一般用于付费购买次数,投票等场景使用, 防止网络爬虫多频率访问。
官网使用说明:http://www.django-rest-framework.org/api-guide/throttling/
配置文件
REST_FRAMEWORK = {
# 。。。。。。
# 限速设置
'DEFAULT_THROTTLE_CLASSES': (
'rest_framework.throttling.AnonRateThrottle', # 未登陆用户
'rest_framework.throttling.UserRateThrottle' # 登陆用户
),
'DEFAULT_THROTTLE_RATES': {
# *****************测试配置***********************
# 'anon': '3/minute', # 每分钟可以请求3次
# 'user': '5/minute' # 每分钟可以请求五次
# ******************生产环境的配置****************
'anon': '100/day',
'user': '1000/day'
}
}
视图类
class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
"""
list:
返回商品列表数据
retrieve:
返回商品详情数据
"""
# 网站限速
throttle_classes = (UserRateThrottle, AnonRateThrottle)
# Cache requested url for each user for 2 hours
@method_decorator(cache_page(60 * 60 * 2))
@method_decorator(vary_on_cookie)
def retrieve(self, request, *args, **kwargs):
"""重写retrieve方法, 查看伤情时不仅仅返回商品序列化的信息,还需要修改商品的点击数"""
#。。。
@method_decorator(cache_page(5), name='dispatch')
class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
#。。。
将后端API文档47.105.62.144/docs传给前端开发人员