restful规范及DRF基础

RESTful规范


REST风格

  • 资源 网页中能看到的都是资源

  • URI 统一资源标识符

    URL 统一资源定位符

  • 统一资源接口

    对资源的操作根据HTTP请求方式的不同来进行不同的操作

    遵循HTTP请求方式的语义

  • 前后端传输的是资源的表述

  • 展现的是资源的状态

凡是遵循REST风格实现的前后端交互都叫RESTful架构


核心思想

  • 面向资源去编程, url中尽量用名词不要用动词
  • 根据HTTP请求方式的不同对资源进行不同的操作

在url中体现的


在返回值中

  • 携带状态码

  • 返回值

    • get 返回查看的所有或者单条数据
    • post 返回新增的这条数据
    • put/patch 返回更新的这条数据
    • delete 返回值空
  • 携带错误信息

  • 携带超链接

    前后端不分离的项目用的比较多


FBV和CBV区别


  • FBV 基于函数的视图
  • CBV 基于类的视图
urlpatterns = [
    path('admin/', admin.site.urls),
    path('test_fbv', test_fbv),
    path('test_cbv', TestCBV.as_view())
]
def test_fbv(request):
    return HttpResponse("ok")


class TestCBV(View):
    def get(self, request):
        return HttpResponse("ok")

CBV首先执行了as_view()方法, 然后在内部做了一个分发本质和FBV是一样的~

以后做接口开发的时候,就要用CBV, 因为需要用到类的调用以及一些特性


APIView和View的区别

  • APIView继承了View

    • APIView 重写了as_view以及 dispatch方法

    • 在dispatch里重新封装了request

      • request = Request()

        旧的request变成了_request
        get请求数据 ------> request.query_params
        post请求的数据------>request.data

我们django中写CBV的时候继承的是View,rest_framework继承的是APIView


APIView

我们django中写CBV的时候继承的是View,rest_framework继承的是APIView

不管是View还是APIView最开始调用的都是as_view()方法

APIView继承了View, 并且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证


as_view()方法做了什么???

在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法~~但是这里的dispatch方法应该是我们APIView中的


request这个变量是经过django封装的uwsgi协议的模块处理过的, 这里通过initialize_request方法再次处理这个变量, 然后赋值给了另一个同名的变量(不同的名称空间)request,并且赋值给了self.request, 也就是我们在视图中用的request.xxx到底是什么~~


这个方法返回的是Request这个类的实例对象~~我们注意我们看下这个Request类中的第一个参数request,是我们走我们django的时候的原来的request~


这个Request类把原来的request赋值给了self._request, 也就是说以后_request是我们老的request,新的request是我们这个Request类~~

所以, 现在的问题是,继承APIView之后请求来的数据都在哪????


当我们用了rest_framework框架以后,我们的request是重新封装的Request类~

request.query_params 存放的是我们get请求的参数

request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求~~~

相比原来的django的request,我们现在的request更加精简,清晰了~~~


序列化


查看数据

使得后端的数据能够被前端的浏览器识别

本质上就是将python数据转换成json数据类型


Json格式数据和python格式数据的对应关系

from /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/json/encoder.py

+-------------------+---------------+
| Python            | JSON          |
+===================+===============+
| dict              | object        |
+-------------------+---------------+
| list, tuple       | array         |
+-------------------+---------------+
| str               | string        |
+-------------------+---------------+
| int, float        | number        |
+-------------------+---------------+
| True              | true          |
+-------------------+---------------+
| False             | false         |
+-------------------+---------------+
| None              | null          |
+-------------------+---------------+

/DRFDemo/djangoDemo/models.py

from django.db import models


# Create your models here.

__all__= ["Book", "Publisher", "Author"]

class Book(models.Model):
    title = models.CharField(max_length=32)
    CHOICES = ((1, 'Python'), (2, 'Linux'), (3, 'go'))
    category = models.IntegerField(choices=CHOICES)
    pub_time = models.DateField()
    publisher = models.ForeignKey(to="Publisher")
    authors = models.ManyToManyField(to="Author")

class Publisher(models.Model):
    title = models.CharField(max_length=32)


class Author(models.Model):
    name = models.CharField(max_length=32)

