django-rest-framework 基础二 序列化器和路由

1. 序列化器

1. 序列化,序列化器会把模型对象(qs,book)转换成字典,经过response以后变成json字符串
2. 反序列化,把客户端发(前端)送过来的数据,经过request以后变成字典(data),序列化器可以把字典转成模型-->存到数据库中
3. 反序列化,完成数据校验功能---》前端传入的数据是否合法,长度够不够等等, 进行数据校验

1.1 Serializer的使用

使用序列化器完成增删改查接口

准备数据,modles.py

from django.db import models

# Create your models here.
class Book(models.Model):
name = models.CharField(max_length=128)
auth = models.CharField(max_length=128)
price = models.DecimalField(decimal_places=2, max_digits=5)
"""
增加一个书籍表
数据库迁移:
python3 manage.py makemigrations
python3 manage.py migrate 如果之前这些步骤做过,可以忽略
"""

序例化文件serializers.py

from rest_framework import serializers
from drftest.models import Book class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(min_length=3) # 不但序列化,而且限制最小长度不能小于3
auth = serializers.CharField()
price = serializers.DecimalField(decimal_places=2, max_digits=5) def create(self, validated_data):
# validated_data校验过后的数据
book = Book.objects.create(**validated_data)
return book # 返回新增的对象 def update(self, instance, validated_data):
# instance为要修改的对象
# validated_data校验过后的数据
instance.name = validated_data.get('name')
instance.auth = validated_data.get('auth')
instance.price = validated_data.get('price')
instance.save() # 模型对象自带的save,保存到数据库中(必须要save,否则只修改了数据,但没有保存到数据库里)
return instance """
必须要重写create和update 因为save里只是定义了,但没具体实现,因为不知道具体存到哪个表中,所以要在序列化类中实现 def update(self, instance, validated_data):
raise NotImplementedError('`update()` must be implemented.') def create(self, validated_data):
raise NotImplementedError('`create()` must be implemented.')
"""

视图函数views.py

from drftest.serializers import BookSerializer
from drftest.models import Book from rest_framework.views import APIView
from rest_framework.response import Response class BookView(APIView):
# 查全部的数据
def get(self,request):
book_list = Book.objects.all()
res = BookSerializer(instance=book_list, many=True)
return Response(res.data)
# 新增一条的数据
def post(self, request):
res = BookSerializer(data=request.data)
if res.is_valid(): # 校验数据
res.save() # 校验通过保存数据,保存时要重写create 方法,在序列化文件里
return Response(res.data)
return Response({"code" : 1001, "msg" : "数据验证失败", "error" : res.errors}) class BookViewDetail(APIView):
# 查某一条的数据
def get(self,request,pk):
book_list = Book.objects.filter(pk=pk).first()
res = BookSerializer(instance=book_list)
return Response(res.data)
# 修改某一条的数据
def put(self,request, pk):
book_list = Book.objects.filter(pk=pk).first()
# 既有instance,又有data,表示修改
res = BookSerializer(instance=book_list, data=request.data)
if res.is_valid(): # 校验数据
res.save() # 校验通过保存时要重写update 方法,在序列化文件里
return Response(res.data)
return Response({"code": 1001, "msg": "数据验证失败", "error": res.errors}) # 删除某一条的数据
def delete(self, request, pk):
res = Book.objects.filter(pk=pk).delete()
print(res)
return Response({"code": 1002, "msg": "数据删除成功"})

路由urls.py

from django.contrib import admin
from django.urls import path
from drftest import views urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookViewDetail.as_view()),
]

示例:

查全部数据

查某一条数据:

新增一条数据:

修改一条数据(修改价格为12.9)

删除一条数据:

总结

  • 第一步:写一个类:必须继承drf中的Serializer及其子类

  • 第二步:在类中写要序列化的字段-->要序列化哪些,就写哪些,不序列化的不写

  • 第三步:使用序列化类,视图类中用

    得到序列化类对象 对象.data,通过Response返回给前端

1.2 序列化器中的字段类型

字段 字段构造方式
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)
EmailField EmailField(max_length=None, min_length=None, allow_blank=False)
RegexField RegexField(regex, max_length=None, min_length=None, allow_blank=False)
SlugField SlugField(maxlength=50, min_length=None, allow_blank=False) 正则字段,验证正则模式 [a-zA-Z0-9-]+
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField(format=’hex_verbose’) format: 1) 'hex_verbose'"5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2) 'hex'"5ce0e9a55ffa654bcee01238041fb31a" 3)'int' - 如: "123456789012312313134124512351145145114" 4)'urn' 如: "urn:uuid:5ce0e9a5-5ffa-654b-cee0-1238041fb31a"
IPAddressField IPAddressField(protocol=’both’, unpack_ipv4=False, **options)
IntegerField IntegerField(max_value=None, min_value=None)
FloatField FloatField(max_value=None, min_value=None)
DecimalField DecimalField(max_digits, decimal_places, coerce_to_string=None, max_value=None, min_value=None) max_digits: 最多位数 decimal_palces: 小数点位置
DateTimeField DateTimeField(format=api_settings.DATETIME_FORMAT, input_formats=None)
DateField DateField(format=api_settings.DATE_FORMAT, input_formats=None)
TimeField TimeField(format=api_settings.TIME_FORMAT, input_formats=None)
DurationField DurationField()
ChoiceField ChoiceField(choices) choices与Django的用法相同
MultipleChoiceField MultipleChoiceField(choices)
FileField FileField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ImageField ImageField(max_length=None, allow_empty_file=False, use_url=UPLOADED_FILES_USE_URL)
ListField ListField(child=, min_length=None, max_length=None)
DictField DictField(child=)

