路漫漫其修远兮
吾将上下而求索

drf学习:Vue+Django REST framework打造生鲜电商项目6-13章

第6章 商品类别数据和vue展示
本章节实现了商品分类数据的获取以及商品的搜索功能,本章节不仅实现商品分类列表数据的获取还包括分类详情的获取,在获取到数据后和vue前端项目完成
了联调, 也简单介绍了vue项目中是如何完成商品分类数据的显示。

6-1 商品类别数据接口-1
6-2 商品类别数据接口-2
6-3 vue展示商品分类数据
6-4 vue展示商品列表页数据-1
6-5 vue展示商品列表页数据
6-6 vue的商品搜索功能






第7章 用户登录和手机注册
本章节完成了drf的登录和手机注册功能,首先从drf的token登录原理和实现讲起,然后引申出jwt的登录方式,在详细的讲解了jwt的原理之后我们会讲解如何
将jwt登录集成到drf中。在手机注册的功能开发中我们详细的讲解了如何集成云片网到短信发送功能以及如何去完成短信的验证功能,本章节还会详细的讲
解serializer的字段验证功...

7-1 drf的token登录和原理-1
7-2 drf的token登录和原理-2

用户从请求到返回都经历了什么,下面的文档需要好好理解下
http://projectsedu.com/2016/10/17/django%E4%BB%8E%E8%AF%B7%E6%B1%82%E5%88%B0%E8%BF%94%E5%9B%9E%E9%83%BD%E7%BB%8F%E5%8E%86%E4%BA%86%E4%BB%80%E4%B9%88/

因为有下面的认证接口,drf的web能显示登录退出按钮,但是这个drf自带的模板里面有csrf验证,不能直接使用
url(r'^api-auth/', include('rest_framework.urls')),

session认证原理,使用了下面两个中间件,用户发送请求的时候,验证session是否是数据库里面的session,取出user,
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',



token认证
https://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication

根据官方文档:添加到install_app: 'rest_framework.authtoken'
会在数据库中添加一张表:key, create user_id 即每个用户有一个token
python manage.py makemigrations
python manage.py migrate

然后在url中添加
from rest_framework.authtoken import views
urlpatterns += [
    url(r'^api-token-auth/', views.obtain_auth_token)
]


然后测试,输入admin的账号密码,会返回admin的token,并且mysql表中也会加入这个token,具体执行过程可以查看views.obtain_auth_token
curl -H 'Content-Type: application/json' -d '{"username":"admin","password":"admin1234"}' 192.168.170.30:8000/api-token-auth/
{"token":"443c4438e3d85e16a75597574723754a661a66f9"}

在settings里面将token认证添加
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication',
    )
}


drf会轮流进行上面的三种验证,当某一种验证成功后,会将用户信息存放到request.user属性里面
当用户发送请求后,进入中间件里面,会统一先执行每个中间件里面的process_request方法,进行一些检查工作,cookie检查等,才会进入view里面执行用户的view
关于tokenAuthentication具体过程,需要结合基础课程,查看具体执行过程


然后请求的时候在header里面添加此认证信息
curl -X GET http://192.168.170.30:8000/goods/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'




7-3 viewsets配置认证类

但是当用户输入错误的token,会显示令牌无效:curl -X GET http://192.168.170.30:8000/goods/ -H 'Authorization: Token abcdefg'
但是goods路径应该是公共参数,因此可以在goods里面设置认证class为空即可



7-4 json web token的原理

https://www.jianshu.com/p/180a870a308a




7-5 json web token方式完成用户认证
使用下面的这个插件:https://github.com/GetBlimp/django-rest-framework-jwt

参考文档:http://getblimp.github.io/django-rest-framework-jwt/
1、安装
 pip install djangorestframework-jwt

2、settings认证设置
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',

3、设置url
from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    '',
    # ...

    url(r'^jwt-auth/', obtain_jwt_token),
]