插入点数据




/DRFDemo/DRFDemo/urls.py

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^demo/', include("djangoDemo.urls")),
]

/DRFDemo/djangoDemo/urls.py

from django.conf.urls import url
from .views import BookView

urlpatterns=[
    url(r'^book', BookView.as_view())
]

第一版 用values方法取数据

/DRFDemo/djangoDemo/views.py

from django.http import JsonResponse
from django.shortcuts import render, HttpResponse
from django.views import View
from .models import Book,Publisher
import json


class BookView(View):
    def get(self, request):
        book_queryset = Book.objects.values("id", "title", "pub_time",'publisher')
        book_list = list(book_queryset)
        '''python自带json模块不支持时间格式, 需要对时间格式支持需要用django的JsonResponse模块'''
        # ret = json.dumps(book_list, ensure_ascii=False)
        # return HttpResponse(ret)
        ret=[]
        for book in book_list:
            print(book)
            book['publisher'] = {
                'id': book['id'],
                'title': Publisher.objects.filter(id=book['publisher']).first().title
            }
            ret.append(book)
        return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})


输出结果

[
    {
        "id": 1,
        "title": "水货开房没带身份证",
        "pub_time": "2019-10-08",
        "publisher": {
            "id": 1,
            "title": "沙河出版社"
        }
    }
]

第二版 使用django序列化组件获取数据

/DRFDemo/djangoDemo/views.py

from django.shortcuts import render, HttpResponse
from django.views import View
from .models import Book,Publisher
from django.core import serializers

class BookView(View):
    def get(self,request):
        book_queryset = Book.objects.all()
        data = serializers.serialize("json",book_queryset, ensure_ascii=False)
        return HttpResponse(data)

输出结果

[
    {
        "model": "djangoDemo.book",
        "pk": 1,
        "fields": {
            "title": "水货开房没带身份证",
            "category": 3,
            "pub_time": "2019-10-08",
            "publisher": 1,
            "authors": [
                1,
                2
            ]
        }
    }
]

第三版 使用djangorestframework

前面2版的缺点: 不能处理外键关系

新建一个app

python3 manager.py startapp SerDemo

安装djangorestframework

pip3 install djangorestframework

注册rest_framework这个app, 如果不注册, 通过drf序列化的数据无法在页面上渲染


第一步: 新建序列化器

序列化器中的定义的字段对象必须和ORM字段的名字是一致的

/DRFDemo/SerDemo/serializers.py

from rest_framework import serializers


class PublishSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)

class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    pub_time = serializers.DateField()
    category = serializers.CharField(source="get_category_display")

    # 外键关系
    publisher = PublishSerializer()
    authors = AuthorSerializer(many=True)

第二步: 使用自定义的序列化器序列化queryset

  1. 把模型对象(ORM对象)放入序列化器进行字段匹配, 匹配上的字段进行序列化 匹配不上丢弃

  2. 序列化好的数据在ser_obj.data中

  3. 外键关系的序列化是嵌套的序列化器对象 注意: many=True

    只要指定了many=True, 则肯定是可迭代对象


/DRFDemo/DRFDemo/urls.py

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^demo/', include("djangoDemo.urls")),
    url(r'^api/', include("SerDemo.urls")),
]

/DRFDemo/SerDemo/urls.py

from django.conf.urls import url,include
from .views import BookView
urlpatterns = [
    url(r'^book/', BookView.as_view()),
]

/DRFDemo/SerDemo/views.py

from django.shortcuts import render
from rest_framework.views import APIView
from djangoDemo.models import Book
from .serializers import BookSerializer
from rest_framework.response import Response
# Create your views here.

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
				'''
				用序列化器进行序列化
				加了many=True这个参数, 则会先循环book_queryset这个对象,把循环出来的每一个对象放到序列化器中序列				化, 这些对象是ORM对象, 把这些对象和序列化器中的对象进行匹配, 匹配上的则序列化, 匹配不上的则丢弃
				'''
        ser_obj = BookSerializer(book_queryset, many=True)
        '''
          BookSerializers(<QuerySet [<Book: 水货开房没带身份证>]>, many=True):
          id = IntegerField()
          title = CharField(max_length=32)
          category = CharField(source='get_category_display')
          pub_time = DateField()
          publisher = PublisherSerializers():
          id = IntegerField()
          name = CharField(max_length=32)
          authors = AuthorSerializers(many=True):
          id = IntegerField()
          name = CharField(max_length=32)
        '''
        return Response(ser_obj.data)

第三步: 注册rest_framwork app

使得页面中渲染rest_framwork的页面

/DRFDemo/DRFDemo/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'djangoDemo.apps.DjangodemoConfig',
    "SerDemo.apps.SerdemoConfig",
    "rest_framework.apps.RestFrameworkConfig",
]

输出结果


相关报错

报错1

Got AttributeError when attempting to get a value for field `id` on serializer `BookSerializers`.
The serializer field might be named incorrectly and not match any attribute or key on the `QuerySet` instance.
Original exception text was: 'QuerySet' object has no attribute 'id'.

原因: 序列化queryset对象时候, 没有加many=True

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = serializers.BookSerializers(book_queryset)
        return Response(ser_obj.data)

解决: 加上 many=True

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = serializers.BookSerializers(book_queryset,many=True)
        return Response(ser_obj.data)

报错2

Object of type 'ListSerializer' is not JSON serializable

原因: 最后返回到页面的是一个序列化的对象, 并不是一个具体的数据

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = serializers.BookSerializers(book_queryset,many=True)
        return Response(ser_obj)

解决: 返回序列化的数据

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = serializers.BookSerializers(book_queryset,many=True)
        return Response(ser_obj.data)

反序列化


新增数据

通过post方法写入数据库, 前端通过json格式传到后端, 后端反序列化成python数据类型进行处理写入数据库


思路

-- 确定新增的数据结构
		-- 序列化器
			-- 正序和反序列化字段不统一
			-- required=False 只序列化不走校验
			-- read_only=True  只序列化用
			-- write_only=True  只反序列化用
			-- 重写create方法
		-- 验证通过返回ser_obj.validated_data
		-- 验证不通过返回ser_obj.errors

/DRFDemo/DRFDemo/urls.py

from django.conf.urls import url,include
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^demo/', include("djangoDemo.urls")),
    url(r'^api/', include("SerDemo.urls")),
]

/DRFDemo/SerDemo/urls.py

from django.conf.urls import url
from .views import BookView, BookEditView
urlpatterns = [
    url(r'^book/', BookView.as_view()),
]

第一步: 确认字段


确认需要校验的序列化的字段和反序列的字段, 并重写create方法

/DRFDemo/SerDemo/serializers.py

from rest_framework import serializers
from djangoDemo.models import Book
import copy


class PublishSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)

class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32)
    pub_time = serializers.DateField()

    # read_only=True  反序列化不校验该字段, 序列化时校验该字段
    category = serializers.CharField(source="get_category_display", read_only=True)

    # 外键关系
    publisher = PublishSerializer(read_only=True)
    # 内部通过外键关系的id找到了publish_obj
    # PublishSerializer(publish_obj)
    
    authors = AuthorSerializer(many=True, read_only=True)
    # 这里加上 many=True, 因为多对多的缘故, 内部通过外键关系的id找到的authors_obj是可迭代对象的数据类型, 因为有多个数据, 所以需要通过可迭代的数据类型包裹 
    

    # write_only=True  序列化时候不校验该字段, 反序列化校验该字段
    post_category = serializers.IntegerField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        # validated_data  校验通过的数据  就是book_obj
        # 通过ORM操作给Book表增加数据
        print(validated_data)
        '''
        前端传过来的数据: 
        {   "title": "水货国庆节很寂寞",
            "pub_time": "2019-10-08",
            "post_category": 1,
            "publisher_id": 1,
            "author_list": [1,2]   
    		}
        '''
        cleaned_data = copy.deepcopy(validated_data)
        cleaned_data.pop('author_list')
        cleaned_data['category']=cleaned_data['post_category']
        cleaned_data.pop('post_category')
        book_obj = Book.objects.create(**cleaned_data)
        book_obj.authors.add(*validated_data['author_list'])
        return book_obj

第二步: 对前端的数据反序列化