其中ListFieldDictFieldmodels中没有的类型,在反序列化时,如果前端传入列表或字典可以使用这两字段进行反序列化。

1.2.1 字段参数

写在字段类中的参数

选项参数:

参数名称 作用
max_length 最大长度(CharField)
min_lenght 最小长度(CharField)
allow_blank 是否允许为空(CharField)
trim_whitespace 是否截断空白字符(CharField)
max_value 最小值 (IntegerField)
min_value 最大值(IntegerField)

通用参数

参数名称 说明
read_only 表明该字段仅用于序列化输出,默认False
write_only 表明该字段仅用于反序列化输入,默认False
required 表明该字段在反序列化时必须输入,默认True
default 反序列化时使用的默认值
allow_null 表明该字段是否允许传入None,默认False
validators 该字段使用的验证器(不太用)
error_messages 包含错误编号与错误信息的字典
label 用于HTML展示API页面时,显示的字段名称
help_text 用于HTML展示API页面时,显示的字段帮助提示信息

通用参数中重点的两个:

"""
read_only:表明该字段仅用于序列化输出,默认False
如果 read_only=True,这个字段只用来做序列化
把对象---》json给前端 write_only:表明该字段仅用于反序列化输入,默认False
如果 write_only=True,这个字段只用来做反序列化
前端json---》存到数据库 什么都不写,表示既序列化,又反序列化
read_only=True 序列化给前端,前端看到的字段,但前端传数据的时候可以不传这个对应的字段
write_only=True 反序列化时,前端需要传什么过的字段
但一个字段里不能即写read_only=True又写write_only=True。 示例:
id = serializers.CharField(read_only=True)
name=serializers.CharField(max_length=32,min_length=3,)
auth=serializers.CharField(write_only=True)
"""

1.3 序列化时,定制序列化的字段

例如定制一个price_info字段

方法一:在序列化类中写

class BookSerializer(serializers.Serializer):
...
price_info = serializers.SerializerMethodField()
# 使用SerializerMethodField方法,下面必须要写一个 以get_开头后跟自定义字段名的函数
def get_price_info(self,obj):
return "price is " + str(obj.price) ... # 只在序列化中增加,其他的内容不变
"""
class ExampleSerializer(self):
extra_info = SerializerMethodField() def get_extra_info(self, obj):
return ... # Calculate some data to return. """

方法二:在models中写方法

"""models.py"""
from django.db import models # Create your models here. class Book(models.Model):
name = models.CharField(max_length=128)
auth = models.CharField(max_length=128)
price = models.DecimalField(decimal_places=2, max_digits=5) #以下为新增的自定义的字段
@property
def price_info(self):
return "price is " + str(self.price) # 在序列化类中
"""Serializers.py""" class BookSerializer(serializers.Serializer):
...
#models里定义,序列化中使用 read_only=True 只有序列化中使用
price_info = serializers.CharField(read_only=True)
... # 其他的内容不变

上面的两个方法的效果一样。

1.4 局部勾子和全局勾子

验证顺序:

先走字段选项参数的规则,再走局部钩子,最后是走全局钩子

1.4.1 字段选项参数的规则:

"""serializers.py"""

from rest_framework import serializers
from drftest.models import Book class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
name = serializers.CharField(min_length=3) # 不但序列化,而且限制最小长度不能小于3
auth = serializers.CharField()
price = serializers.DecimalField(decimal_places=2, max_digits=5) """
字段选项参数的规则:
name = serializers.CharField(min_length=3) 限制书籍名字最小长度不能小于3
price = serializers.DecimalField(decimal_places=2, max_digits=5)
"""

书籍名字为不符合规范

书籍名字为不符合规范并价钱也不符合

1.4.2 局部勾子验证

class BookSerializer(serializers.Serializer):
def create(self, validated_data):pass
def update(self, instance, validated_data):
# 局部钩子,只验证某一个字段
# 要验证哪个字段, 必须要validate_开后,后面跟字段名,如:validate_name
def validate_name(self,attr):
if attr.startswith('xx'):
raise ValidationError("名字不能以xx开头")
else:
return attr # 没有问题,正常返回

验证(虽然符合字段的规范,但不符合局部勾子的规范)

1.4.3 全部勾子

class BookSerializer(serializers.Serializer):
def create(self, validated_data):pass
def update(self, instance, validated_data): def validate(self, attrs):
# attrs校验过后的数据
if attrs.get('name') == attrs.get('auth'):
raise ValidationError('作者名不能等于书名')
else:
return attrs

1.5 ModelSerializer模型类序列化器

上面使用的序列化器写出的接口,在新增和修改的时候必须要重写createupdate方法,可以使用ModelSerializer跟表模型做绑定,就不需要重写createupdate方法了。

为了和之前写的做区分,继承ModelSerializer类的为第二个版本_v2

序列化serializers.py

class BookSerializer_v2(serializers.ModelSerializer):
class Meta:
model = Book
# fields = '__all__' # 拿全部字段
fields = ['id','name','auth', 'price','price_info'] # 没有create 和updata方法了
# 局部勾子
def validate_name(self, attr):
if attr.startswith('YY'):
raise ValidationError("名字不能以YY开头")
else:
return attr # 没有问题,正常返回
# 全局勾子
def validate(self, attrs):
# attrs校验过后的数据
if attrs.get('name') == attrs.get('auth'):
raise ValidationError('作者名不能等于书名')
else:
return attrs

视图views.py

class BookView_v2(APIView):
def get(self,request):
book_list = Book.objects.all()
res = BookSerializer_v2(instance=book_list, many=True)
return Response(res.data) def post(self, request):
res = BookSerializer_v2(data=request.data)
if res.is_valid():
res.save()
return Response(res.data)
return Response({"code" : 1001, "msg" : "数据验证失败", "error" : res.errors}) class BookViewDetail_v2(APIView):
def get(self, request, pk):
book_list = Book.objects.filter(pk=pk).first()
res = BookSerializer_v2(instance=book_list)
return Response(res.data) def put(self, request, pk):
book_list = Book.objects.filter(pk=pk).first()
# 既有instance,又有data,表示修改
res = BookSerializer_v2(instance=book_list, data=request.data)
if res.is_valid():
res.save()
return Response(res.data)
return Response({"code": 1001, "msg": "数据验证失败", "error": res.errors}) def delete(self, request, pk):
res = Book.objects.filter(pk=pk).delete()
print(res)
return Response({"code": 1002, "msg": "数据删除成功"})

路由urls.py

rom django.contrib import admin
from django.urls import path
from drftest import views urlpatterns = [
path('admin/', admin.site.urls),
path('books/', views.BookView.as_view()),
path('books/<int:pk>/', views.BookViewDetail.as_view()),
path('books_v2/', views.BookView_v2.as_view()),
path('books_v2/<int:pk>/', views.BookViewDetail_v2.as_view()),
]

访问新接口:

修改一条数据

原数据:

修改价格为:12.8

使用ModelSerializer不用写createupdate方法,依然可以修改和新增。

1.5.1 增加额外的参数

上面的方法不用写createupdate方法了,但是如果想在使用字段选项参数,没办法直接传参数了。

解决方法:

extra_kwargs = {'字段名':{参数:值}}

序列化serializers.py

class BookSerializer_v2(serializers.ModelSerializer):
class Meta:
model = Book
# fields = '__all__' # 拿全部字段
fields = ['id','name','auth', 'price','price_info'] # 使用字段选项参数
extra_kwargs = {
'id':{'read_only':True},
'price_info':{'read_only':True},
'name':{'min_length':3,'max_length':5} } def validate_name(self, attr):
if attr.startswith('YY'):
raise ValidationError("名字不能以YY开头")
else:
return attr # 没有问题,正常返回
# 全局勾子
def validate(self, attrs):
# attrs校验过后的数据
if attrs.get('name') == attrs.get('auth'):
raise ValidationError('作者名不能等于书名')
else:
return attrs # 如果也想在这里面定制字段,比如像上面一样,增加price_info,
# price_info,它不是数据库中字段,但也要在fields中注册
fields = ['id','name','auth', 'price','price_info'] # price_info字段的增加也只能使用在models.py中写方法了
"""models.py代码:""" from django.db import models # Create your models here. class Book(models.Model):
name = models.CharField(max_length=128)
auth = models.CharField(max_length=128)
price = models.DecimalField(decimal_places=2, max_digits=5)
@property
def price_info(self):
return "price is " + str(self.price)

1.6 序列化多表操作

拿书籍的数据时,不但要拿基本信息,还要拿对应的出版社和作者

序列化serializers.py

from rest_framework import serializers
from drftest.models import Book
from django.core.exceptions import ValidationError class BookSerializer_v2(serializers.ModelSerializer):
class Meta:
model = Book
# fields = '__all__' # 拿全部字段
fields = ['id','name','auth', 'price','price_info','publish_list','auth_list'] extra_kwargs = {
'id':{'read_only':True},
'price_info':{'read_only':True},
'price':{'write_only':True},
'name':{'min_length':3,'max_length':5},
'publish_list':{'read_only':True},
'auth_list':{'read_only':True}, } def validate_name(self, attr):
if attr.startswith('YY'):
raise ValidationError("名字不能以YY开头")
else:
return attr # 没有问题,正常返回
# 全局勾子
def validate(self, attrs):
# attrs校验过后的数据
if attrs.get('name') == attrs.get('auth'):
raise ValidationError('作者名不能等于书名')
else:
return attrs

models.py

from django.db import models

# Create your models here.

class Book(models.Model):
name = models.CharField(max_length=128)
auth = models.CharField(max_length=128)
price = models.DecimalField(decimal_places=2, max_digits=5)
publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE,default=1)
bookToAuth = models.ManyToManyField(to='Authors') @property
def price_info(self):
return "price is " + str(self.price) @property
def publish_list(self):
#单条数据
return {'name':self.publish.name,"address":self.publish.address,'phone':self.publish.phone} @property
def auth_list(self):
# 多条数据
l = []
for auth in self.bookToAuth.all():
l.append({"name":auth.name, 'city':auth.city})
return l class Publish(models.Model):
name = models.CharField(max_length=255)
address = models.CharField(max_length=255)
phone = models.CharField(max_length=20) class Authors(models.Model):
name = models.CharField(max_length=128)
city = models.CharField(max_length=128)
authdetail = models.ForeignKey(to='AuthDetail', on_delete=models.CASCADE,default=1) class AuthDetail(models.Model):
address = models.CharField(max_length=255)
phone = models.CharField(max_length=20)

views.py

class BookView_v2(APIView):
def get(self,request):
book_list = Book.objects.all()
res = BookSerializer_v2(instance=book_list, many=True)
return Response(res.data) def post(self, request):
res = BookSerializer_v2(data=request.data)
if res.is_valid():
res.save()
return Response(res.data)
return Response({"code" : 1001, "msg" : "数据验证失败", "error" : res.errors}) class BookViewDetail_v2(APIView):
def get(self, request, pk):
book_list = Book.objects.filter(pk=pk).first()
res = BookSerializer_v2(instance=book_list)
return Response(res.data) def put(self, request, pk):
book_list = Book.objects.filter(pk=pk).first()
# 既有instance,又有data,表示修改
res = BookSerializer_v2(instance=book_list, data=request.data)
if res.is_valid():
res.save()
return Response(res.data)
return Response({"code": 1001, "msg": "数据验证失败", "error": res.errors}) def delete(self, request, pk):
res = Book.objects.filter(pk=pk).delete()
print(res)
return Response({"code": 1002, "msg": "数据删除成功"})

urls.py

rom django.contrib import admin
from django.urls import path
from drftest import views urlpatterns = [
path('admin/', admin.site.urls),
path('books_v2/', views.BookView_v2.as_view()),
path('books_v2/<int:pk>/', views.BookViewDetail_v2.as_view()),
]

注意: 查询、修改和删除都没有问题,但是新增有问题,因为涉及到多表,而且Book表中的publish字段为主键和Publish表相关联。直接新增会报错,要先在Publish表中有了相关数据才能新增,同理Authors表中新增也一样,它和AuthDetail相关联。所以对应的表中都了数据才新增成功。

1.7 编写视图函数

之前继承APIView编写视图函数,现在可以使用GenericAPIView它继承了APIView,比之前多了一些属性和方法。

1.7.1 编写视图函数第二种方法

继承GenericAPIView方法写视图函数(以publish表为例,编写5个接口),其他的内容不动。

views.py

from django.shortcuts import render
from drfViews.serializers import BookSerializer, BookSerializer_v2, PublishSerializer,AuthDetailSerializer,AuthorsSerializer
from drfViews.models import Book, Publish,AuthDetail, Authors from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.response import Response class PublishView(GenericAPIView):
queryset = Publish.objects.all() # 这个Publish表中全部数据,名字必须为queryset
serializer_class = PublishSerializer # 用来序列化的类, 名字必须为serializer_class def get(self,request):
obj = self.get_queryset() # get_queryset就是queryset
# ser = self.serializers(instance=obj,many=True)
ser = self.get_serializer(instance=obj, many = True) # 和上面的代码同样功能 return Response(ser.data) def post(self,request):
# ser = PublishSerializer(data=request.data)
ser = self.get_serializer(data=request.data) # 和上面的代码同样功能
if ser.is_valid():
ser.save()
return Response({"code": 2000, 'msg': '数据新增成功', 'data': ser.data})
return Response({"code": 4000, 'msg': '数据检验失败', 'errors': ser.errors}) class PublishViewDetail(GenericAPIView):
queryset = Publish.objects.all()
serializer_class = PublishSerializer def get(self,request, *args, **kwargs):
# publish = Publish.objects.all().filter(pk=pk).first()
obj = self.get_object() # 和上面的代码同样功能 # ser = PublishSerializer(instance=publish)
ser = self.get_serializer(instance=obj) # 和上面的代码同样功能 return Response(ser.data) def put(self,request, *args, **kwargs):
obj = self.get_object()
ser = self.get_serializer(instance = obj, data = request.data) # # 既有instance,又有data,表示修改
if ser.is_valid():
ser.save()
return Response({"code": 2001, 'msg': '数据修改成功', 'data': ser.data})
return Response({"code": 4000, 'msg': '数据检验失败', 'errors': ser.errors}) def delete(self,request, *args, **kwargs):
obj = self.get_object().delete()
return Response({"code": 2002, 'msg': '数据删除成功'})

