要一直走下去

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

有Django-JsonResponse序列化,为什么还要用DRF框架?

第一版:用.values JsonResponse来实现序列化
Json.dumps(book_list, ensure_ascii=False)方法不能序列化Date类型
JsonResponse(book_list, safe=False, json_dumps_params={'ensure_ascii':False})可以序列化Date类型
如果有forienkey传的就是ID,就需要自己拼,这样代码会重复
如果用DjangoSerializer呢?

第二版:用django serializers实现序列化
from django.core import serializers
ret = serializers.serialize("json", book_list_queryset, ensure_ascii=False)
return HttpResponse(ret)
这样的数据外键依然是ID,依然需要自己拼,跟上面的差不多

第三版:用框架实现序列化
pip install djangorestframework

 

------------图书的增删改查-----------

图书列表: get请求  http://127.0.0.1:8000/serdemo/book/list 

新增图书: post请求  http://127.0.0.1:8000/serdemo/book/list 

图书详情:get请求  http://127.0.0.1:8000/serdemo/retrieve/<id>

修改图书:put请求  http://127.0.0.1:8000/serdemo/retrieve/<id>

 

 

 

 models.py

from django.db import models


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="图书的名称")
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = models.IntegerField(choices=CHOICES, verbose_name="图书的类别")
    pub_time = models.DateField(verbose_name="图书的出版日期")
    publisher = models.ForeignKey(to="Publisher", on_delete=None)
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title


class Publisher(models.Model):
    title = models.CharField(max_length=32, verbose_name="出版社的名称")

    def __str__(self):
        return self.title


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者的姓名")

    def __str__(self):
        return self.name

views.py

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


class BookView(APIView):
    def get(self, request):
        books_list = Book.objects.all()
        ret = BookSerializer(books_list, many=True)  # 如果是单个对象就不加"many=True"
        return Response(ret.data)

    def post(self, request):
        serializer = BookSerializer(data=request.data)  # 放在data里,表示是反序列化的数据
        if serializer.is_valid():
            serializer.save()
            print(
                serializer.data)  # {'id': 22, 'category_display': 'Go', 'publisher_info': {'id': 1, 'title': '春风出版社'}, 'authors_list': [{'id': 3, 'name': '张三'}, {'id': 4, 'name': '李四'}], 'title': 'GO语言编程思想', 'pub_time': '2018-12-25'}
            print(
                serializer.validated_data)  # OrderedDict([('title', 'GO语言编程思想'), ('category', 2), ('pub_time', datetime.date(2018, 12, 25)), ('publisher', <Publisher: 春风出版社>), ('author', [<Author: 张三>, <Author: 李四>])])
            return Response(serializer.data)  # 如果用serializer.validated_data会报错:"Publish不是JSON可序列化对象"
        else:
            return Response(serializer.errors)


class BookEditView(APIView):
    def get(self, request, id):
        try:
            book_obj = Book.objects.get(id=id)
        except Exception as e:
            return Response({"error": e.__str__()})
        ret = BookSerializer(book_obj)
        return Response(ret.data)

    def put(self, request, id):
        book_obj = Book.objects.get(id=id)
        # 第一个参数是要更新的对象,第二个参数是要更新的数据,第三个参数表示允许部分更新
        serializer = BookSerializer(book_obj, data=request.data, partial=True)
        if serializer.is_valid():
            serializer.save()  # 要重写serializer中的update方法
            return Response(serializer.validated_data)
        else:
            return Response(serializer.errors)

    def delete(self, request, id):
        book_obj = Book.objects.get(id=id)
        book_obj.delete()
        return Response("")

    '''
    {
    "title": "GO语言编程思想",
    "w_category": 2,
    "pub_time": "2018-12-25",
    "publisher_id": 1,
    "author_list": [3,4]
    }
    '''

 

urls.py

from django.urls import path
from . import views

app_name = 'serdemo'
urlpatterns = [
    path("book/list", views.BookView.as_view()),
    path("retrieve/<int:id>", views.BookEditView.as_view())
]

serializers.py

from rest_framework import serializers
from .models import Book


class PublisherSerializer(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_validator(value):
    '''
    校验器,校验Book的title字段
    :param value:
    :return:
    '''
    if "fuck" in value.lower():
        raise serializers.ValidationError("标题中不能有脏话")
    return value


class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)  # required=False,表示这个字段不校验
    title = serializers.CharField(max_length=32, validators=[my_validator, ])  # 验证器的优先级比该字段的验证函数高
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    # category序列化和反序列化不一样,read_only=True表示只序列化的时候用,后端传到前端是汉子
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    # write_only只是反序列化用,前端传到后端的是数字
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data['title'],
                                   category=validated_data['w_category'],
                                   pub_time=validated_data['pub_time'],
                                   publisher_id=validated_data['publisher_id'])
        book.author.add(*validated_data['author_list'])
        return book

    def update(self, instance, validated_data):
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("category", instance.category)
        instance.pub_time = validated_data.get("pub_time", instance.pub_time)
        instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
        author_list = validated_data.get("author_list")
        if author_list:
            instance.author.set(*author_list)
        instance.save()
        return instance

    def validate_title(self, value):
        '''
        钩子函数validate_字段,单独校验title
        :param value:
        :return:
        '''
        if "python" not in value.lower():
            raise serializers.ValidationError("标题中必须含有‘python’")
        return value

    def validate(self, attrs):
        w_category = attrs.get('w_category')
        publisher_id = attrs.get('publisher_id')
        if w_category == 1 and publisher_id == 1:
            return attrs
        else:
            raise serializers.ValidationError("分类及标题不符合要求")


"""
反序列化的数据结构:
{
    "title": "GO语言编程思想",
    "w_category": 2,
    "pub_time": "2018-12-25",
    "publisher_id": 1,
    "author_list": [3,4]
}
"""

model_serializers.py

from rest_framework import serializers
from .models import Book


class BookSerializer(serializers.ModelSerializer):
    '''
    使用ModelSerializer反序列化,只配置class Meta就能实现。
    所以,只需要重写原字段的序列化功能就可以了,重写的时候序列化字段跟原字段不一样,
    例如category改成category_display,如果跟原字段一样就都重写了,这里只重写原字段的序列化
    同时,需要配置xx将原字段配置为只反序列化
    所以,序列化用category_display,反序列化用category
    '''
    category_display = serializers.SerializerMethodField(read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors_list = serializers.SerializerMethodField(read_only=True)

    def get_category_display(self, obj):
        return obj.get_category_display()

    def get_publisher_info(self, obj):
        # obj是序列化的每个Book对象,publiser是外键
        publisher_obj = obj.publisher
        return {"id": publisher_obj.id, "title": publisher_obj.title}

    def get_authors_list(self, obj):
        # author是多对多
        authors_queryset = obj.author.all()
        return [{"id": author_obj.id, "name": author_obj.name} for author_obj in authors_queryset]

    class Meta:
        model = Book
        # fields = ["id", "title", "pub_time"]
        fields = "__all__"  # 排序就列表分开写,不排序就写__all__
        # depth = 1  # 根据外键关系向下找一层,这样把外键所有字段都查出来,method_field
        extra_kwargs = {"category": {"write_only": True},
                        "publisher": {"write_only": True},
                        "author": {"write_only": True}
                        }

 

posted on 2020-03-23 23:33  要一直走下去  阅读(181)  评论(0编辑  收藏  举报