4、测试认证
curl -H 'Content-Type: application/json' -d '{"username":"admin","password":"admin1234"}' 192.168.170.30:8000/jwt-auth/
{"token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNTUxMTU2NTA1LCJlbWFpbCI6ImFAYi5jb20ifQ.R
8geek9Fhf9S2wR8CIvCN4kABrzr189UeAj8ymeNfZg"}




7-6 vue和jwt接口调试

整个过程为:
vue前端输入用户名和密码,发送给后端,
后端认证过后,将token作为报文返回给用户
用户将用户名和token保存到cookie中
下次访问的时候将此内容放到header中发送给后端


当用户在输入用户名对话框里面输入邮箱的时候,也用邮箱进行用户认证验证,下面是具体的配置,
在settings中添加使用自定义的验证
AUTHENTICATION_BACKENDS = (
    'users.views.CustomBackend'
)


在views里面添加自定义类
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth import get_user_model
from django.db.models import Q


User = get_user_model()
class CustomBackend(ModelBackend):
    """
    自定义用户验证,查询用户
    """
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            user = User.objects.get(Q(username=username)|Q(email=username))
            if user.check_password(password):
                return user
        except Exception as e:
            return None


jwt设置过期时间,还有token前缀替换为自定义的字符串
import datetime
JWT_AUTH = {
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}



7-7 云片网发送短信验证码

# -*- coding: utf-8 -*-
__author__ = 'bobby'
import json
import requests


class YunPian(object):

    def __init__(self, api_key):
        self.api_key = api_key
        self.single_send_url = "https://sms.yunpian.com/v2/sms/single_send.json"

    def send_sms(self, code, mobile):
        parmas = {
            "apikey": self.api_key,
            "mobile": mobile,
            "text": "【慕学生鲜】您的验证码是{code}。如非本人操作,请忽略本短信".format(code=code)
        }

        response = requests.post(self.single_send_url, data=parmas)
        re_dict = json.loads(response.text)
        return re_dict


if __name__ == "__main__":
    yun_pian = YunPian("")
    yun_pian.send_sms("2017", "")





7-8 drf实现发送短信验证码接口-1
7-9 drf实现发送短信验证码接口-2


编写文件:user/serializes.py
下面是验证用户发送验证码的序列化

import re
from rest_framework import serializers
from django.contrib.auth import get_user_model
from datetime import datetime
from datetime import timedelta
from rest_framework.validators import UniqueValidator
from .models import VerifyCode
from backend.settings import REGEX_MOBILE

User = get_user_model()

class SmsSerializer(serializers.Serializer):
    mobile = serializers.CharField(max_length=11)
    #这里的方法名字是以validate开头,以mobile结尾,不知道有没有必须这样做
    def validate_mobile(self, mobile):
        """
        验证手机号码
        :param data:
        :return:
        """

        # 手机是否注册
        if User.objects.filter(mobile=mobile).count():
            raise serializers.ValidationError("用户已经存在")

        # 验证手机号码是否合法
        if not re.match(REGEX_MOBILE, mobile):
            raise serializers.ValidationError("手机号码非法")

        # 验证码发送频率
        one_mintes_ago = datetime.now() - timedelta(hours=0, minutes=1, seconds=0)
        if VerifyCode.objects.filter(add_time__gt=one_mintes_ago, mobile=mobile).count():
            raise serializers.ValidationError("距离上一次发送未超过60s")

        return mobile

这里用到了一个手机正则表达式
# 手机号码正则表达式
REGEX_MOBILE = "^1[358]\d{9}$|^147\d{8}$|^176\d{8}$"



views.py里面添加短信viewset,当指定CreateModelMixin的时候,并且router里面将post方法和create方法对应起来,表示只允许使用post方法,get方法不被允许,还有待验证
class SmsCodeViewset(CreateModelMixin, viewsets.GenericViewSet):
    """
    发送短信验证码
    """
    serializer_class = SmsSerializer

    def generate_code(self):
        """
        生成四位数字的验证码
        :return:
        """
        seeds = "1234567890"
        random_str = []
        for i in range(4):
            random_str.append(choice(seeds))

        return "".join(random_str)

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)   #当设置为True,则有异常会中断,后面的不会执行

        mobile = serializer.validated_data["mobile"]

        yun_pian = YunPian(APIKEY)

        code = self.generate_code()
        #这里需要先发送验证码成功后,再将其保存到数据库中
        sms_status = yun_pian.send_sms(code=code, mobile=mobile)

        if sms_status["code"] != 0:  #发送验证码错误,将信息返回给用户
            return Response({
                "mobile":sms_status["msg"]
            }, status=status.HTTP_400_BAD_REQUEST)
        else:
            code_record = VerifyCode(code=code, mobile=mobile)
            code_record.save()
            return Response({
                "mobile":mobile
            }, status=status.HTTP_201_CREATED)


