drf考试题目,及解题代码
考试
1 有车型(CarModel),车厂(CarFactory),经销商(Distributor)三个表,一个车厂可以生产多种车型,一个经销商可以出售多种车型,一个车型可以有多个经销商出售
车型:车型名,车型出厂价,车厂id
车厂:车厂名,车厂地址,联系电话
经销商:经销商名,地址,联系电话
2 有用户表,基于django内置user表,扩展mobile字段
3 编写登陆接口,jwt方式返回token,
格式为{status:100,msg:登陆成功,token:safasdfa}
3 只有管理员登陆后可以新增,修改,删除(车型,车厂,经销商)
2 普通用户登陆可以查看车型(群查所有的都要有分页,单查)
注:查车型:返回车型名字价格,车厂名字与地址,经销商名字和电话
加分项:
用户注册接口
管理员有用户锁定,删除功能
.
.
# 模型表代码
from django.db import models
from django.contrib.auth.models import AbstractUser
# Create your models here.
class UserInfo(AbstractUser):
mobile = models.BigIntegerField(verbose_name='手机号', null=True, blank=True)
class CarModel(models.Model):
name = models.CharField(max_length=32)
price = models.IntegerField()
factory = models.ForeignKey(to='CarFactory', on_delete=models.CASCADE, null=True, blank=True)
distributors = models.ManyToManyField(to='Distributor')
@property
def factory_detail(self):
return {'name': self.factory.name, 'addr': self.factory.addr}
@property
def distribute_detail(self):
return [{'name': distributor.name, 'phone': distributor.phone} for distributor in self.distributors.all()]
class CarFactory(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
phone = models.BigIntegerField()
class Distributor(models.Model):
name = models.CharField(max_length=32)
addr = models.CharField(max_length=32)
phone = models.BigIntegerField()
.
.
纯手动,烦一点的写法
路由层代码
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import SimpleRouter
from app01 import views
router = SimpleRouter()
router.register('user', views.UserView, 'user')
# token签发也就是登录自己写视图类来完成
# 查车
router.register('set_car', views.SetCarView, 'set_car')
router.register('search_car', views.SearchCarView, 'search_car')
# 查经销商
router.register('set_distributor', views.SetDistributorView, 'c_d_distributor')
router.register('search_distributor', views.SearchDistributorView, 'search_distributor')
# 查工厂
router.register('set_factory', views.SetFactoryView, 'c_d_factory')
router.register('search_factory', views.SearchFactoryView, 'search_factory')
urlpatterns = [
path('admin/', admin.site.urls),
path('api/v1/', include(router.urls)),
]
--------------------------------------------------
# 视图层代码
from rest_framework.decorators import action
from app01.models import UserInfo, CarModel, CarFactory, Distributor
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER
from rest_framework.response import Response
from django.contrib import auth
from rest_framework.mixins import ListModelMixin, CreateModelMixin, UpdateModelMixin
from rest_framework.generics import DestroyAPIView, RetrieveAPIView
from rest_framework.viewsets import ViewSetMixin, ViewSet, GenericViewSet
from app01.serializer import CarSerializer, FactorySerializer, DistributorSerializer
class UserView(ViewSet):
@action(methods=['POST'], detail=False)
def login(self, request, *args, **kwargs):
username = request.data.get('username')
password = request.data.get('password')
user_obj = auth.authenticate(request, username=username, password=password)
if user_obj:
# 通过user_obj 得到payload
payload = jwt_payload_handler(user_obj)
# 生成token
token = jwt_encode_handler(payload)
return Response({'status': 1000, 'msg': '登录成功', 'token': token})
else:
return Response({'status': 1001, 'msg': '用户名或密码错误'})
from app01.authentication import JsonWebTokenAuthentication
from app01.page import CommonPageNumberPagination
from app01.permissions import CommonPermission
# 删车,新增车,修改车
class SetCarView(ViewSetMixin, DestroyAPIView, CreateModelMixin, UpdateModelMixin):
queryset = CarModel.objects.all()
serializer_class = CarSerializer
# token认证,兼确认请求头里面有没有带token
authentication_classes = [JsonWebTokenAuthentication]
# 是否是管理员权限认证,如果不是没有权限执行该视图类下的接口函数
permission_classes = [CommonPermission]
# 查单个,查所有,只要登录了就行了
class SearchCarView(ViewSetMixin, RetrieveAPIView, ListModelMixin):
# token认证
authentication_classes = [JsonWebTokenAuthentication]
queryset = CarModel.objects.all()
serializer_class = CarSerializer
# 再加个分页功能
pagination_class = CommonPageNumberPagination
# 删厂,新增厂,修改厂
class SetFactoryView(ViewSetMixin, DestroyAPIView, CreateModelMixin, UpdateModelMixin):
authentication_classes = [JsonWebTokenAuthentication]
permission_classes = [CommonPermission]
queryset = CarFactory.objects.all()
serializer_class = FactorySerializer
# 查单个,查所有
class SearchFactoryView(ViewSetMixin, RetrieveAPIView, ListModelMixin):
# token认证
authentication_classes = [JsonWebTokenAuthentication]
queryset = CarFactory.objects.all()
serializer_class = FactorySerializer
# 再加个分页功能
pagination_class = CommonPageNumberPagination
# 删,新增,修改经销商
class SetDistributorView(ViewSetMixin, DestroyAPIView, CreateModelMixin, UpdateModelMixin):
authentication_classes = [JsonWebTokenAuthentication]
permission_classes = [CommonPermission]
queryset = Distributor.objects.all()
serializer_class = DistributorSerializer
# 查单个,查所有
class SearchDistributorView(ViewSetMixin, RetrieveAPIView, ListModelMixin):
# token认证
authentication_classes = [JsonWebTokenAuthentication]
queryset = Distributor.objects.all()
serializer_class = DistributorSerializer
# 再加个分页功能
pagination_class = CommonPageNumberPagination
--------------------------------------------------
--------------------------------------------------
# 序列化类代码如下:
from rest_framework import serializers
from app01.models import UserInfo, CarModel, CarFactory, Distributor
class CarSerializer(serializers.ModelSerializer):
class Meta:
model = CarModel
fields = ['id', 'name', 'price', 'factory', 'distributors', 'factory_detail', 'distribute_detail']
extra_kwargs = {
'factory_detail': {'read_only': True},
'distribute_detail': {'read_only': True},
'factory': {'write_only': True},
'distributors': {'write_only': True}
}
class FactorySerializer(serializers.ModelSerializer):
class Meta:
model = CarFactory
fields = ['id', 'name', 'addr', 'phone']
class DistributorSerializer(serializers.ModelSerializer):
class Meta:
model = Distributor
fields = ['id', 'name', 'addr', 'phone']
--------------------------------------------------
--------------------------------------------------
# 自定义登录认证类代码
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import jwt
from rest_framework_jwt.utils import jwt_decode_handler
from app01.models import UserInfo
class JsonWebTokenAuthentication(BaseAuthentication):
def authenticate(self, request):
# 取出token
token = request.META.get('HTTP_TOKEN')
if token:
try:
payload = jwt_decode_handler(token) # 重点代码 用token获取荷载
user_obj = UserInfo.objects.get(pk=payload.get('user_id'))
# 得到当前用户对象,get是filter与first的结合,但是如果拿不到直接报错
# 只要访问一次登录接口,就会去Userinfo表中查一次用户---优化操作
# user_obj = Userinfo(id=payload.get('user_id'),username=payload.get('username'))
# 或者user_obj={'id':payload.get('user_id')}
return user_obj,token
except jwt.ExpiredSignature:
raise AuthenticationFailed('token过期')
except jwt.DecodeError:
raise AuthenticationFailed('token认证失败')
except jwt.InvalidTokenError:
raise AuthenticationFailed('token无效')
except Exception as e:
raise AuthenticationFailed('未知错误')
raise AuthenticationFailed('token没有传,认证失败')
---------------------------------------------
# 自己写的权限类,新建个permissions.py文件 代码如下:
# 是超级管理员就有权限执行,不是就没有权限执行视图函数
from rest_framework.permissions import BasePermission
class CommonPermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_superuser == 1:
return True
else:
self.message = '您没有权限'
return False
---------------------------------------------
---------------------------------------------
# 自定义分页类
from rest_framework.pagination import PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
page_size = 2 # 每页显示2条
page_query_param = 'page' # page = 10 查询第10页的数据,每页显示2条
page_size_query_param = 'size' # 定制每页显示条数的参数 page=2&size=3 每页显示3条,并查询第10页的数据,不写&size=3就还是每页显示2条
max_page_size = 4 # 每页最大显示4条,上面定制的page=2&size=5 就变成了 每页显示4条 查询第10页的数据
---------------------------------------------
# 配置文件代码
import datetime
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # token过期时间
}
---------------------------------------------
.
.
.
.
.
.
# 全自动,不用写登录接口签发token,也不要写自定义认证类来校验请求头带的token是否正确
# 自定义权限类换一种方法来写,原来只判断是不是超级管理员,如果不是,就直接返回false,
# 就没有权限执行视图类里面对应的函数了,那么也就必须要把增删改 与查单个查所有
# 分到两个视图类里面来写,
# 现在在权限类里面,判断完是不是超级管理员后,如果不是再继续判断是不是get请求,
# 如果是也返回true,最后else返回false
# 这样就可以写在一个视图类里面了
.
.
-----------------------------------------------
# 路由层代码
from django.contrib import admin
from django.urls import path
from app01 import views
from rest_framework_jwt.views import obtain_jwt_token
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('user', views.UserView, 'user') # /user/login--->post请求
router.register('car_model', views.CarModelView, 'car_model')
router.register('car_factory', views.CarFactoryView, 'car_factory')
router.register('distributor', views.DistributorView, 'distributor')
urlpatterns = [
path('admin/', admin.site.urls),
path('login/', obtain_jwt_token), # 基于auth表及扩展表,快速签发token
]
urlpatterns += router.urls
# 登录签发token接口视图类不用写了
-----------------------------------------------
-----------------------------------------------
# 对于快速签发的token的返回格式可以设置一下
配置里面
JWT_AUTH = {
'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler',
}
创一个utils.py文件
def jwt_response_payload_handler(token, user=None, request=None):
return {
'status': 100,
'msg': '登录成功',
'username':user.username,
'token': token,
}
-----------------------------------------------
-----------------------------------------------
# 视图层代码 车,厂,经销商 都只需要一个视图类
from rest_framework.viewsets import ModelViewSet # 用它5个接口全有了
from .serializer import *
from .page import MyPageNumberPagination # 自定义分页类
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication # 自带的
from .permission import AdminPermission # 自定义权限类
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER # 定义token的返回格式用的
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
# 类名都是驼峰
# 函数名,方法名,变量名,文件名用下划线
class CarModelView(ModelViewSet):
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated, AdminPermission]
queryset = CarModel.objects.all()
serializer_class = CarModelSerializer
pagination_class = MyPageNumberPagination # 分页类
class CarFactoryView(ModelViewSet):
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated, AdminPermission]
queryset = CarFactory.objects.all()
serializer_class = CarFactorySerializer
pagination_class = MyPageNumberPagination # 分页类
class DistributorView(ModelViewSet):
authentication_classes = [JSONWebTokenAuthentication]
permission_classes = [IsAuthenticated, AdminPermission]
queryset = Distributor.objects.all()
serializer_class = DistributorSerializer
pagination_class = MyPageNumberPagination # 分页类
# 用jet自带的认证类,就必须要配合django自带的确认是否登录的权限类一起用
# 因为jwt自带的认证类,对于请求不带token的直接就让过了,
# 所以要用IsAuthenticated权限类,再确认请求是否没带token
-----------------------------------------------
-----------------------------------------------
# 权限类,代码
from rest_framework.permissions import BasePermission
class AdminPermission(BasePermission):
def has_permission(self, request, view):
if request.user.is_superuser:
return True
else:
# 不是超级用户,只能访问get
if request.method == 'GET':
return True
else:
return False
-----------------------------------------------
序列化类和纯手动的一样的代码,分页类代码也是一样
-----------------------------------------------
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY