DRF important stage of learning Summary: *****

Disclaimer: This article is a blogger original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
This link: HTTPS: //blog.csdn.net/qq_39801390/article/details/81186928
----------------
Disclaimer: This article is CSDN blogger "Bullinger Bullinger, "the original article, follow the CC 4.0 BY-SA copyright agreement, reproduced, please attach the original source link and this statement.
Original link: https: //blog.csdn.net/qq_39801390/article/details/81186928

DRF Framework

I. know restful architecture

REST, Representational State Transfer namely the abbreviation, we generally call him 'presentation layer state transformation'

Path design ideas REST is simple: resources (such as HTML, or images, documents, and the like) he should be a noun, we have before when acquiring goods, we might write: / GET Products's / but this is not right .. wrong we should not appear in the path that is the verb get, we'll use the rest design path is: GET / products / GET request here is the way to express our way to get to request data, of course, we there is no need to enter the address bar GET Thus our path will be very concise.

HTTP verb

There are four HTTP verbs:

  • GET (SELECT): Remove the resource from the server (one or more).

  • POST (CREATE): a new resource on the server.

  • PUT (UPDATE): update the resource (after the complete resources provided by the client to change) in the server.

  • DELETE (DELETE): Delete the resource from the server.

Parentheses is the corresponding SQL commands.

This front is the concept. Write so it.

 

II. Serialization and deserialization

View generally do three things:

  • The requested data (such as JSON format) to an object model class

  • Database operations

  • Converting the response data object model classes (e.g. JSON format)

We we will be involved in the json data into the first and third steps into the model when the class object, and the object model classes will be converted into json data return back.

This will involve the issue of a duplicate conversions back and forth, so we use serialization and de-serialization.

Serialization and deserialization definitions:

Converting a type of data structure in the program to other formats (dictionaries, JSON, the XML, etc.), for example in Django installed for the class object model JSON string, we call this sequence of the conversion process. Conversely, to convert the other form (dictionaries, JSON, the XML, etc.) as the program data, for example, convert JSON string class object model in Django, a process we call deserialization.

Method 1. Definitions

For BookInfo Before we used to create a serializer.

class BookInfoSerializer(serializers.Serializer):
    "", "Book data serializer" ""
    id = serializers.IntegerField(label='ID', read_only=True)
    btitle = serializers.CharField(label='名称', max_length=20)
    bpub_date = serializers.DateField(label='发布日期', required=False)
    bread = serializers.IntegerField(label='阅读量', required=False)
    bcomment = serializers.IntegerField (label = 'comments amount', required = False)
    image = serializers.ImageField(label='图片', required=False)

The serializer inherit serializers.Serializer We define each field names and fields in the database is consistent, label indication label is displayed in the HTML page api, field names displayed .read_only indicates that the field is only used to sequence of output. that is only possible to read him, when he returned can return, received when he does not need to receive, because it is from the growing .required indicate whether it is required, false representation that can fill in, you can not fill in .

 

Field construction way

Field Field construction way
BooleanField BooleanField()
NullBooleanField NullBooleanField()
CharField CharField(maxlength=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 (max length = 50, min_length = None, allow_blank = False) regular field, to verify normal mode [A-zA-Z0-9 -] +
URLField URLField(max_length=200, min_length=None, allow_blank=False)
UUIDField UUIDField (format = 'hex_verbose')  format: 1) 'hex_verbose' As "5ce0e9a5-5ffa-654b-cee0-1238041fb31a" 2)  'hex' As  "5ce0e9a55ffa654bcee01238041fb31a" 3) 'int' - such as:  "123456789012312313134124512351145145114" 4) 'urn' as: "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: maximum number of digits decimal_palces: decimal point position
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 and usage of the same 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=)

This is the definition of each of the above types of syntax, which required not write, this is required which can each write.

 

Option parameter definitions of each option inside:

parameter name effect
max_length The maximum length
min_lenght The minimum length
allow_blank Whether to allow empty
trim_whitespace Whether or not cut blank character
max_value Minimum
min_value Maximum

Meaning common parameters in the following table:

parameter name Explanation
read_only Indicates that the sequence of output fields are used, default False
write_only This field is only used to indicate deserialization input, default False
required Indicates that the field must be entered at the time of deserialization, default True
default The default values ​​used when deserialization
allow_null It indicates whether the field allows incoming None, default False
validators This field is used to verify
error_messages It contains an error number and the error message dictionary
label Field Name HTML for display when the API page, displayed
help_text When the display API for HTML page, field displays help information

These tables can later be used when defining serialization filter.

Here add the difference allow_blank and allow_null:

null:
If True, Django will store empty values as NULL in the database. Default # 原文解释
is False.
    如果为True,空值将会被存储为NULL,默认为False。
blank:
    If True, the field is allowed to be blank. Default is False.  # 原文解释
    如果为True,字段允许为空,默认不允许。
    
    其实感觉没什么区别.

创建serializer对象

Serializer的构造结构:

Serializer(instance=None, data=empty, kwarg)

1)用于序列化时,将模型类对象传入instance参数

2)用于反序列化时,将要被反序列化的数据传入data参数

3)除了instance和data参数外,在构造Serializer对象时,还可通过context参数额外添加数据

下面是一个事例:

serializer = AccountSerializer(account, context={'request': request})

通过context添加的数据,我们可以使用Serializer对象的context属性获取.data数据我们也可以使用该对象的data属性获取,获取到的是序列化完成的数据.

2.序列化

基本的使用:

先创建一个模型类对象:book = BookInfo.objects.get(id=1)

然后创建一个序列化的对象:ser = BookInfoSerializer(book) # 此处的book就是instance

我们可以通过:ser.data取出序列化后的数据:

我们查询的不是一个数据,是多个数据,我们就要加上many = True 这个选项可以序列化模型类里面含有很多数据的情况.

关联对象的序列化

我们在定义一对多的多的一方是,定义外键有很多种办法:

  1. PrimaryKeyRelatedField

    这个是将被序列化为关键对象的主键.也就是bookinfo的主键

    hbook = serializers.PrimaryKeyRelatedField(label='图书', read_only=True)
    hbook = serializers.PrimaryKeyRelatedField(label='图书', queryset=BookInfo.objects.all())

read_only = True是指该字段将不能作为反序列化使用

query_set 表示将用作反序列化时参数校验使用.

  1. StringRelatedField

    这个将被序列化为关联对象的字符串表示方式(即str方法的返回值)

    我举个栗子:

    hbook = serializers.StringRelatedField(label='图书')

    在这里我们得到的data数据是:我们在str方法里面定义的返回的数据.

  2. 使用关联对象的序列化器

    这个也就是在hbook = BookInfoSerializer()

    就是将整个的序列器全部加进去.这样我们会得到一本书的所有信息.

  3. HyperlinkedRelatedField

    这里是我们将其序列化为获取关联对象数据的链接接口.

    for example:

    hbook = serializers.HyperlinkedRelatedField(label='图书', read_only=True, view_name='books-detail')

view_name = XXX 这里的view_name是必须要指明的,这样DRF框架才可以找到指定的路由,然后在拼接成一个完整的URL.

  1. SlugRelatedField

    这将被序列化为关联对象的指定字段数据

    hbook = serializers.SlugRelatedField(label='图书', read_only=True, slug_field='bpub_date')  # 也就是显示关联对象你想他显示的数据
  2. 重写to_representation()方法

    序列化器的每个字段其实都是都是有该字段类型的to_representation来决定的,我们重写他.

    class BookRelateField(serializers.RelatedField):
        """自定义用于处理图书的字段"""
        def to_representation(self, value):
            return 'Book: %d %s' % (value.id, value.btitle)

我们定义了一个新的关联字段类型,

hbook = BookRelateField(read_only = True)

3.反序列化

同样的,我们使用序列化器进行反序列化的时候,我们需要对数据进行验证,验证通过之后,我们才可以获取保存成功的数据,或者我们保存数据模型类的对象.

我们通过is_valid()来验证数据的正确性.

验证失败:我们可以用序列化对象.errors来获取错误

验证成功:我们可以使用序列化对象.validated_data 来获取数据

is_valid()方法还可以在验证失败时抛出异常serializers.ValidationError,可以通过传递raise_exception=True参数开启,REST framework接收到此异常,会向前端返回HTTP 400 Bad Request响应。 如:

serializer.is_valid(raise_exception=True)

我们还可以自定义验证方法:

  1. validate<fieldname>

    对我们后面填入的fieldname字段进行验证,在我们的BookInfoSerializer里面添加:

     def validatebtitle(self, value):
            if 'django' not in value.lower():
                raise serializers.ValidationError("图书不是关于Django的")
            return value

btitle就是fieldname 这样设置之后,这个方法就可以验证btitle的正确性了.btitle的值,就会传给value.

我们验证的时候,依然是用is_valid,来进行验证.

  1. validate

    一般需要将模型中的多个字段进行验证时,我们可以使用validate进行验证

    我们在BookInfoSerializer中定义一个validate方法:

     def validate(self, attrs):
            bread = attrs['bread']
            bcomment = attrs['bcomment']
            if bread < bcomment:
                raise serializers.ValidationError('阅读量小于评论量')
            return attrs

    3.validators

    我们在序列化器中添加选项参数,也可以补充验证行为.

    btitle = serializers.CharField(label='名称', max_length=20, validators=[about_django])

我们在类的上面定义一个about_Leijingjing方法:

def about_django(value):
    if 'Leijingjing' not in value.lower():
        raise serializers.ValidationError("图书不是关于Leijingjing的")

这就OK了.

4.保存

验证成功后,我们就可以保存了.我们在BookInfoSerializer里面定义两个方法:create(), update()

  def create(self, validated_data):
        """新建"""  # 用于将字典解包,解成 a = 1 的这种形式
        return BookInfo.objects.create(validated_data)
    def update(self, instance, validated_data):
        """更新,instance为要更新的对象实例"""
        instance.btitle = validated_data.get('btitle', instance.btitle)
        instance.bpub_date = validated_data.get('bpub_date', instance.bpub_date)
        instance.bread = validated_data.get('bread', instance.bread)
        instance.bcomment = validated_data.get('bcomment', instance.bcomment)
        instance.save()
        return instance

定义了这个之后,我们就可以在反序列化字段的时候,就可以使用save()来返回一个数据对象实例了.

如果创建序列化器对象的时候,没有传递instance实例,则调用save()方法的时候,create()被调用,相反,如果传递了instance实例,则调用save()方法的时候,update()被调用。

这很神奇,理解不了,只有记住了.

 

还有两点:

1) 在对序列化器进行save()保存时,可以额外传递数据,这些数据可以在create()和update()中的validated_data参数获取到

serializer.save(owner=request.user)

2)默认序列化器必须传递所有required的字段,否则会抛出验证异常。但是我们可以使用partial参数来允许部分字段更新

# Update comment with partial data
serializer = CommentSerializer(comment, data={'content': u'foo bar'}, partial=True)

...

5.模型类序列化器

在生成模型类序列化器的时候,有一些注意点.需要记一下.

我们生成一个模型类序列化器:BookInfoSerializer

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = '__all'

model 指向的是哪个模型类

fields指向的是我们序列化哪些字段.

指定字段

我们可以在操作fields 来实现字段控制:fields = ('id', 'btitle', 'bpub_date')

这个表示只显示这三个字段.

我们可以使用exclude来排除哪些字段:exclude = ('image',) 这是一个元祖.

我们可以使用depth来实现嵌套表示,depth是整数,它表示嵌套的层级数.

如:

class HeroInfoSerializer2(serializers.ModelSerializer):
    class Meta:
        model = HeroInfo
        fields = '__all'
        depth = 1

形成的序列化器如下: 在hbook后面又套了一层.

HeroInfoSerializer():
    id = IntegerField(label='ID', read_only=True)
    hname = CharField(label='名称', max_length=20)
    hgender = ChoiceField(choices=((0, 'male'), (1, 'female')), label='性别', required=False, validators=[<django.core.valators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
    hcomment = CharField(allow_null=True, label='描述信息', max_length=200, required=False)
    hbook = NestedSerializer(read_only=True):
        id = IntegerField(label='ID', read_only=True)
        btitle = CharField(label='名称', max_length=20)
        bpub_date = DateField(allow_null=True, label='发布日期', required=False)
        bread = IntegerField(label='阅读量', max_value=2147483647, min_value=-2147483648, required=False)
        bcomment = IntegerField(label='评论量', max_value=2147483647, min_value=-2147483648, required=False)
        image = ImageField(allow_null=True, label='图片', max_length=100, required=False)

我们还可以显示只读字段:

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        read_only_fields = ('id', 'bread', 'bcomment')  # 这些表示是只读字段,也就是只用于序列化输出的字段.

添加额外参数

我们可以使用extra_kwargs参数为ModelSerializer添加或修改原有的选项参数

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        extra_kwargs = {
            'bread': {'min_value': 0, 'required': True},
            'bcomment': {'min_value': 0, 'required': True},
        }

序列化与反序列化到此为止!!!

三.环境安装与配置

安装drf命令: pip install djangorestframework 然后在install_apps里面注册rest_framework

书写视图函数:在views.py中

class BookInfoViewSet(ModelViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer

定义路由:是在urls.py中定义的

urlpatterns = [
    ...
]
router = DefaultRouter()  # 可以处理视图的路由器
router.register(r'books', views.BookInfoViewSet)  # 向路由器中注册视图集
urlpatterns += router.urls  # 将路由器中的所以路由信息追到到django的路由列表

亖.视图及视图集

1.request 和 response

DRF框架封装了一个request对象在里面,我们就不在使用原来Django中的httprequest对象了.他一般有两个属性一个是.data ,一个是.query_params

request.data是对应于原先Django中的.json 和.files.这个也是使用最多的,有如下特点:

  • 包含了解析之后的文件和非文件数据

  • 包含了对POST、PUT、PATCH请求方式解析后的数据

  • 利用了REST framework的parsers解析器,不仅支持表单类型数据,也支持JSON数据

request.query_params 和原先Django中的GET方法相同,是获取查询字符串中的内容的.

同样的,框架内部也还有一个response对象,我们最开始需要在配置文件里面配置一下,如下

REST_FRAMEWORK = {
    'DEFAULT_RENDERER_CLASSES': (  # 默认响应渲染类
        'rest_framework.renderers.JSONRenderer',  # json渲染器
        'rest_framework.renderers.BrowsableAPIRenderer',  # 浏览API渲染器
    )
}

构造方式:Response(data, status=None, template_name=None, headers=None, content_type=None)

一般使用的最多的就是data 和status ,data指的是序列化之后的字典数据,但尚未render的数据. status表示状态码,还有一个.content表示render过后的数据.

2.视图

视图集,这里是一个链接,是各视图之间的关系.

 

可能看不清,不要慌,接着往下看

1)两个基类

APIView是DRF框架提供的所有视图的基类,他继承自Django的View类.他和Django中的View不同的地方在于

  • 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象;

  • 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端要求的格式;

  • 任何APIException异常都会被捕获到,并且处理成合适的响应信息;

  • 在进行dispatch()分发前,会对请求进行身份认证、权限检查、流量控制。

他其中定义的属性有:权限控制,流量限制,身份认证

  • authentication_classes 列表或元祖,身份认证类

  • permissoin_classes 列表或元祖,权限检查类

  • throttle_classes 列表或元祖,流量控制类

也就是说,如果我们定义的类视图继承了APIView我们就可以使用这些属性.

GenericAPIView,他继承自APIView类,他在APIView的基础上增加了列表视图(也就是获取全部数据)和详情视图(获取单个数据)的通用支持方法.使用的时候我们需要搭配多个mixin扩展类使用.他的属性有:

列表视图和详情视图通用的:

  • queryset 列表视图的查询集

  • serializer_class 视图使用的序列化器

列表视图使用的:

  • pagination_class 分页控制类 我们获取所有数据,我们就需要使用分页操作,或者过滤操作

  • filter_backends 过滤控制后端

详情视图使用的:

  • lookup_field 查询单一数据库对象时使用的条件字段,默认为'pk' 这个使用的比较多.pk表示主键

  • lookup_url_kwarg 查询单一数据时URL中的参数关键字名称,默认与look_field相同

提供的方法,我们如果继承了他,我们在我们定义的类视图中,就可以直接使用self.方法名调用他.很方便

列表视图与详情视图通用的:

get_queryset()返回列表视图与详情视图的查询集,是两个视图获取数据的基础.

get_serializer()返回序列化器对象,我们在类视图的最开始的地方,会指定一个查询集,一个序列化集,我们使用这个方法,我们就不用再写序列化集,直接使用这个来返回序列化对象了.比如

本来: ser = BookInfoSerializer(book) 现在 ser = get_Serializer(book) 就好了

get_serializer_class 会返回一个序列化器类,这个有什么用,我也不知道

详情视图专用的:

get_object() 这个会返回我们需要的详情类的模型类对象.不过我们需要在方法中传入一个pk值,

2)五个扩展类

五个分别是:ListModelMixin(返回所有数据),CreateModelMixin(创造一个数据),RetrieveModelMixin(获取单个的数据对象),UpdateModelMixin (更新某条数据),DestoryModelMixin(删除数据)

我们如果继承了:这个其中的方法,我们就可以不用写视图方法中的处理逻辑了.

我们就可以这样写!

继承ListModelMixin ,我们就可以这样写:

  def get(self, request):
        return self.list(request)  # 这是因为我们调用了扩展类里面的list方法.我们传入request就好了啊

CreateModelMixin里面是create方法,RetrieveModelMixin里面是retrieve方法,UpdateModelMixin 里面是update方法,DestoryModelMixin里面是destroy方法.

3)子视图

