Django REST Framework详细介绍一下不使用DRF的序列化方式

时间:Nov. 8, 2019 分类:

目录:

前期准备

安装和配置

添加app和安装djangorestframework

$ django-admin startproject drf
$ python manage.py startapp drfdemo
$ pip install djangorestframework

setting配置

INSTALLED_APPS = [
    ...
    'drfdemo',
    'rest_framework',
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'djangodemo',
        'USER': 'root',
        'PASSWORD': '123456',
        'HOST': '172.16.32.32',
        'PORT': 3306,
    }
}

init.py

import pymysql
pymysql.install_as_MySQLdb()

models字段

models.py

from django.db import models

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


class Book(models.Model):
    title = models.CharField(max_length=32)
    CHOICES = ((1, "Python"), (2, "Linux"), (3, "Golang"))
    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)

admin.py

from django.contrib import admin
from . import models

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

同步数据库设计

python manage.py makemigrations
python manage.py migrate

在不使用djangorestframework的情况下

直接使用视图

创建超级用户createsuperuser然后直接添加数据

views.py

from django.http import HttpResponse
from django.views import View
from .models import Book

import json

class BookView(View):
    def get(self, request):
        book_queryset = Book.objects.values("id", "title")
        book_list = list(book_queryset)
        ret = json.dumps(book_list)
        return HttpResponse(ret)

url配置

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^api/', include('drfdemo.urls'))
]

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

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

启动直接请求/api/book/接口,返回如下结果

[{"id": 1, "title": "Django REST Framework(\u7b2c\u4e8c\u7248)"}]

只需要对对应请求方法实现对应的操作并返回数据即可

正常获取到的QuerySet类型,可以直接通过list()变为列表,通过json.dumps()序列化,然后通过HttpResponse()返回

但是会遇到很多问题

  • 中文文字是ascii码的,需要在json.dumps()的时候传入ensure_ascii=False
  • 如果是datetime类型的时间,无法进行json.dumps(),需要直接使用JsonResponse()并传入safe=False
  • 直接使用JsonResponse(),中文文字还是ascii码,需要JsonResponce()的时候传入json_dumps_params={"ensure_ascii":False}

JsonResponse继承了HttpResponse,调用了json.dumps(data, cls=encoder, **json_dumps_params)

另外加一点问什么能序列化datatime,cls不是默认jsonencoder,而是使用的DjangoJSONEncoder,DjangoJSONEncoder继承jsonencoder,而重写了default方法,使用isinstance(o, datetime)判断数据是否为datetime.datetime类型,datetime.date类型或者datetime.time类型

所以view修改一下就是

from django.http import HttpResponse, JsonResponse
from django.views import View
from .models import Book

import json

class BookView(View):
    def get(self, request):
        book_queryset = Book.objects.values("id", "title")
        book_list = list(book_queryset)
        # ret = json.dumps(book_list, ensure_ascii=False)
        # return HttpResponse(ret)
        return JsonResponse(book_list, safe=False, json_dumps_params={"ensure_ascii": False})

也可以自定义解析器

class BooksView(View):
    def get(self, request):
        book_list = Book.objects.values("id", "title", "chapter", "pub_time", "publisher")
        book_list = list(book_list)
        # 如果我们需要取外键关联的字段信息 需要循环获取外键 再去数据库查然后拼接成我们想要的
        ret = []
        for book in book_list:
            pub_dict = {}
            pub_obj = Publish.objects.filter(pk=book["publisher"]).first()
            pub_dict["id"] = pub_obj.pk
            pub_dict["title"] = pub_obj.title
            book["publisher"] = pub_dict
            ret.append(book)
        ret = json.dumps(book_list, ensure_ascii=False, cls=MyJson)
        return HttpResponse(ret)


# 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)