路由ulrs.py

from django.contrib import admin
from django.urls import path, include
from drfViews import views urlpatterns = [
path('admin/', admin.site.urls),
path('publish/',views.PublishView.as_view()),
path('publish/<int:pk>/',views.PublishViewDetail.as_view()),
]

GET查全部

POST 新增数据

GET 查一条数据

PUT 修改数据

DELETE 删除数据

1.7.2 编写视图函数第三种方法

使用rest_framework.mixins里面的五个扩展视图类配合GenericAPIView

from rest_framework.mixins import
ListModelMixin, # 列出所有数据集(get查所有)
CreateModelMixin, # 创建实例(post创建数据)
DestroyModelMixin, # 删除实例 (delete删除数据)
RetrieveModelMixin, # 检索实例 (get查一条数据)
UpdateModelMixin # 更新实例 (put更新数据)
这5个是视图扩展类(不是视图类,没有集成APIView,需要配合GenericAPIView),这五个类是单独的,它们没用继承其他类 这五个扩展视图类在使用的时候,一定要配合GenericAPIView

(以Authors表为例,编写5个接口)

views.py

from django.shortcuts import render
from drfViews.serializers import BookSerializer, BookSerializer_v2, PublishSerializer,AuthDetailSerializer,AuthorsSerializer
from drfViews.models import Book, Publish,AuthDetail, Authors from rest_framework.views import APIView
from rest_framework.generics import GenericAPIView
from rest_framework.mixins import CreateModelMixin,ListModelMixin,DestroyModelMixin,RetrieveModelMixin,UpdateModelMixin
from rest_framework.response import Response # 取全部数据和新增,继承CreateModelMixin,ListModelMixin
class AuthorsView(GenericAPIView,CreateModelMixin,ListModelMixin):
queryset = Authors.objects.all() # 拿到实例
serializer_class = AuthorsSerializer # 序列化类 def get(self,request):
return super().list(request) # 取全部数据 def post(self,request):
return super().create(request) # 取新增数据 class AuthorsDetailView(GenericAPIView, UpdateModelMixin,DestroyModelMixin,RetrieveModelMixin):
queryset = Authors.objects.all()
serializer_class = AuthorsSerializer def get(self, request, *args, **kwargs):
return super().retrieve(request, *args, **kwargs) # 取某指定数据(一条) def put(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs) # 更新数据 def delete(self,request, *args, **kwargs):
return super().destroy(request, *args, **kwargs) # 删除数据

路由urls.py

from django.contrib import admin
from django.urls import path
from drfViews import views urlpatterns = [
path('admin/', admin.site.urls),
path('author/', views.AuthorsView.as_view()),
path('author/<int:pk>/', views.AuthorsDetailView.as_view()),
]

由于AuthorsAuthDetail表有外键关联,在新增作者的时候,作者详情表要先有对应的数据才能新增成功,

所以在新增作者的时候要么先新增作者详情表,要么在models.pyAuthors里面重写create方法新增这两个表的数据。

serializers.pyAuthorSerialzier里面重写create方法:

serializers.py

address = serializers.CharField(write_only=True)
phone = serializers.CharField(max_length=20, write_only=True) def create(self,validated_data):
datail = AuthDetail.objects.create(address=validated_data.get('address'), phone=validated_data.get('phone'))
print(datail)
author = Authors.objects.create(authdetail=datail, name=validated_data.get('name'),city=validated_data.get('city'))
return author

1.7.3 编写视图函数第四种方法

通过9个视图子类,编写视图函数.

from rest_framework.generics import
CreateAPIView, # 创建 (POST)
ListAPIView, # 显示 (GET查全部)
DestroyAPIView, # 删除 (delete)
RetrieveAPIView, # 筛选 (GET查某一条)
UpdateAPIView, # 更新 (UPDATE)
ListCreateAPIView, # 创建和显示 (POST、GET全部)
RetrieveUpdateAPIView, #筛选和更新 (GET查某一条、UPDATE)
RetrieveUpdateDestroyAPIView, # 筛选,更新和删除 (GET查某一条、UPDATE和DELETE)
RetrieveDestroyAPIView # 筛选和删除 (GET查某一条和DELETE) 继承了这些类后,里面的增删改查接口都现实了。