还有七个可以的子类视图.就是他已经继承好了,我们继承一个,其实就已经继承了好几个的意思.

CreateAPIView 继承自: GenericAPIView、CreateModelMixin

ListAPIView 继承自:GenericAPIView、ListModelMixin

RetrieveAPIView 继承自:GenericAPIView、RetrieveModelMixin

DestroyAPIView 继承自:GenericAPIView、DestoryModelMixin

UpdateAPIView 继承自:GenericAPIView、UpdateModelMixin

RetrieveUpdateAPIView 继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin

RetrieveUpdateDestroyAPIView 继承自:GenericAPIView、RetrieveModelMixin、UpdateModelMixin、DestoryModelMixin

真多!

3.视图集

视图集就是Viewset(),就是将一系列逻辑相关的动作放在一个类中,

  • list() 提供一组数据

  • retrieve() 提供单个数据

  • create() 创建数据

  • update() 更新数据

  • destory() 删除数据

我们在视图集中不在实现get 和post方法了,我们就使用上面列的几种方法.

# 比如我们定义了以下两个方法
class BookInfoViewSet(viewsets.ViewSet):
    def list(self, request):
        ...
    def retrieve(self, request, pk=None):
        ...
        
# 我们定义路由的时候,就这样定义
urlpatterns = [
    url(r'^books/$', BookInfoViewSet.as_view({'get':'list'}),
    url(r'^books/(?P<pk>\d+)/$', BookInfoViewSet.as_view({'get': 'retrieve'})
]
# 在as_view后面加上什么类型,以及对应的方法.

上面的五个已经定义好的,我们不需要给他指定请求方法.

但是我们要是定义一个自定义的方法,我们就需要给他指定一个请求方式了.

这时,我们就需要给我们写的方法,添加一个装饰器,action,

action需要接收两个参数:

  • methods: 该action支持的请求方式,使用列表包裹

  • detail: 表示是action中要处理的是否是视图资源的对象(即是否通过url路径获取主键),如果是True,我们就是要给他传入一个主键pk,False就不用传.

比如:

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    # detail为False 表示不需要处理具体的BookInfo对象
    @action(methods=['get'], detail=False)
    def latest(self, request):
        """
        返回最新的图书信息
        """
        book = BookInfo.objects.latest('id')
        serializer = self.get_serializer(book)
        return Response(serializer.data)
    # detail为True,表示要处理具体与pk主键对应的BookInfo对象
    @action(methods=['put'], detail=True)
    def read(self, request, pk):
        """
        修改图书的阅读量数据
        """
        book = self.get_object()
        book.bread = request.data.get('read')
        book.save()
        serializer = self.get_serializer(book)
        return Response(serializer.data)
        
        
# 我们定义路由的时候,我们这样定义
 url(r'^books/latest/$', views.BookInfoViewSet.as_view({'get': 'latest'})),
 url(r'^books/(?P<pk>\d+)/$', views.BookInfoViewSet.as_view({'get': 'retrieve'})),

和之前无差.

视图集父类

这其中也有很多已经封装好的子类用于继承的,如下:

1) ViewSet

继承自APIView,作用也与APIView基本类似,提供了身份认证、权限校验、流量管理等。

在ViewSet中,没有提供任何动作action方法,需要我们自己实现action方法。

2)GenericViewSet

继承自GenericAPIView,作用也与GenericAPIVIew类似,提供了get_object、get_queryset等方法便于列表视图与详情信息视图的开发。

3)ModelViewSet

继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin、CreateModelMixin、UpdateModelMixin、DestoryModelMixin。

4)ReadOnlyModelViewSet

继承自GenericAPIVIew,同时包括了ListModelMixin、RetrieveModelMixin。

五.路由

路由一共分为两种: DefaultRouter ,和 SimpleRouter,

创建路由对象,并注册视图集

router = routers.SimpleRouter()
router.register(r'books', BookInfoViewSet, base_name='book')

注册的语法如下:register(prefix, viewset, base_name)

books 就是prefix , viewset就是BookInfoViewSet, book就是 base_name

prefix是路由前缀,在请求的地址中.如127.0.0.1:8000/books

base_name就是区别视图方法的,一般是这样的格式 : book-list (list方法)

这后面的不重要了,看看就行了 

 

 

Guess you like

Origin www.cnblogs.com/lqh950422/p/12111249.html