提交 413accc2 编写于 作者: C Corley

V1.8

上级 cfb1fde5
......@@ -154,7 +154,15 @@ REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
]
],
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '30/hour',
'user': '500/hour'
}
}
# 自定义用户认证配置
......@@ -183,4 +191,20 @@ app_private_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/app_private.txt')
alipay_public_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/ali_public.txt')
ali_app_id = "2021000116666333"
return_url = 'http://127.0.0.1:8000/alipay/return/'
notify_url = 'http://127.0.0.1:8000/alipay/return/'
\ No newline at end of file
notify_url = 'http://127.0.0.1:8000/alipay/return/'
# drf-extensions配置
REST_FRAMEWORK_EXTENSIONS = {
'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60 * 15
}
# Redis缓存配置
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
\ No newline at end of file
......@@ -16,7 +16,6 @@ Including another URLconf
# from django.contrib import admin
from django.conf.urls import url, include
from django.views.static import serve
from django.views.generic import TemplateView
from django.views.generic.base import RedirectView
from rest_framework.documentation import include_docs_urls
from rest_framework.routers import DefaultRouter
......@@ -25,7 +24,7 @@ from rest_framework_jwt.views import obtain_jwt_token
import xadmin
from .settings import MEDIA_ROOT
from goods.views import GoodsListViewSet, CategoryViewSet
from goods.views import GoodsListViewSet, CategoryViewSet, BannerViewSet, IndexCategoryViewSet
from users.views import SmsCodeViewSet, UserViewSet
from user_operation.views import UserFavViewSet, LeavingMessageViewSet, AddressViewSet
from trade.views import ShoppingCartViewSet, OrderViewSet, AliPayView
......@@ -61,6 +60,12 @@ router.register(r'shopcarts', ShoppingCartViewSet, basename='shopcarts')
# 配置下订单路由
router.register(r'orders', OrderViewSet, basename='orders')
# 配置轮播图路由
router.register(r'banners', BannerViewSet, basename='banners')
# 配置首页商品系列路由
router.register(r'indexgoods', IndexCategoryViewSet, basename='indexgoods')
urlpatterns = [
url(r'^xadmin/', xadmin.site.urls),
url(r'^media/(?P<path>.*)$', serve, {'document_root':MEDIA_ROOT}),
......
......@@ -25,4 +25,7 @@
先开发和测试DRF自带API文档,再通过动态设置权限和序列化实现用户个人信息修改,再进行用户收藏、用户留言和用户收货地址的功能开发。
#### V1.7
进一步实现业务功能,主要实现购物车功能、订单功能和支付功能,支付主要使用支付宝支付接口,完成与Django和Vue的接口调试。
\ No newline at end of file
进一步实现业务功能,主要实现购物车功能、订单功能和支付功能,支付主要使用支付宝支付接口,完成与Django和Vue的接口调试。
#### V1.8
完善相关功能,主要包括首页的轮播图、新品展示和商品系列分类展示,商品的点击数、收藏数、库存量和销量功能实现,进行DRF缓存设置,记忆对访问速率进行限制。
\ No newline at end of file
import xadmin
from .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner
from .models import Goods, GoodsCategory, GoodsImage, GoodsCategoryBrand, Banner, IndexAd
class GoodsAdmin(object):
......@@ -51,4 +51,5 @@ class IndexAdAdmin(object):
xadmin.site.register(Goods, GoodsAdmin)
xadmin.site.register(GoodsCategory, GoodsCategoryAdmin)
xadmin.site.register(Banner, BannerGoodsAdmin)
xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin)
\ No newline at end of file
xadmin.site.register(GoodsCategoryBrand, GoodsBrandAdmin)
xadmin.site.register(IndexAd, IndexAdAdmin)
\ No newline at end of file
......@@ -16,4 +16,4 @@ class GoodsFilter(django_filters.rest_framework.FilterSet):
class Meta:
model = Goods
fields = ['name', 'pricemin', 'pricemax', 'is_hot']
\ No newline at end of file
fields = ['name', 'pricemin', 'pricemax', 'is_hot', 'is_new']
\ No newline at end of file
# Generated by Django 3.0.8 on 2020-08-04 10:33
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('goods', '0008_auto_20200729_1112'),
]
operations = [
migrations.AlterField(
model_name='goodscategorybrand',
name='category',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='brands', to='goods.GoodsCategory', verbose_name='商品类目'),
),
]
# Generated by Django 3.0.8 on 2020-08-04 12:54
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('goods', '0009_auto_20200804_1033'),
]
operations = [
migrations.CreateModel(
name='IndexAd',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='category', to='goods.GoodsCategory', verbose_name='商品类目')),
('goods', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='goods', to='goods.Goods', verbose_name='商品')),
],
options={
'verbose_name': '首页商品类别广告',
'verbose_name_plural': '首页商品类别广告',
},
),
]
......@@ -31,7 +31,7 @@ class GoodsCategory(models.Model):
class GoodsCategoryBrand(models.Model):
'''品牌名'''
category = models.ForeignKey(GoodsCategory, verbose_name='商品类目', null=True, on_delete=models.SET_NULL)
category = models.ForeignKey(GoodsCategory, verbose_name='商品类目', related_name='brands', null=True, on_delete=models.SET_NULL)
name = models.CharField(default='', max_length=30, verbose_name='品牌名', help_text='品牌名')
desc = models.TextField(default='', max_length=200, verbose_name='品牌描述', help_text='品牌描述')
image = models.ImageField(max_length=200, upload_to='brands/')
......@@ -105,5 +105,17 @@ class Banner(models.Model):
verbose_name = '轮播商品'
verbose_name_plural = verbose_name
def __str__(self):
return self.goods.name
class IndexAd(models.Model):
category = models.ForeignKey(GoodsCategory, verbose_name='商品类目', related_name='category', null=True, on_delete=models.SET_NULL)
goods = models.ForeignKey(Goods, verbose_name='商品', related_name='goods', null=True, on_delete=models.SET_NULL)
class Meta:
verbose_name = '首页商品类别广告'
verbose_name_plural = verbose_name
def __str__(self):
return self.goods.name
\ No newline at end of file
from django.db.models import Q
from rest_framework import serializers
from .models import Goods, GoodsCategory, GoodsImage
from .models import Goods, GoodsCategory, GoodsImage, Banner, GoodsCategoryBrand, IndexAd
class TerCategorySerializer(serializers.ModelSerializer):
......@@ -41,4 +42,40 @@ class GoodsSerializer(serializers.ModelSerializer):
images = GoodsImageSerializer(many=True)
class Meta:
model = Goods
fields = '__all__'
class BannerSerializer(serializers.ModelSerializer):
class Meta:
model = Banner
fields = '__all__'
class BrandSerializer(serializers.ModelSerializer):
class Meta:
model = GoodsCategoryBrand
fields = '__all__'
class IndexCategorySerializer(serializers.ModelSerializer):
brands = BrandSerializer(many=True)
goods = serializers.SerializerMethodField()
sub_cat = SecCategorySerializer(many=True)
ad_goods = serializers.SerializerMethodField()
def get_goods(self, obj):
all_goods = Goods.objects.filter(Q(category_id=obj.id)|Q(category__parent_category_id=obj.id)|Q(category__parent_category__parent_category_id=obj.id))
goods_serializer = GoodsSerializer(all_goods, many=True, context={'request': self.context['request']})
return goods_serializer.data
def get_ad_goods(self, obj):
goods_json = {}
ad_goods = IndexAd.objects.filter(category_id=obj.id)
if ad_goods:
good_instance = ad_goods[0].goods
goods_json = GoodsSerializer(good_instance, many=False, context={'request': self.context['request']}).data
return goods_json
class Meta:
model = GoodsCategory
fields = '__all__'
\ No newline at end of file
from rest_framework import mixins, viewsets, filters
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination
from rest_framework.throttling import AnonRateThrottle, UserRateThrottle
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework_extensions.cache.mixins import CacheResponseMixin
from .models import Goods, GoodsCategory
from .serializers import GoodsSerializer, CategorySerializer
from .models import Goods, GoodsCategory, Banner
from .serializers import GoodsSerializer, CategorySerializer, BannerSerializer, IndexCategorySerializer
from .filters import GoodsFilter
......@@ -14,7 +17,8 @@ class GoodsPagination(PageNumberPagination):
page_size_query_param = 'page_size'
max_page_size = 100
class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
'''
商品列表页,并实现分页、搜索、过滤、排序
list:
......@@ -23,6 +27,7 @@ class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewset
商品详情
'''
throttle_classes = [AnonRateThrottle, UserRateThrottle]
queryset = Goods.objects.filter(is_delete=False).order_by('id')
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
......@@ -31,6 +36,14 @@ class GoodsListViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewset
search_fields = ['name', 'goods_brief', 'goods_desc']
ordering_fields = ['sold_num', 'shop_price']
def retrieve(self, request, *args, **kwargs):
'''重写实现点击数'''
instance = self.get_object()
instance.click_num += 1
instance.save()
serializer = self.get_serializer(instance)
return Response(serializer.data)
class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet):
'''
......@@ -41,4 +54,23 @@ class CategoryViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets
'''
queryset = GoodsCategory.objects.filter(category_type=1).filter(is_delete=False)
serializer_class = CategorySerializer
\ No newline at end of file
serializer_class = CategorySerializer
class BannerViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
'''
list:
轮播图列表
'''
queryset = Banner.objects.filter(is_delete=False).order_by('index')
serializer_class = BannerSerializer
class IndexCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
'''
list:
商品分类数据
'''
queryset = GoodsCategory.objects.filter(is_delete=False, is_tab=True, name__in=['生鲜食品', '酒水饮料'])
serializer_class = IndexCategorySerializer
......@@ -118,7 +118,7 @@ class OrderDetailSerializer(serializers.ModelSerializer):
return_url=return_url,
notify_url=notify_url
)
pay_url = alipay.gateway + '?' + order_string
pay_url = alipay._gateway + '?' + order_string
return pay_url
class Meta:
......
......@@ -44,6 +44,30 @@ class ShoppingCartViewSet(viewsets.ModelViewSet):
def get_queryset(self):
return ShoppingCart.objects.filter(user=self.request.user, is_delete=False)
def perform_create(self, serializer):
'''创建购物车更新库存量'''
shop_cart = serializer.save()
goods = shop_cart.goods
goods.goods_num -= shop_cart.nums
goods.save()
def perform_destroy(self, instance):
'''删除购物车更新库存量'''
goods = instance.goods
goods.goods_num += instance.nums
goods.save()
instance.delete()
def perform_update(self, serializer):
'''修改购物车更新库存量'''
existed_record = ShoppingCart.objects.filter(is_delete=False).get(id=serializer.instance.id)
existed_nums = existed_record.nums
saved_record = serializer.save()
nums = saved_record.nums - existed_nums
goods = saved_record.goods
goods.goods_num -= nums
goods.save()
class OrderViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
'''
......@@ -113,6 +137,11 @@ class AliPayView(APIView):
existed_orders = OrderInfo.objects.filter(order_sn=order_sn, is_delete=False)
if existed_orders:
for order in existed_orders:
order_goods = order.goods.all()
for order_good in order_goods:
goods = order_good.goods
goods.sold_num += order_good.goods_num
goods.save()
order.pay_status = trade_status
order.trade_no = trade_no
order.pay_time = datetime.now()
......@@ -127,14 +156,19 @@ class AliPayView(APIView):
data = dict(request.POST.items())
signature = data.pop("sign", None)
success = self.alipay.verify(data, signature)
trade_status = self.alipay.api_alipay_trade_query(out_trade_no="2020073117084113366").get("trade_status", None)
order_sn = data.get('out_trade_no', None)
trade_status = self.alipay.api_alipay_trade_query(out_trade_no=order_sn).get("trade_status", None)
if success and trade_status in ("TRADE_SUCCESS", "TRADE_FINISHED"):
order_sn = data.get('out_trade_no', None)
trade_no = data.get('trade_no', None)
existed_orders = OrderInfo.objects.filter(order_sn=order_sn, is_delete=False)
print(len(existed_orders))
if existed_orders:
for order in existed_orders:
order_goods = order.goods.all()
for order_good in order_goods:
goods = order_good.goods
goods.sold_num += order_good.goods_num
goods.save()
order.pay_status = trade_status
order.trade_no = trade_no
order.pay_time = datetime.now()
......
......@@ -4,3 +4,6 @@ from django.apps import AppConfig
class UserOperationConfig(AppConfig):
name = 'user_operation'
verbose_name = '用户操作管理'
def ready(self):
import user_operation.signals
from django.db.models.signals import post_save, post_delete
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
from .models import UserFav
@receiver(post_save, sender=UserFav)
def create_userfav(sender, instance=None, created=False, **kwargs):
if created:
goods = instance.goods
goods.fav_num += 1
goods.save()
@receiver(post_delete, sender=UserFav)
def delete_userfav(sender, instance=None, created=False, **kwargs):
goods = instance.goods
goods.fav_num -= 1
goods.save()
\ No newline at end of file
......@@ -36,6 +36,13 @@ class UserFavViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.Retr
return UserFavSerializer
return UserFavSerializer
# def perform_create(self, serializer):
# '''重写实现收藏数'''
# instance = serializer.save()
# goods = instance.goods
# goods.fav_num += 1
# goods.save()
class LeavingMessageViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin, viewsets.GenericViewSet):
'''
......
......@@ -6,7 +6,7 @@ from rest_framework.authtoken.models import Token
User = get_user_model()
@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
def create_user(sender, instance=None, created=False, **kwargs):
if created:
password = instance.password
instance.set_password(password)
......
......@@ -5,13 +5,13 @@ let host = 'http://shop.projectsedu.com';
let local_host = 'http://127.0.0.1:8000';
//获取商品类别信息
export const queryCategorygoods = params => { return axios.get(`${host}/indexgoods/`) }
export const queryCategorygoods = params => { return axios.get(`${local_host}/indexgoods/`) }
//获取首页中的新品
export const newGoods = params => { return axios.get(`${host}/newgoods/`) }
//获取轮播图
export const bannerGoods = params => { return axios.get(`${host}/banners/`) }
export const bannerGoods = params => { return axios.get(`${local_host}/banners/`) }
//获取商品类别信息
export const getCategory = params => {
......
......@@ -34,7 +34,8 @@ module.exports = {
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'template.html',
inject: true
inject: true,
favicon: path.resolve('favicon.ico')
}),
//new webpack.optimize.CommonsChunkPlugin({name:'vendor',filename:'vendor.bundle.js'})
......
......@@ -14,9 +14,11 @@ django-filter==2.3.0
django-formtools==2.2
django-guardian==2.3.0
django-import-export==2.3.0
django-redis==4.12.1
django-reversion==3.0.7
djangorestframework==3.11.0
djangorestframework-jwt==1.11.0
drf-extensions==0.6.0
et-xmlfile==1.0.1
future==0.18.2
httplib2==0.18.0
......@@ -37,9 +39,10 @@ pycryptodome==3.9.8
pycryptodomex==3.9.4
PyJWT==1.7.1
pyOpenSSL==19.1.0
python-alipay-sdk==2.0.1
python-alipay-sdk==2.1.0
pytz==2020.1
PyYAML==5.3.1
redis==3.5.3
requests==2.24.0
rsa==4.6
six==1.15.0
......@@ -49,4 +52,4 @@ uritemplate==3.0.1
urllib3==1.25.9
xlrd==1.2.0
XlsxWriter==1.2.9
xlwt==1.3.0
\ No newline at end of file
xlwt==1.3.0
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册