AuthDetail表为例实现五个接口

views.py

from rest_framework.generics import CreateAPIView, ListAPIView,UpdateAPIView,RetrieveAPIView, DestroyAPIView

class AuthDetailView(ListAPIView,CreateAPIView):
# 查询所有和新增
queryset = AuthDetail.objects.all()
serializer_class = AuthDetailSerializer class AuthDetail_detailView(RetrieveAPIView,UpdateAPIView,DestroyAPIView):
# 查询单条,删除,修改
queryset = AuthDetail.objects.all()
serializer_class = AuthDetailSerializer

urls.py

from django.contrib import admin
from django.urls import path, include
from drfViews import views urlpatterns = [
path('admin/', admin.site.urls), path('authDetail/', views.AuthDetailView.as_view()),
path('authDetail/<int:pk>/', views.AuthDetail_detailView.as_view()),
]

GET获取所有

POST新增

GET获取一条

PUT修改

DELETE删除

除了这五个类之外还有四个组合的类

from rest_framework.generics import
ListCreateAPIView,
RetrieveUpdateAPIView,
RetrieveUpdateDestroyAPIView,
RetrieveDestroyAPIView,

使用这四个组合的类:

from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView, RetrieveUpdateAPIView,RetrieveDestroyAPIView

class AuthDetailView(ListCreateAPIView):
# 就相当于ListAPIView,CreateAPIView 查询所有和新增
queryset = AuthDetail.objects.all()
serializer_class = AuthDetailSerializer class AuthDetail_detailView(RetrieveUpdateDestroyAPIView):
# 相当于:RetrieveAPIView,UpdateAPIView,DestroyAPIView 查询单条,删除,修改
queryset = AuthDetail.objects.all()
serializer_class = AuthDetailSerializer #实现和上面一样的结果 class AuthDetail_detailView(RetrieveUpdateAPIView) # 查询单条和更新 class AuthDetail_detailView(RetrieveDestroyAPIView) # 查询单条和删除 class AuthDetail_detailView(UpdateAPIView,DestroyAPIView) # 更新和删除 # 这种方法以后是用的最多的,因为可以重写一些方法:
# 有可能要重写--》get_queryset--》get_serializer_class--》perform_create--》get,post方法

1.7.4 编写视图函数第五种方法

5个接口都使用一个视图类:ModelViewSet,但是需要修改路由。

views.py

from rest_framework.viewsets import ModelViewSet

class AuthDetailView(ModelViewSet):   # 5个接口
queryset = AuthDetail.objects.all()
serializer_class = AuthDetailSerializer

urls.py

from django.contrib import admin
from django.urls import path
from drfViews import views
#导入DRF的routers模块
from rest_framework import routers router = routers.SimpleRouter()
#注册
router.register('authDetailView',views.AuthDetailView, 'authDetailView') urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls

这样五个接口就可以访问了。

但有时候,我们只想让访问GET接口,其他的接口不能访问,就可以使用ReadOnlyModelViewSet

"""views.py"""
from rest_framework.viewsets import ReadOnlyModelViewSet class AuthDetailView(ReadOnlyModelViewSet):
queryset = AuthDetail.objects.all()
serializer_class = AuthDetailSerializer """urls.py""" from django.contrib import admin
from django.urls import path
from drfViews import views
#导入DRF的routers模块
from rest_framework import routers router = routers.SimpleRouter()
#注册
router.register('authDetailView',views.AuthDetailView, 'authDetailView') urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls 使用GET方法访问时是没有问题的,但使用POST,PUT,DELETE方法则会报错 "detail": "Method \"POST\" not allowed."
"detail": "Method \"PUT\" not allowed."
"detail": "Method \"DELETE\" not allowed."

ModelViewSetReadOnlyModelViewSet之所有能达到这种效果,主要是它们继承了以下几个类。

from rest_framework.viewsets import 

class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass class ReadOnlyModelViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass """
CreateModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin,
ListModelMixin,
""" # 这五个就是上面写的增删改查的 扩展视图类 # 而且这两个类都继承了GenericViewSet,
class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
pass # 之所有要重写路由主要是:ViewSetMixin类,使用它就必须要重写路由。

以后只要想重写路由必须要继承ViewSetMixin类或子类

from rest_framework.viewsets import
ViewSetMixin ModelViewSet = CreateModelMixin+RetrieveModelMixin+UpdateModelMixin+DestroyModelMixin+ListModelMixin+GenericViewSet ReadOnlyModelViewSet = RetrieveModelMixin+ListModelMixin+GenericViewSet GenericViewSet = ViewSetMixin+generics.GenericAPIView ViewSet = ViewSetMixin + views.APIView # 只要继承了ViewSetMixin以子类ModelViewSet,ReadOnlyModelViewSet,GenericViewSet,ViewSet就必须在urls.py里导入routes自动生成路由