这里的反序列化完成了校验和转换2个步骤

  • 校验前端传过来的字段的名字是否和序列化器中定义的需要反序列化的字段的名字是否一样
  • 如果校验通过了, 则将json数据类型转换为python数据类型, 保存在序列化器的对象的属性validated_data
from django.shortcuts import render
from rest_framework.views import APIView
from djangoDemo.models import Book
from .serializers import BookSerializer
from rest_framework.response import Response
# Create your views here.

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        # 用序列化器进行序列化
        ser_obj = BookSerializer(book_queryset, many=True)
        return Response(ser_obj.data)

    def post(self, request):
        # 确定数据类型以及数据以及数据结构
        # 对前端的数据进行校验
        book_obj = request.data
        ser_obj = BookSerializer(data=book_obj)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)

第三步: 新增数据


{
    "title": "水货国庆节很寂寞",
    "pub_time": "2019-10-08",
    "post_category": 1,
    "publisher_id": 1,
    "author_list": [1, 2]
}


注意!!!  序列化和反序列化的时候, 其实就是实例化继承了serializers.Serializer的序列化类进行相应的操作


Serializer的构造方法为:
Serializer(instance=None, data=empty, **kwargs)

  • 用于序列化时,校验后端数据, 将python的数据类型转换为前端可以识别的json数据类型, 将模型类对象传入instance参数
  • 用于反序列化时,校验前端数据, 并将json数据类型转换为python的数据类型, 将要被反序列化的数据传入data参数

相关报错


报错1

AssertionError at /api/book/
Cannot call `.is_valid()` as no `data=` keyword argument was passed when instantiating the serializer instance.

问题: 反序列化的时候, 将反序列化的数据传入了instance参数, 默认不用关键字传参是将数据传入instance参数

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = BookSerializers(book_queryset, many=True)
        return Response(ser_obj.data)

    def post(self, request):
        book_queryset = request.data
        ser_obj = BookSerializers(book_queryset)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)

解决: 将反序列化的数据传入用关键字传参传给data参数

class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = BookSerializers(book_queryset, many=True)
        return Response(ser_obj.data)

    def post(self, request):
        book_queryset = request.data
        ser_obj = BookSerializers(data=book_queryset)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)

更新数据


第一步: 新建子路由关系


/DRFDemo/DRFDemo/urls.py

from django.conf.urls import url
from .views import BookView, BookEditView
urlpatterns = [
    url(r'^book/', BookView.as_view()),
    url(r'^books/(?P<id>\d+)', BookEditView.as_view()),
]

第二步: 新建视图类


/DRFDemo/SerDemo/views.py

from rest_framework.views import APIView
from djangoDemo.models import Book
from .serializers import BookSerializer
from rest_framework.response import Response

class BookEditView(APIView):
    def get(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        ser_obj = BookSerializer(book_obj)
        return Response(ser_obj.data)

    def put(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        # partial=True  对序列化器中的update方法中, 只对部分字段进行校验
        ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)

第三步: 序列化器中重写update方法


/DRFDemo/SerDemo/serializers.py

from rest_framework import serializers
from djangoDemo.models import Book
import copy

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32)
    pub_time = serializers.DateField()

    # read_only=True  反序列化不校验该字段, 序列化时校验该字段
    category = serializers.CharField(source="get_category_display", read_only=True)

    # 外键关系
    publisher = PublishSerializer(read_only=True)
    # 内部通过外键关系的id找到了publish_obj
    # PublishSerializer(publish_obj)
    authors = AuthorSerializer(many=True, read_only=True)

    # write_only=True  序列化时候不校验该字段, 反序列化校验该字段
    post_category = serializers.IntegerField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        # validated_data  校验通过的数据  就是book_obj
        # 通过ORM操作给Book表增加数据
        print(validated_data)
        '''
        前端传过来的数据: 
        {'title': '水货开房没带身份证',
         'pub_time': datetime.date(2019, 10, 8), 
         'post_category': 1, 
         'publisher_id': 1, 
         'author_list': [1, 2]}
        '''
        cleaned_data = copy.deepcopy(validated_data)
        cleaned_data.pop('author_list')
        cleaned_data['category'] = cleaned_data['post_category']
        cleaned_data.pop('post_category')
        book_obj = Book.objects.create(**cleaned_data)
        book_obj.authors.add(*validated_data['author_list'])
        return book_obj

    def update(self, instance, validated_data):
        # instance 更新的book_obj 对象
        # validated_data  前端传过来的并且校验通过的数据
        # validated data中的键值肯定是 title|pub_time|post_category|publisher_id|author_list|
        # ORM 做更新操作
        instance.title = validated_data.get('title', instance.title)
        instance.pub_time = validated_data.get('pub_time', instance.pub_time)
        instance.category = validated_data.get('post_category', instance.category)
        instance.publisher_id = validated_data.get('publisher_id', instance.publisher_id)
        if validated_data.get('author_list'):
            instance.author.set(validated_data['author_list'])
        instance.save()

        return instance

