drf 测试(车型、车场、经销商)
一、实现要求
1 有车型(CarModel),车厂(CarFactory),经销商(Distributor)三个表,一个车厂可以生产多种车型,一个经销商可以出售多种车型,一个车型可以有多个经销商出售 车型:车型名,车型出厂价,车厂id 车厂:车厂名,车厂地址,联系电话 经销商:经销商名,地址,联系电话 2 有用户表,基于django内置user表,扩展mobile字段 3 编写登陆接口,jwt方式返回token, 格式为{status:100,msg:登陆成功,token:safasdfa} 4 所有接口(除登录外),必须登录后才能访问 5 管理员登陆后可以增,删,单查,群查,改 车型,车厂,经销商(具备所有接口权限) 6 普通用户登陆可以查看车型,车厂,经销商单条,所有(只有查看权限) 7 所有查询所有接口带分页功能 8 查询所有车型接口,可以按车型名字精准过滤 加分项: 用户注册接口 管理员有用户锁定,删除用户功能
注:
根据信息提取出表关系:车型和车场:一对多,车型和经销商:多对多
Models:
from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): mobile = models.IntegerField(null=True) # 车型表 class CarModel(models.Model): carmodel_name = models.CharField(max_length=64) carfact_price = models.IntegerField(null=True) carfact = models.ForeignKey(to='CarFactory', on_delete=models.CASCADE, null=True) distributor = models.ManyToManyField(to='Distributor', null=True) # 定义返回字段 # 车场信息 def factory_info(self): return {'name': self.carfact.carfact_name, 'addr': self.carfact.carfact_addr, 'phone': self.carfact.carfact_phone} # 经销商信息 def dealers_info(self): dealers_info_list = [] for dealer in self.distributor.all(): dealers_info_list.append({'name': dealer.dist_name, 'addr': dealer.dist_addr, 'phone': dealer.dist_phone}) # 车厂表 class CarFactory(models.Model): carfact_name = models.CharField(max_length=64) carfact_addr = models.CharField(max_length=64) carfact_phone = models.IntegerField(null=True) # 经销商表 class Distributor(models.Model): dist_name = models.CharField(max_length=64) dist_addr = models.CharField(max_length=64) dist_phone = models.IntegerField(null=True)
views视图类导入模块汇总
from rest_framework.response import Response from rest_framework_jwt.settings import api_settings from django.contrib.auth import authenticate from rest_framework.viewsets import ViewSet, ModelViewSet from rest_framework.generics import GenericAPIView from rest_framework.mixins import CreateModelMixin, DestroyModelMixin from .models import CarModel, CarFactory, Distributor from .serializer import CarModelSerializer, CarFactorySerializer, DistributorSerializer, UserSerializer from .page import CommonPageNumberPagination from django_filters.rest_framework import DjangoFilterBackend from rest_framework.permissions import IsAuthenticated, IsAdminUser from rest_framework_jwt.authentication import JSONWebTokenAuthentication from .permissions import UserPermission from .models import User from rest_framework.views import APIView from rest_framework.decorators import action jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
二、注册登录接口
1、登录
使用authenticate 方法去比对验证加密后的密码
class LoginView(APIView): def post(self, request): username = request.data.get('username') password = str(request.data.get('password')) user_obj = authenticate(request, username=username, password=password) if user_obj: payload = jwt_payload_handler(user_obj) token = jwt_encode_handler(payload) return Response({'status': 100, 'msg': '登录成功', 'token': token, 'username': user_obj.username}) else: return Response({'status': 101, 'msg': '用户名或密码错误'})
2、注册
class UserView(ViewSet, GenericAPIView, CreateModelMixin): # ViewSet =ViewSetMixin + APIView queryset = User.objects.all() serializer_class = UserSerializer def create(self, request, *args, **kwargs): ser = self.get_serializer(data=request.data) if ser.is_valid(): ser.save() return Response({'code': 100, 'msg': '注册成功!', 'result': ser.data}) return Response({'status': 101, 'msg': '注册失败!', 'erros': ser.errors}) ###### class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['username', 'password', 'mobile'] extra_kwargs = { 'password': {'write_only': True} } def create(self, validated_data): user = User.objects.create_user(**validated_data) return user
三、权限管理、分页、JWT、过滤
1、views
# 车型 class CarModelView(ModelViewSet): queryset = CarModel.objects.all() serializer_class = CarModelSerializer pagination_class = CommonPageNumberPagination # 分页 authentication_classes = [JSONWebTokenAuthentication] # 签发token permission_classes = [IsAuthenticated, UserPermission] # IsAuthenticated 只有token认证通过的可以访问视图。 UserPermission验证用户的权限 filter_backends = [DjangoFilterBackend] # 过滤 filterset_fields = ['carmodel_name', 'carfact_price'] # 车厂 class CarFactoryView(ModelViewSet): queryset = CarFactory.objects.all() serializer_class = CarFactorySerializer pagination_class = CommonPageNumberPagination # 分页 # authentication_classes = [JSONWebTokenAuthentication] # permission_classes = [IsAuthenticated, UserPermission] filter_backends = [DjangoFilterBackend] # 过滤 filterset_fields = ['carfact_name', 'carfact_phone'] # 经销商 class DistributorView(ModelViewSet): queryset = Distributor.objects.all() serializer_class = DistributorSerializer pagination_class = CommonPageNumberPagination # 分页 authentication_classes = [JSONWebTokenAuthentication, ] permission_classes = [IsAuthenticated, UserPermission] filter_backends = [DjangoFilterBackend] # 过滤 filterset_fields = ['dist_name', 'dist_phone']
2、分页类
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination class CommonPageNumberPagination(PageNumberPagination): # 重写几个类属性 page_size = 3 # 每页显示多少条 page_query_param = 'page' # 指定第几页的key值 http://127.0.0.1:8000/books/?page=3 page_size_query_param = 'size' # 可以指定每页显示多少条 size=300000 max_page_size = 5
3、自定义的认证类
判断用户的角色和请求方法,普通用户只能有查看单条和查看所有的权限
from rest_framework.permissions import BasePermission from rest_framework.exceptions import AuthenticationFailed class UserPermission(BasePermission): def has_permission(self, request, view): if not request.user.is_superuser and request.method != 'GET': # 如果是普通用户,只能查看所有或者单条,没修改、更新、创建权限 raise AuthenticationFailed('You must be a superuser') return True
四、管理员有用户锁定,删除用户功能
# 管理员有用户锁定,删除用户功能 class AdminView(ViewSet, GenericAPIView, DestroyModelMixin): queryset = User.objects.all() authentication_classes = [JSONWebTokenAuthentication] permission_classes = [IsAuthenticated, IsAdminUser] # IsAdminUser普通用户不能使用这个接口 @action(methods=['DELETE'], detail=True) # 重写于DestroyModelMixin的delete方法 def delete_user(self, request, *args, **kwargs): return self.destroy(request, *args, **kwargs) @action(methods=['GET'], detail=True) def lock(self, request, *args, **kwargs): user = self.get_object() if user is None: return Response({'status': 101, 'msg': '用户不存在!'}) if user.is_active: user.is_active = False user.save() return Response({'status': 100, 'msg': '用户锁定成功!'}) else: # is_active为0的情况 return Response({'status': 102, 'msg': '用户已经锁定,请勿重复操作!'}) @action(methods=['GET'], detail=True) def unlock(self, request, *args, **kwargs): user = self.get_object() if user is None: return Response({'status': 101, 'msg': '用户不存在!'}) if user.is_active is False: user.is_active = True user.save() return Response({'status': 100, 'msg': '用户解锁成功!'}) else: return Response({'status': 102, 'msg': '用户没有锁定,请勿重复操作!'})
五、序列化类
from rest_framework import serializers from .models import CarModel, CarFactory, Distributor from .models import User class UserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['username', 'password', 'mobile'] extra_kwargs = { 'password': {'write_only': True} } def create(self, validated_data): user = User.objects.create_user(**validated_data) return user class CarModelSerializer(serializers.ModelSerializer): class Meta: model = CarModel fields = '__all__' extra_kwargs = { 'carmodel_name': {'max_length': 8, 'min_length': 3}, 'distributor': {'write_only': True}, 'carfact': {'write_only': True} } carfact_detail = serializers.SerializerMethodField() def get_carfact_detail(self, obj): return {'name': obj.carfact.carfact_name, 'addr': obj.carfact.carfact_addr} distributor_detail = serializers.SerializerMethodField() def get_distributor_detail(self, obj): l = [] for i in obj.distributor.all(): l.append({'name': i.dist_name, 'addr': i.dist_addr, 'phone': i.dist_phone}) return l class CarFactorySerializer(serializers.ModelSerializer): class Meta: model = CarFactory fields = '__all__' class DistributorSerializer(serializers.ModelSerializer): class Meta: model = Distributor fields = '__all__'
六、路由
from django.urls import path, include from rest_framework.routers import SimpleRouter from app01.views import CarModelView, CarFactoryView, DistributorView, UserView, AdminView,LoginView route = SimpleRouter() route.register('user', UserView, 'user') route.register('admin', AdminView, 'admin') route.register('carmodel', CarModelView, 'carmodel') route.register('carfact', CarFactoryView, 'carfact') route.register('dict', DistributorView, 'dict') urlpatterns = [ path('login/', LoginView.as_view()), path('', include(route.urls)) ]