1.7.5 以上类的总结:

2. 路由组件

2.1 两种使用ViewSetMixin的方法

# 方法一:
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin class TestAPIView(ViewSetMixin,APIView): # ViewSetMixin必须要写在前面
pass from rest_framework.viewsets import ViewSet
class TestAPIView(ViewSet):
pass TestAPIView(ViewSet) == TestAPIView(ViewSetMixin,APIView): # 方法二:
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import ViewSetMixin class TestGenericAPIView(ViewSetMixin,GenericAPIView): # ViewSetMixin必须要写在前面
pass from rest_framework.viewsets import GenericViewSet
class TestGenericAPIView(GenericViewSet):
pass TestGenericAPIView(GenericViewSet) == TestGenericAPIView(ViewSetMixin,GenericAPIView):

只要继承了ViewSetMixin视图类中的方法就可以不用写成之前的get,post,put,delete,名字随意写,不过要在路由中写成path('url/',views.类名.as_view({'get':'自己定义的方法','put':'自己定义的方法2'}))

示例:

"""views.py"""
from rest_framework.viewsets import ViewSet
class TestView(ViewSet):
def list(self,request):
return Response("GET方法")
def create(self,request):
return Response("POST方法") """urls.py""" from django.contrib import admin
from django.urls import path
from drfViews import views urlpatterns = [
path('admin/', admin.site.urls),
path('testView/', views.TestView.as_view({'get':"list",'post':"create"})) ]

实例这种写法过程:

视图中的类中继承了ViewSetMixin类,而ViewSetMixin方法中重新写了as_view()方法,而重写的as_veiw()方法用法:
view = MyViewSet.as_view({'get': 'list', 'post': 'create'}) def as_view(cls, actions=None, **initkwargs):
其中actions就是{'get': 'list', 'post': 'create'},如果actions没有值则会报错:
"The `actions` argument must be provided when "
"calling `.as_view()` on a ViewSet. For example "
"`.as_view({'get': 'list'})`"

2.2 自动生成路由步骤:

自动生成路由必须要继承的类或子类:

GenericViewSet + 5个扩展视图类之一(
CreateModelMixin,
RetrieveModelMixin,
UpdateModelMixin,
DestroyModelMixin,
ListModelMixin,
)
才能自动生成,因为请求要相互对应:
{'get':'list','post':'create','put':'update','delete':'destroy','get':'retrieve'} # 这就是为什么ModelViewSet和 ReadOnlyModelViewSet可以自动生成路由,如果没有继承这5个扩展视图类之一,则不能自动生成

自动生成路由步骤:

# 第一步 导入routers
from django.urls import path, include
from rest_framework import routers
# 第二步 实例化:
router = routers.SimpleRouter() # 第三步 注册:
router.register('URL地址',views.对应的类名, '别名')
router.register('authDetailView',views.AuthDetailView, 'authDetailView')
# 第四步:
urlpatterns += router.urls

urlpatterns = [
path('URL地址', include(router.urls) )
]

2.3 action再生成路由

from rest_framework.viewsets import GenericViewSet

from rest_framework.decorators import action

class TestView(GenericViewSet):
@action(methods=['GET', 'POST'], detail=False)
def login(self,request):
return Response("GET方法")
def test(self,request):
return Response("POST方法") action(methods=None, detail=None, url_path=None, url_name=None, **kwargs):
methods = 请求方式,是个列表
detail = 是否带id, False为不带
url_path= url地址,不写则默认方法名为地址
url_name = 别名 给上面的login加上action装饰器后,
会再之前http://172.0.0.1:8000/test/的后面生成路径--->:http://172.0.0.1:8000/test/login/
访问的时候直接访问http://172.0.0.1:8000/test/login/,由于方法里methods=['GET', 'POST']写了get和post方法,所以get和post方法都会执行。
如果设置url_path
@action(methods=['GET', 'POST'], detail=False,url_path='hello')
def login(self,request):
则访问的时候就要访问:
http://172.0.0.1:8000/test/hello/ 如果 detail=True(方法不常用), 则访问路径: http://172.0.0.1:8000/test/pk值/login/ 代码:
"""
from rest_framework.viewsets import GenericViewSet
from rest_framework.decorators import action class TestView(GenericViewSet):
@action(methods=['GET', 'POST'], detail=True)
def login(self,request,pk):
return Response("GET方法")
def test(self,request):
return Response("POST方法")
""" 路由:urls.py
"""
from django.contrib import admin
from django.urls import path, include
from drfViews import views
from rest_framework import routers router = routers.DefaultRouter()
router.register('test',views.TestView,'test') urlpatterns = [
path('admin/', admin.site.urls),
path('api/',include(router.urls))
]
""" 上面把自动成生的路由放在了api里面所以访问地址:
http://127.0.0.1:8000/api/test/login/

