DRF案例之车厂API
目录
- DRF案例之车厂API
- 需求
- urls.py
- models.py
- views.py
- MySerializers.py
- MyValidate.py
- MyFilter.py
- MyPagination.py
- settings注册自定义类
- 国际化输出
需求
- 定义车型表(CarModel),车厂表(CarFactory),经销商表(Distributor)
- 一个车厂可以生产多种车型
- 一个经销商可以出售多种车型
- 一个车型可以有多个经销商出售
- 定义用户表,要求由django内置的user表扩写,新添mobile字段
- 定义登录接口,要求使用jwt返回token,格式要求为{“status”:100, “msg”:“登录成功”, “token”:“…”}
- token的过期时间为3天
- 所有接口(除登录),必须登录后才能访问
- 管理员登录后可以对车型车厂经销商三表进行增删改,群查,单查
- 普通用户仅能使用查询车型、车厂,经销商和删除车型这几个接口
- 所有查询接口都要有分页功能
- 查询所有车型接口时可以按车型名字进行精准过滤
urls.py
from django.contrib import admin
from django.urls import path
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.routers import SimpleRouter
from car.views import CarModelView, CarFactoryView, DistributorView# 创建SimpleRouter实例并注册url, 这个步骤是用SimpleRouter自动生成路由
routers = SimpleRouter()
routers.register('CarModelView', CarModelView, 'CarModelView')
routers.register('CarFactoryView', CarFactoryView, 'CarFactoryView')
routers.register('DistributorView', DistributorView, 'DistributorView')
urlpatterns = [path('admin/', admin.site.urls),# 用simplejwt自带的模块帮我们创建登录接口,因此视图不再需要手写path('login/', TokenObtainPairView.as_view()),
]
# 将SimpleRouter创建的映射添加进路由
urlpatterns += routers.urls
models.py
from django.db import models
from django.contrib.auth.models import AbstractUserclass CarModel(models.Model):# 车型name = models.CharField(max_length=19, null=True)price = models.CharField(max_length=19, null=True)carFactory = models.ForeignKey(to='CarFactory', on_delete=models.CASCADE, null=True)distributor = models.ManyToManyField(to='Distributor', null=True)# 这两个方法是将车厂、经销商详情封装成字典和列表的序列化过程def carFactory_detail(self):return {'name': self.carFactory.name, 'addr': self.carFactory.addr, 'mobile': self.carFactory.mobile}def distributor_list(self):distributor_list = []for i in self.distributor.all():distributor_list.append({'name': i.name, 'addr': i.addr, 'mobile': i.mobile})return distributor_listclass CarFactory(models.Model):# 车厂name = models.CharField(max_length=19, null=True)addr = models.CharField(max_length=19, null=True)mobile = models.CharField(max_length=11, null=True)class Distributor(models.Model):# 经销商name = models.CharField(max_length=19, null=True)addr = models.CharField(max_length=19, null=True)mobile = models.CharField(max_length=11, null=True)class UserLog(AbstractUser):# 用户mobile = models.CharField(max_length=11, null=True)
settings注册用户表
AUTH_USER_MODEL = 'car.UserLog'
views.py
from rest_framework.viewsets import ViewSetMixin
from rest_framework.generics import ListCreateAPIView, DestroyAPIView, UpdateAPIView
from car.models import CarFactory, CarModel, Distributor
from car.MySerializers import CarModelSerializer, CarFactorySerializer, DistributorSerializer# 用viewsets的子类创建增删改查接口
class CarModelView(ViewSetMixin, ListCreateAPIView, DestroyAPIView, UpdateAPIView):queryset = CarModel.objects.all()serializer_class = CarModelSerializerclass CarFactoryView(ViewSetMixin, ListCreateAPIView, DestroyAPIView, UpdateAPIView):queryset = CarFactory.objects.all()serializer_class = CarFactorySerializerclass DistributorView(ViewSetMixin, ListCreateAPIView, DestroyAPIView, UpdateAPIView):queryset = Distributor.objects.all()serializer_class = DistributorSerializer
MySerializers.py
from rest_framework_simplejwt.serializers import TokenObtainPairSerializerfrom car.models import CarModel, CarFactory, Distributor, UserLog
from rest_framework import serializersclass CarModelSerializer(serializers.ModelSerializer):class Meta:model = CarModel# fields限定字段,将仅用于序列化的字段进行拆分fields = ['id', 'name', 'price', 'carFactory', 'distributor', 'carFactory_detail', 'distributor_list']extra_kwargs = {'id': {'read_only': True},'carFactory_detail': {'read_only': True},'distributor_list': {'read_only': True},}class CarFactorySerializer(serializers.ModelSerializer):class Meta:model = CarFactoryfields = '__all__'class DistributorSerializer(serializers.ModelSerializer):class Meta:model = Distributorfields = '__all__'class UserLogSerializer(serializers.ModelSerializer):class Meta:model = UserLogfields = '__all__'# 重写登录接口的序列化类,自定制返回格式
class CommonTokenObtainSerializer(TokenObtainPairSerializer):def validate(self, attrs):# 获取父类的元素,也就是默认的返回内容dic = super().validate(attrs)data = {'code': 100,'msg': '登录成功','username': self.user.username,'token': dic.get('access')}return data
MyValidate.py
重写权限类
from rest_framework.permissions import BasePermissionclass Permission(BasePermission):def has_permission(self, request, view):# 首先判断发送请求的是否为超级用户,如果是则直接返回if not request.user.is_superuser:# 如果请求的路由是'CarModelView'且为GET、DELETE请求则访问通过if view.basename == 'CarModelView' and request.method == 'DELETE' or request.method == 'GET':return Trueelse:return Falsereturn True
MyFilter.py
重写过滤类
from rest_framework.filters import BaseFilterBackendclass CommonFilter(BaseFilterBackend):def filter_queryset(self, request, queryset, view):# 精准查询# 示例:http://127.0.0.1:8000/car/?name=张三name = request.query_params.get('name', None)if name:queryset = queryset.filter(name__contains=name)return queryset
MyPagination.py
重写分页类
from rest_framework.pagination import PageNumberPagination# 1.基本分页
class CommonPageNumberPagination(PageNumberPagination):# 每页显示2条page_size = 2# http://127.0.0.1:8008/publish/?page=2 当前页数page_query_param = 'page'# http://127.0.0.1:8008/publish/?page=2&size=3 每页显示条数page_size_query_param = 'size'# 每页最多显示10条max_page_size = 10# 示例# http://127.0.0.1:8008/publish/?page=2 查询第二页,每页显示2条
settings注册自定义类
REST_FRAMEWORK = {# DRF默认权限类'DEFAULT_PERMISSION_CLASSES': ('car.MyValidate.Permission',),# DRF默认认证类'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework_simplejwt.authentication.JWTAuthentication',),# DRF默认分页类'DEFAULT_PAGINATION_CLASS': ('car.MyPagination.CommonPageNumberPagination'),# DRF默认过滤类'DEFAULT_FILTER_BACKENDS': ['car.MyFilter.CommonFilter'],}
国际化输出
让jwt和drf默认的返回信息变成中文
# settings.pyINSTALLED_APPS = ['django.contrib.admin','django.contrib.auth','django.contrib.contenttypes','django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles','car','rest_framework','rest_framework_simplejwt',
]LANGUAGE_CODE = 'zh-hans'TIME_ZONE = 'Asia/Shanghai'USE_I18N = TrueUSE_TZ = False