url中定义路径
router = DefaultRouter()
router.register(r'codes', SmsCodeViewset, base_name="codes")

urlpatterns = [
    url(r'^', include(router.urls)),
]


当使用post方法测试:结果都可以达到要求
curl -H 'Content-Type: application/json' -d '{"mobile":"15211112222"}' 192.168.170.30:8000/codes/




7-10 user serializer和validator验证-1
7-11 user serializer和validator验证-2

用户注册功能代码比较多,看gitlab具体代码吧,序列化和viewset

username虽然是用户名,但是必须写手机号,不然后面从验证码表中查不到

help_text='密码'  web表单下面的帮助说明

label="用户名"  web表单前面的名字

def validate_code(self, code): 表示验证从用户那里发来的请求字段code

code = serializers.CharField(write_only=True) 必须加write_only字段,表示只向后端传送,保存到数据库中
不从后端向前端传送,前端不会显示该字段

fields = ('username','code','password')  表示前端必须传入三个参数,不然报错,mobile是在类里面从username变量赋值的

程序流程查看的入库是post方法对应viewset里面的create方法,其实也是继承CreateModelMixin里面的create方法
create方法里面找到对应的序列化类,根据序列化里面验证方法验证字段,其实最后还是调用序列化里面的create
保存数据是调用的UserRegSerializer.create方法


测试发送请求:POST http://127.0.0.1:8000/users/
{
    "code": "4136",
    "username": "15211112222",  这里的username指的是手机号
    "password": "pass"
}

返回数据
{
    "username": "15211112223",
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxNywidXNlcm5hbWUiOiIxNTIxMTExMjIyMyIsImV4cCI6MTU1MTI3ODg0OSwiZW1haWwi
    Om51bGx9.Bim897Gz7JBZMWi9B2mTNz3lc8g9oFKgC4zLt6Zbpl8",
    "name": "15211112223"
}




drf默认的返回提醒模式
通过http状态码来提醒用户是否正确,
用户传送过来几个字段,每个字段单独返回该字段是否正确
都遵循这种模式来开发,而不是通过自定义status状态码来实现
http_code: 400, 401
{
    mobile: ['xxx'],
    code: ['yyy']
}









7-12 django信号量实现用户密码修改


label 网页显示的名字
write_only 只写,不读
style 网页密码显示***

密码明文,需重写
    # def create(self, validated_data):
    #     user = super(UserRegSerializer, self).create(validated_data=validated_data)
    #     user.set_password(validated_data["password"])
    #     user.save()
    #     return user
这里通过信号量来实现
接收post_save信号量,在信号里面再将用户的密码单独修改掉

created 入参表示是否为新建动作还是update动作,分别进行处理

要在apps.py里面导入信号量
    def ready(self):
        import users.signals

修改表字段,要makemigration

也可以在viewset里面重载create方法,更灵活




7-13 vue和注册功能联调
略










第8章 商品详情页功能
本章节详细的讲解商品详情页功能的开发,包括商品的详情的展示、商品的收藏功能和热卖商品的接口开发,在收藏功能中会介绍到drf的权限以及认证配置

8-1 viewsets实现商品详情页接口

序列化json嵌套使用下面的比较好理解
还需要再看,不知道为什么相同的东西循环了几次

view里面写viewset
from rest_framework import generics, mixins
from rest_framework.pagination import PageNumberPagination
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from rest_framework.permissions import IsAuthenticated

class GoodsPagination(PageNumberPagination):
    page_size = 5
    page_size_query_param = 'page_size'
    page_query_description = 'page'
    max_page_size = 10


class GoodsListView(mixins.ListModelMixin,
                  GenericViewSet):
    queryset = Goods.objects.all()
    serializer_class = GoodsSerializer
    pagination_class = GoodsPagination
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    permission_classes = (IsAuthenticated,)
    

