返回顶部

DRF之序列化

一. DRF序列化

  我们前后端交互一般都选择JSON数据格式,JSON是一个轻量级的数据交互格式。

  那么我们给前端数据的时候都要转成json格式,那就需要对我们从数据库拿到的数据进行序列化。

  接下来我们看下django序列化和rest_framework序列化的对比。

1.Django的序列化方法

表结构:

from django.db import models

# Create your models here.

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

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=models.CASCADE)
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "01-图书表"
        db_table = verbose_name_plural


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

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "02-出版社表"
        db_table = verbose_name_plural


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

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "03-作者表"
        db_table = verbose_name_plural

urls:

path('list/', BookView.as_view()),

views:

我们自己处理数据:

class BookView(View):

    def get(self, request):
        book_queryset = models.Book.objects.values('id','title','pub_time', 'publisher')
        book_list = list(book_queryset)
        ret = []
        for book in book_list:
            publish_id = book['publisher']
            publish_obj = models.Publisher.objects.filter(pk=publish_id).first()
            book['publisher'] = {'id':publish_id, 'title': publish_obj.title}
            ret.append(book)
        ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
        return HttpResponse(ret)
        # return JsonResponse(ret, safe=False, json_dumps_params={'ensure_ascii':False})  通过JasonResponse就不需要在处理日期显示问题了。

# json.JSONEncoder.default()
解决json不能序列化时间字段的问题
class MyJson(json.JSONEncoder):
    def default(self, field):
        if isinstance(field, datetime.datetime):
            return field.strftime('%Y-%m-%d %H:%M:%S')
        elif isinstance(field, datetime.date):
            return field.strftime('%Y-%m-%d')
        else:
            return json.JSONEncoder.default(self, field)

用Django给我们提供的序列化方法,可以得到数据,就是数据格式有点复杂:

from django.core import serializers


# 能够得到我们要的效果 结构有点复杂
class BookView(View):

def get(self, request):
book_queryset = models.Book.objects.all()
ret = serializers.serialize('json', book_queryset, ensure_ascii=False)

return HttpResponse(ret)

"""
结果:
[{"model": "xuliehua.book", "pk": 1, "fields": {"title": "python基础", "category": 1, "pub_time": "2020-10-14",
"publisher": 1, "author": [1, 2]}}, {"model": "xuliehua.book", "pk": 2, "fields": {"title": "数据库基础", "category": 3,
"pub_time": "2020-10-01", "publisher": 2, "author": [1]}}]
"""

 

2. DRF的序列化方法

urls:

from django.urls import path
from xuliehua.views import BookView, BookEditView


urlpatterns = [

    path('list/', BookView.as_view()),
    path('retrieve/<int:pk>/', BookEditView.as_view())
]

views:

from rest_framework.views import APIView
from rest_framework.response import Response
from xuliehua import models
from xuliehua.serializers import BookSerializer,BookModelSerializer


class
BookView(APIView): def get(self, request): book_queryset = models.Book.objects.all() ret = BookModelSerializer(book_queryset, many=True) return Response(ret.data) def post(self, request): ret = BookModelSerializer(data=request.data, many=False) if ret.is_valid(): ret.save() return Response(ret.data) else: return Response(ret.errors) """
通过postman提交的数据格式
{ "title": "数据库基础1", "w_category": "1", "pub_time": "2020-10-01", "publisher_id": "1", "author_list": [ "1", "2" ] }
""" class BookEditView(APIView): def get(self, request, pk): book_obj = models.Book.objects.filter(pk=pk).first() ret = BookModelSerializer(book_obj, many=False) return Response(ret.data) def put(self, request, pk): book_obj = models.Book.objects.filter(pk=pk).first() ret = BookModelSerializer(book_obj, data=request.data, partial=True) if ret.is_valid(): ret.save() return Response(ret.data) else: return Response(ret.errors)

自己写的序列化器,继承于 serializers.ModelSerializer 或者  serializers.Serializer,这两个就有点像form和modelform

先看serializers.Serializer

# 自定义校验器
def
my_validator(value): if '敏感' in value.lower(): raise serializers.ValidationError('不能含有敏感信息') return value 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, validators=[my_validator,]) CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux")) category = serializers.CharField(source='get_category_display', read_only=True) w_category = serializers.ChoiceField(choices=CHOICES, write_only=True) pub_time = serializers.DateField() publisher = PublishSerializer(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): print(validated_data) book = models.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("w_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) if validated_data.get("author_list"): instance.author.set(validated_data["author_list"]) instance.save() return instance # 局部狗子 def validate_title(self, value): if 'python' not in value.lower(): raise serializers.ValidationError('标题必须含有python') return value # 全局钩子 def validate(self, attrs): if attrs.get('w_category') == 1 and attrs.get('publisher_id') == 2: return attrs else: raise serializers.ValidationError('分类以及标题不符合要求')

serializers.ModelSerializer

class BookModelSerializer(serializers.ModelSerializer):

    category_display = serializers.CharField(source='get_category_display',read_only=True)
    publisher_info = serializers.SerializerMethodField(read_only=True)
    authors = serializers.SerializerMethodField(read_only=True)

    def get_publisher_info(self, obj):
        publish_obj = obj.publisher
        return {'id':publish_obj.pk, 'title': publish_obj.title}

    def get_authors(self, obj):
        author_queryset = obj.author.all()
        return [{'id': author.pk, 'name': author.name}  for author in author_queryset]

    def validate_title(self, value):
        if 'python' not in value.lower():
            raise serializers.ValidationError('标题必须含有python')
        return value

    class Meta:
        model = models.Book
        fields = '__all__'
        extra_kwargs = {'category':{'write_only':True}, 'publisher': {'write_only': True}, 'author': {'write_only':True}}

views中,就可以通过这两个序列化器,选择一个进行数据的序列化。

通过postman的GET方法访问 http://127.0.0.1:8000/books/retrieve/1/:

{
    "id": 1,
    "category_display": "Go",
    "publisher_info": {
        "id": 1,
        "title": "北京出版社"
    },
    "authors": [
        {
            "id": 1,
            "name": "alex"
        }
    ],
    "title": "python全栈开发",
    "pub_time": "2020-10-14"
}

通过postman的PUT方法访问 http://127.0.0.1:8000/books/retrieve/1/:

提交的json数据:

{
    "title":"python全栈开发",
    "category": 2,
    "publisher":1,
    "author": [1,2]
}

返回的数据:

{
    "id": 1,
    "category_display": "Go",
    "publisher_info": {
        "id": 1,
        "title": "北京出版社"
    },
    "authors": [
        {
            "id": 2,
            "name": "wupeiqi"
        }
    ],
    "title": "python全栈开发",
    "pub_time": "2020-10-14"
}

 

posted @ 2020-10-14 16:27  muguangrui  阅读(199)  评论(0编辑  收藏  举报