django-rest-framework 基础二 序列化器和路由的更多相关文章

  1. Django REST framework 中的序列化器

    在此之前定义一个序列化工具:     views中的的代码 from rest_framework.viewsets import ModelViewSet from .models import B ...

  2. Django REST framework基础:解析器和渲染器

    解析器 解析器的作用 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己可以处理的数据.本质就是对请求体中的数据进行解析. 在了解解析器之前,我们要先知道Accept以及ContentTy ...

  3. Django REST framework基础:序列化

    表结构: class Article(models.Model): id = models.AutoField(primary_key=True) title = models.CharField(m ...

  4. Django rest framework 基础

    01: Django rest framework 基础 ​ ​ 1.1 什么是RESTful 1. REST与技术无关,代表的是一种软件架构风格(REST是Representational Stat ...

  5. 一: DRF web应用框架基础,及序列化器的使用

    ---恢复内容开始--- 一: web 应用模式(有两种) 1: 前后端不分离(前端从后端直接获取数据) 2: 前后端分离 二: api 接口 原因一: 为了在团队内部形成共识.防止个人习惯差异引起的 ...

  6. Django Rest framework基础使用之View:APIView, mixins, generic, viewsets

    先看一张图,对DRF的各个APIView,Mixin,Viewset等有个基本印象: 具体使用方法: 1.APIView: DRF 的API视图 有两种实现方式: 一种是基于函数的:@api_view ...

  7. Django REST framework基础:视图和路由

    DRF中的Request 在Django REST Framework中内置的Request类扩展了Django中的Request类,实现了很多方便的功能--如请求数据解析和认证等. 比如,区别于Dj ...

  8. Django Rest framework基础使用之Request/Response

    1.Request restframework提供了一个Request对象(rest_framework.request.Request) Request对象继承了Django默认的HttpReque ...

  9. Django Rest framework基础使用之 serializer

    rest-framework文档地址:http://www.django-rest-framework.org/ Django Rest framework是一个非常强大且灵活的工具包,用于构建web ...

随机推荐

  1. 解释 WEB 模块?

    Spring 的 WEB 模块是构建在 application context 模块基础之上,提供一个适 合 web 应用的上下文.这个模块也包括支持多种面向 web 的任务,如透明地处理 多个文件上 ...

  2. 说出 5 条 IO 的最佳实践?

    IO 对 Java 应用的性能非常重要.理想情况下,你不应该在你应用的关键路径上 避免 IO 操作.下面是一些你应该遵循的 Java IO 最佳实践: a)使用有缓冲区的 IO 类,而不要单独读取字节 ...

  3. 【代码开源】GreaterWMS 抖音SDK调用教程

    应用介绍 GreaterWMS 抖音SDK调用教程 SDK具体功能: 1,一仓多店,多仓多店 2,库存同步,商品同步 3,快递发货,物流轨迹 4,订单拦截 5,字节云仓 6,精选联盟 7,供应分销 8 ...

  4. javascript 判断变量是否是数组(Array)

    过完春节又有好多人寻找新的机会,旁边的人面试完就会分享一些问题,明明会的但是面试的时候,想不全,面试官不满意...这个懊恼的行为,今天的文章跟大家分享下:javascript如何判断便是是数组. 1. ...

  5. three.js 入门详解(一)

    1. 概述 1.1 什么是WebGL? WebGL是在浏览器中实现三维效果的一套规范 想要使用WebGL原生的API来写3D效果的话,很吃力.three.js是WebGL的一个开源框架,它省去了很多麻 ...

  6. tomcat 安装配置及问题解决

    最近没写程序 刚想运行一个jsp程序发现tomcat出现一些问题,然后就重新装了程序,重新配置 总结经验就是不要怕报错,把错误复制下来,百度里面都有解决办法 要安装与自己jdk版本相匹配的tomcat ...

  7. java中String类的用法

    1.String String类很常用,很重要. String不像int或float, 它是参考类型.final类型, 不能被继承,String is a Reference Type,Defined ...

  8. CCF201509-2日期计算

    问题描述 给定一个年份y和一个整数d,问这一年的第d天是几月几日? 注意闰年的2月有29天.满足下面条件之一的是闰年: 1) 年份是4的整数倍,而且不是100的整数倍: 2) 年份是400的整数倍. ...

  9. [ Perl ] 对文本文件进行行列翻转

    https://www.cnblogs.com/yeungchie/ code #!/usr/bin/env perl #----------------------------- # Program ...

  10. 麒麟系统开发笔记(三):从Qt源码编译安装之编译安装Qt5.12

    前言   上一篇,是使用Qt提供的安装包安装的,有些场景需要使用到从源码编译的Qt,所以本篇如何在银河麒麟系统V4上编译Qt5.12源码.   银河麒麟V4版本   系统版本:   Qt源码下载    ...