序列化文件
class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsCategory
        fields = '__all__'


class GoodsImageSerializer(serializers.ModelSerializer):
    class Meta:
        model = GoodsImage
        fields = ('id', 'image')


class GoodsSerializer(serializers.ModelSerializer):
    category = CategorySerializer()
    images = GoodsImageSerializer(many=True)

    class Meta:
        model = Goods
        fields = ['id', 'category', 'images', 'name', 'shop_price']


添加路由
router.register(r'goods', GoodsListView, base_name='users')


添加jwt配置
import datetime
JWT_AUTH = {
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    'JWT_AUTH_HEADER_PREFIX': 'JWT',
}


        
首先进行认证,获取token
curl -X POST -H 'Content-Type: application/json' -d '{"username": "15211112223", "password": "pass"}' 192.168.170.30:8000/jwt-auth/
{"token":"xxx.xxx.xxx"}

然后使用此token进行认证,获取数据
curl -X GET -H 'Authorization: JWT eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyMiwidXNlcm5hbWUiOiIxNTIxMTExMjIyMyIsImV4cCI6MTU1Mj
AxNDI1NywiZW1haWwiOm51bGx9.fIl8w0mwlYxSOoVAdXbLT9U0FCPvfeLsugVUSRR7-cM' 192.168.170.30:8000/goods/?page=5




8-2 热卖商品接口实现

8-3 用户收藏接口实现


queryset可以自己在viewset里面定义,也可以在viewset里面重写get_queryset(self)方法,其实是一样的,都会在方法里面赋值,从请求的起点开始查,
get方法对应list函数,里面会去获取queryset
下面的程序的作用是这个序列化只使用登录用户的账号,具体还要看代码
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )


views文件
class UserFavViewset(mixins.CreateModelMixin, mixins.ListModelMixin,
                     mixins.RetrieveModelMixin, mixins.DestroyModelMixin,
                     viewsets.GenericViewSet):

    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly, )
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    serializer_class = UserFavDetailSerializer

    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
        

序列化文件 
class UserFavDetailSerializer(serializers.ModelSerializer):
    goods = GoodsSerializer()

    class Meta:
        model = UserFav
        fields = ('id', 'add_time', 'goods_id', 'goods')


class UserFavSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )

    class Meta:
        model = UserFav
        validators = [
            UniqueTogetherValidator(
                queryset=UserFav.objects.all(),
                fields=('user', 'goods'),
                message="已经收藏"
            )
        ]

        fields = ("user", "goods", "id")


支持四种方式,post方法需要传入goods的id,get,delete,方法都支持




8-4 drf的权限验证
permission_classes = (IsAuthenticated, IsOwnerOrReadOnly) drf会根据这里的列表进行检查,当检查某项权限未false,会接着检查后面的权限,当有一个权限检查通过,即放行