第四步: 更新数据


{ "title": "尚泽凯咋小巴拉子",
"post_category": 3
}


进一步校验数据


/DRFDemo/SerDemo/serializers.py

from rest_framework import serializers
from djangoDemo.models import Book
import copy


class PublishSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)


class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)

'''自定义校验'''
def my_validate(value):
    print('11111111')
    if '敏感信息' in value.lower():
        raise serializers.ValidationError('有敏感词汇')

    return value

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate, ])
    pub_time = serializers.DateField()

    # read_only=True  反序列化不校验该字段, 序列化时校验该字段
    category = serializers.CharField(source="get_category_display", read_only=True)

    # 外键关系
    publisher = PublishSerializer(read_only=True)
    # 内部通过外键关系的id找到了publish_obj
    # PublishSerializer(publish_obj)
    authors = AuthorSerializer(many=True, read_only=True)

    # write_only=True  序列化时候不校验该字段, 反序列化校验该字段
    post_category = serializers.IntegerField(write_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        # validated_data  校验通过的数据  就是book_obj
        # 通过ORM操作给Book表增加数据
        print(validated_data)
        '''
        前端传过来的数据: 
        {'title': '水货开房没带身份证',
         'pub_time': datetime.date(2019, 10, 8), 
         'post_category': 1, 
         'publisher_id': 1, 
         'author_list': [1, 2]}
        '''
        cleaned_data = copy.deepcopy(validated_data)
        cleaned_data.pop('author_list')
        cleaned_data['category'] = cleaned_data['post_category']
        cleaned_data.pop('post_category')
        book_obj = Book.objects.create(**cleaned_data)
        book_obj.authors.add(*validated_data['author_list'])
        return book_obj

    def update(self, instance, validated_data):
        # instance 更新的book_obj 对象
        # validated_data  前端传过来的并且校验通过的数据
        # validated data中的键值肯定是 title|pub_time|post_category|publisher_id|author_list|
        # ORM 做更新操作
        instance.title = validated_data.get('title', instance.title)
        instance.pub_time = validated_data.get('pub_time', instance.pub_time)
        instance.category = validated_data.get('post_category', instance.category)
        instance.publisher_id = validated_data.get('publisher_id', instance.publisher_id)
        if validated_data.get('author_list'):
            instance.author.set(validated_data['author_list'])
        instance.save()

        return instance

    '''单个字段校验'''
    def validate_title(self, value):
        print(22222222)
        # value就是title的值
        if 'python' not in value.lower():
            raise serializers.ValidationError("标题必须含有python")
        return value


    '''多个字段校验'''
    def validate(self, attrs):
        print(333333333333)
        # attrs  字典有你传过来的所有字段
        print(attrs)
        if "python" in attrs['title'].lower() and attrs['post_category'] == 1:
            return attrs
        else:
            raise serializers.ValidationError('分类或标题不符合要求')

权重比较: 自定义校验的函数 (my_validate) > 单个字段校验的方法(validate_title) > 多个字段校验的方法(validate)


ModelSerializers 序列化


/DRFDemo/djangoDemo/models.py

from django.db import models

# Create your models here.

field = ['Book', 'Publisher', 'Author']

class Book(models.Model):
    title = models.CharField(max_length=32)
    CHOICES = ((1, 'go'), (2, 'linux'), (3, 'python'))
    category = models.IntegerField(choices=CHOICES)
    publisher = models.ForeignKey(to='Publisher')
    author = models.ManyToManyField(to='Author')

    def __str__(self):
        return self.title


class Publisher(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

class Author(models.Model):
    name = models.CharField(max_length=32)

    def __str__(self):
        return self.name

/DRFDemo/DRFDemo/admin.py

from django.contrib import admin

# Register your models here.

from . import models


for table in models.field:
    admin.site.register(getattr(models, table))

/drfdemo2/drfdemo2/settings.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'djangomodel.apps.DjangomodelConfig',
    'drfapp.apps.DrfappConfig',
    'rest_framework.apps.RestFrameworkConfig',
]

/DRFDemo/SerDemo/serializers.py`

from rest_framework import serializers
from djangomodel.models import Book

def my_validate(value):
    if '敏感信息' in value.lower():
        raise serializers.ValidationError('有敏感词汇')

class BookSerializers(serializers.ModelSerializer):
    bookname = serializers.SerializerMethodField()

    def get_bookname(self, object):
        return object.title


    # 一旦定义的字段名使用 SerializerMethodField这个方法, 则就可以接收下面定义的方法(get_字段名)的返回值, 默认是read_only=True
    category_info = serializers.SerializerMethodField()

    def get_category_info(self, object):
        # obj 就是序列化的每个book 对象
        # print('obj', obj)
        return object.get_category_display()  # get_字段名_display() 这个函数返回的是字段里元组中的第二个元素

    author_info = serializers.SerializerMethodField()

    def get_author_info(self, object):
        author_obj = object.author.all()
        return [{'id': author.id, 'name': author.name} for author in author_obj]

    publish_info = serializers.SerializerMethodField()

    def get_publish_info(self, object):
        # object 就相当于是一本书
        publisher_obj = object.publisher
        return {'id': publisher_obj.id, 'name': publisher_obj.name}

    class Meta:
        model = Book
        # fileds指定字段, __all__显示所有字段, exclude排除字段,  fields和exclude 不能共存, 只能指定一个
        fields = '__all__'
        # exclude = ['id']
        # depth = 1 会将所有的外键字段加上选项 read_only = True, 并且会拿到所有字段, 一般在开发中不用
        # depth = 1
        extra_kwargs = {'category': {'write_only': True},
                        'author': {'write_only': True},
                        'publisher': {'write_only': True},
                        'title': {'write_only': True, 'validators': [my_validate, ]},

        }

        category_id = serializers.IntegerField(write_only=True)
        publisher_id = serializers.ListField(write_only=True)


/DRFDemo/SerDemo/urls.py

from django.conf.urls import url
from . import views


urlpatterns = [
    url(r'^books/$', views.BookView.as_view()),
    url(r'^book/(?P<id>\d+)/$', views.BookEdit.as_view())
]

/DRFDemo/SerDemo/views.py

from django.shortcuts import render

# Create your views here.
from rest_framework.views import APIView
from rest_framework.response import Response
from djangomodel.models import Book
from .serializers import BookSerializers


class BookView(APIView):
    def get(self, request):
        book_queryset = Book.objects.all()
        ser_obj = BookSerializers(book_queryset, many=True)
        return Response(ser_obj.data)

    def post(self, request):
        book_queryset = request.data
        '''
        前端数据>>>> 
         {
        "title": "陈骏删库跑路了",
        "category": 1,
        "author": [1, 2],
        "publisher": 1
        }
        '''

        ser_obj = BookSerializers(data=book_queryset)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)



class BookEdit(APIView):
    def get(self, request, id):
        book_queryset = Book.objects.filter(id=id).first()
        ser_obj = BookSerializers(book_queryset)
        return Response(ser_obj.data)


    def patch(self, request, id):
        book_queryset = Book.objects.filter(id=id).first()
        '''
         {
        "title": "陈骏删库跑路了",
        "category": 1,
        "author": [1, 2],
        "publisher": 1
        }
        '''

        # partial=True  对序列化器中的update方法中, 只对部分字段进行校验
        ser_obj = BookSerializers(instance=book_queryset, data=request.data, partial=True)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.validated_data)
        return Response(ser_obj.errors)
posted @ 2019-10-08 21:07  cjw1219  阅读(353)  评论(0编辑  收藏  举报