这里新增加一个权限验证,感觉用不到
class IsOwnerOrReadOnly(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        if request.method in permissions.SAFE_METHODS:
            return True
        return obj.user == request.user


8-5 用户收藏功能和vue联调






第9章 个人中心功能开发
本章节介绍个人中心功能的开发,如个人信息修改、用户收藏管理、留言管理、收货地址的管理和订单管理等。本章还会介绍drf的文档相关功能, 让大家
体验到drf的文档自动化管理功能。本章节会更进一步介绍drf的权限、认证配置功能, 也会讲解到动态设置serializer、权限和认证等功能...

9-1 drf的api文档自动生成和功能详解

后面不能有$符号
url(r'docs/', include_docs_urls(title='工单系统')),
接口说明位置:每个类下面刚开始的注释,会读取这个,可以看文档,里面功能更多
https://www.django-rest-framework.org/topics/documenting-your-api/
help_text为serializer的doc文档里面用的字段描述里面的内容


9-2 动态设置serializer和permission获取用户信息
用户个人中心信息修改
用户不知道自己的id,get user/id 不管传递哪个id,都返回该用户的数据
    def get_object(self):
        return self.request.user

如果用户注册,都可以访问。如果获取信息,有权限
重写apiviewset里面的方法
    def get_permissions(self):
        if self.action == "retrieve":
            return [permissions.IsAuthenticated()]
        elif self.action == "create":
            return []

        return []

        
根据不同的请求,返回不同的序列化,注意,这里最下面必须返回一个序列化,因为除了retrieve和create这两个方法之外,其他的方法也会使
用get_serializer_class这个方法,如果用户使用了get方法,但是这里没有匹配的序列化,会报错
    def get_serializer_class(self):
        if self.action == "retrieve":
            return UserDetailSerializer
        elif self.action == "create":
            return UserRegSerializer

        return UserDetailSerializer
        
        

9-3 vue和用户接口信息联调
9-4 用户个人信息修改
继承:mixins.UpdateModelMixin 对应put和update方法,可以看doc里面的改变和显示查看具体的,部分更新一些参数



9-5 用户收藏功能
差不多



9-6 用户留言功能
add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')
只能查看,不能修改


https://www.django-rest-framework.org/api-guide/parsers/#multipartparser
multipart/form-data  文件上传,需要指定对应类型



9-7 用户收货地址列表页接口开发
9-8 vue和收货地址接口联调







第10章 购物车、订单管理和支付功能
本章节讲解系统的购物车、订单管理和支付宝支付的功能, 本章节除了讲解功能之外也会带领大家去完成服务器远程代码调试的功能, 支付宝的
支付功能我会通过结合支付宝官方文档的方式来讲解支付宝支付的原理以及全流程, 这些知识点让大家不仅能够完成支付宝的支付功能还能理解
到支付宝的支付的完整过程,让大家即使用其他...

10-1 购物车功能需求分析和加入到购物车实现
10-2 修改购物车数量
10-3 vue和购物车接口联调
10-4 订单管理接口-1_1
10-5 订单管理接口-2
10-6 vue个人中心订单接口调试
10-7 pycharm远程代码调试-1
10-8 pycharm远程代码调试-2_1
10-9 支付宝公钥、私钥和沙箱环境的配置
10-10 支付宝开发文档解读
10-11 支付宝支付源码解读
10-12 支付宝通知接口验证
10-13 django集成支付宝notify_url和return_url接口-1
10-14 django集成支付宝notify_url和return_url接口-2
10-15 支付宝接口和vue联调-1
10-16 支付宝接口和vue联调-2








第11章 首页、商品数量、缓存、限速功能开发
第十一章本章节除了完成系统的一些剩余细节之外还能了解到drf的缓存机制以及限制api访问频率的功能。本章节我们会通过django的信号量方
式实现商品数量的修改、本章节会讲解api限速的原理。

11-1 轮播图接口实现和vue调试
11-2 新品功能接口开发
11-3 首页商品分类显示功能-1
11-4 首页商品分类显示功能-2
11-5 商品点击数、收藏数修改
11-6 商品库存和销量修改
11-7 drf的缓存设置
11-8 drf配置redis缓存
11-9 drf的throttle设置api的访问速率







第12章 第三方登录
本章节完成系统的第三方登录集成功能,章节从oauth2.0的原理开始,带领大家去自动实现微博的登录过程之后再代理大家去集成第三方登录的
开源项目, 让大家不仅可以轻松集成微博、qq和微信登录以外还能去轻松集成自己想要集成的其他第三方登录...

12-1 第三登录开发模式以及oauth2.0简介
12-2 oauth2.0获取微博的access_token
12-3 social_django集成第三方登录-1
12-4 social_django集成第三方登录-2







第13章 sentry实现错误日志监控
本章节首先带领大家去体验sentry的错误日志管理功能,让大家领略到sentry的错误日志记录还能及时接收到邮件通知,然后带领大家通
过docker去搭建一个自己的错误日志管理系统,最后讲解如何将sentry集成到drf中。

13-1 sentry的介绍和通过docker搭建sentry
13-2 sentry的功能
13-3 sentry 集成到django rest framework中-1
13-4 sentry 集成到django rest framework中-2

未经允许不得转载:江哥架构师笔记 » drf学习:Vue+Django REST framework打造生鲜电商项目6-13章

分享到:更多 ()

评论 抢沙发

评论前必须登录!