当前位置:   article > 正文

2、DRF实战总结:基于函数的视图API以及自定义序列化器(附源码)_drf serializers model自定义

drf serializers model自定义

前面介绍了什么是DRF,什么是序列化以及什么是符合RESTful规范的Web API。本篇使用DRF提供的序列化器(Serializers类),基于函数视图开发两个API接口并测试。

https://blog.csdn.net/zhouruifu2015/article/details/129648966?spm=1001.2014.3001.5501

需要值得注意的有以下几点:

1. 定义序列化器时一定要注意区分read-only字段和常规字段,read-only字段通常对应用户不能自己操作(添加或修改)的数据。

2. DRF中使用函数开发API视图千万别忘了使用@api_view这个重要的装饰器

两个API的简单描述如下所示 (注意:规范的API文档需要更多信息)。

  1. # 接口描述:文章列表资源。GET请求获取文章列表资源、POST请求提交新文章
  2. # 接口地址:http://127.0.0.1:8000/api/v1/articles
  3. # 请求方式:GET, POST
  4. # 返回参数:JSON格式文章列表和状态码
  5. # 接口描述:单篇文章资源。GET获取文章详情、PUT修改、DELETE删除
  6. # 接口地址:http://127.0.0.1:8000/api/v1/articles/{id}
  7. # 请求方式:GET, PUT, DELETE
  8. # 返回参数:GET和PUT(JSON格式文章详情和状态码), DELETE(状态码)

创建项目和APP

工程路径及APP:django_framework\django_rest_framework_pro\drf_pro

安装依赖库

pip install django djangorestframework

创建一个名为django_rest_framework_pro的项目,以及创建一个名为drf_pro的app。

django-admin.py startproject django_rest_framework_pro # 创建项目

cd django_rest_framework_pro               # 进入项目目录

python manage.py startapp drf_pro # 创建APP

将新建的drf_pro  app和rest_framework添加到INSTALLED_APPS。编辑apiproject/settings.py文件, 如下所示:

INSTALLED_APPS =(

       ...

       'rest_framework',

    'drf_pro',

)

注意: 如果使用的Django版本很低或希望避免自己的app名与第三方库的app名冲突,需要使用drf_pro.apps. drf_pro替换drf_pro。

创建模型 (models)

编辑drf_pro/models.py文件, 创建Article模型,用于存储博客的文章数据。用户(User)与文章(Article)是单对多的关系(ForeinKey),因为一个用户可以发表多篇文章。为了方便,用户模型使用了Django自带的用户模型。

  1. from django.db import models
  2. from django.utils.translation import ugettext as _
  3. from django.contrib.auth import get_user_model
  4. # 用户模型 此处直接使用了Django自带的用户模型
  5. User = get_user_model()
  6. class Article(models.Model):
  7. """
  8. 存储文章数据
  9. """
  10. STATUS_CHOICES = (('p', _('Published')), ('d', _('Draft')),)
  11. title = models.CharField(verbose_name=_('Title (*)'), max_length=90, db_index=True)
  12. body = models.TextField(verbose_name=_('Body'), blank=True)
  13. # 用户(User)与文章(Article)是单对多的关系(ForeinKey)
  14. author = models.ForeignKey(User, verbose_name=_('Author'), on_delete=models.CASCADE, related_name='articles')
  15. status = models.CharField(_('Status (*)'), max_length=1, choices=STATUS_CHOICES, default='s', null=True, blank=True)
  16. create_date = models.DateTimeField(verbose_name=_('Create Date'), auto_now_add=True)
  17. def __str__(self):
  18. return self.title
  19. class Meta:
  20. ordering = ['-create_date']
  21. verbose_name = "Article"
  22. verbose_name_plural = 'Articles'
  23. db_table = "articles"

模型创建好后,同步数据库并创建超级用户, Django会自动根据模型字段生成数据表。

python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
编辑drf_pro/admin.py文件, 添加如下代码:
  1. from django.contrib import admin
  2. from .models import Article
  3. # Register your models here.
  4. class ArticleAdmin(admin.ModelAdmin):
  5. list_display = ('title', 'status', 'create_date')
  6. list_filter = ('status',)
  7. list_per_page = 10
  8. admin.site.register(Article, ArticleAdmin)

启动Django服务器,进入admin后台添加些文章和用户

python manage.py runserver

自定义序列化器(serializers.py)

     利用DRF开发Web API的第一步总是自定义序列化器(serializers)。序列化器的作用是将模型实例(比如用户、文章)序列化和反序列化为诸如json之类的表示形式。一个模型实例可能有许多字段属性,但一般情况下不需要把所有字段信息以JSON格式数据返回给用户。序列化器定义了需要对一个模型实例的哪些字段进行序列化/反序列化, 并可对客户端发送过来的数据进行验证存储
     就像Django提供了Form类和ModelForm类两种方式自定义表单一样,REST framework提供了Serializer类和ModelSerializer类两种方式供自定义序列化器。前者需手动指定需要序列化和反序列化的字段,后者根据模型(model)生成需要序列化和反序列化的字段,可以使代码更简洁。
     下面分别展示如何使用Serializer类和ModelSerializer类自定义序列化器。

使用Serializers

在drf_pro的目录下创建一个名为serializers.py文件,并添加以下内容。
  1. from rest_framework import serializers
  2. from .models import Article
  3. from django.contrib.auth import get_user_model
  4. # 使用REST framework提供的Serializer类和ModelSerializer类两种方式自定义序列化器
  5. User = get_user_model()
  6. class ArticleSerializer(serializers.Serializer):
  7. id = serializers.IntegerField(read_only=True)
  8. title = serializers.CharField(required=True, allow_blank=True, max_length=90)
  9. body = serializers.CharField(required=False, allow_blank=True)
  10. author = serializers.ReadOnlyField(source='author.id')
  11. status = serializers.ChoiceField(choices=Article.STATUS_CHOICES, default='p')
  12. create_date = serializers.DateTimeField(read_only=True)
  13. def create(self, validated_data):
  14. """
  15. Create a new 'article' instance
  16. :param instance:
  17. :param validated_data:
  18. :return:
  19. """
  20. return Article.objects.create(**validated_data)
  21. def update(self, instance, validated_data):
  22. """
  23. Use validated data to return an existing `Article` instance.
  24. :param instance:
  25. :param validated_data:
  26. :return:
  27. """
  28. instance.title = validated_data.get('title', instance.title)
  29. instance.body = validated_data.get('body', instance.body)
  30. instance.status = validated_data.get('status', instance.status)
  31. instance.save()
  32. return instance

序列化器类的第一部分定义了序列化/反序列化的字段。create()和update()方法定义了在调用serializer.save()时如何创建和修改完整的实例。

序列化器类与Django Form类非常相似,并在各种字段中设置各种验证,例如required,max_length和default。

注意:定义序列化器时一定要注明哪些是仅可读字段(read-only fields),哪些是普通字段。对于read-only fields,客户端是不需要也不能够通过POST或PUT请求提交相关数据进行反序列化的。

本例中ID和create_date都是由模型自动生成,每个article的author也希望在视图中与request.user绑定,而不是由用户通过POST或PUT自行修改,所以这些字段都是read-only。相反title,body和status是用户可以添加或修改的字段,所以不能设成read-only。

使用ModelSerializers

ArticleSerializer类中重复了很多包含在Article模型(model)中的字段信息。使用ModelSerializer类可以重构序列化器类,使整体代码更简洁。

将drf_pro/serializers.py文件中的ArticleSerializer类替换为以下内容。两者作用是一样的。

  1. class ArticleSerializer2(serializers.ModelSerializer):
  2. class Meta:
  3. model = Article
  4. fields = '__all__'
  5. read_only_fields = ('id', 'author', 'create_date')

编写API视图(views.py)

     接下来要使用自定义的序列化器来编写API视图,处理客户端的请求,并给出响应。与Django一样,DRF也支持使用基于函数的视图(Functional Based View, FBV)和基于类的视图(Class Based View, CBV)来编写视图(views)。
     实现两个基于函数的视图:article_list和article_detail。编辑blog/views.py文件,并且添加以下内容。
  1. from rest_framework import status
  2. from rest_framework.decorators import api_view
  3. from rest_framework.response import Response
  4. from .models import Article
  5. from .serializers import ArticleSerializer, ArticleSerializer2
  6. @api_view(['GET', 'POST'])
  7. def article_list(request):
  8. """
  9. DRF提供的序列化器类Serializer和ModelSerializer
  10. list all articles or create a new article.
  11. :param request:
  12. :return:
  13. """
  14. if request.method == 'GET':
  15. articles = Article.objects.all()
  16. serializer = ArticleSerializer(articles, many=True)
  17. return Response(serializer.data)
  18. elif request.method == 'POST':
  19. serializer = ArticleSerializer(data=request.data)
  20. if serializer.is_valid():
  21. serializer.save(author=request.user)
  22. return Response(serializer.data, status=status.HTTP_201_CREATED)
  23. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
     注意:由于序列化器中author是read-only字段,用户是无法通过POST提交来修改的,在创建Article实例时需手动将author和request.user绑定,如下所示:
     serializer.save(author=request.user)
     以下是views.py模块中单个article的视图。
  1. @api_view(['GET','PUT',"DELETE"])
  2. def article_detail(request, pk):
  3. """
  4. retrieve, update or delete an article instance
  5. :param request:
  6. :param pk:
  7. :return:
  8. """
  9. try:
  10. article = Article.objects.get(pk=pk)
  11. except Article.DoesNotExist:
  12. return Response(status=status.HTTP_404_NOT_FOUND)
  13. if request.method == 'GET':
  14. serializer = ArticleSerializer2(article)
  15. return Response(serializer.data)
  16. elif request.method == 'PUT':
  17. serializer = ArticleSerializer2(article, data=request.data)
  18. if serializer.is_valid():
  19. serializer.save()
  20. return Response(serializer.data)
  21. return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
  22. elif request.method == 'DELETE':
  23. article.delete()
  24. return Response(status=status.HTTP_204_NO_CONTENT)

这两个函数视图看似和Django普通函数视图非常类似,但其作用大不相同。这里使用了DRF提供的@api_view这个非常重要的装饰器,实现了以下几大功能:

  • 与Django传统函数视图相区分,强调这是API视图,并限定了可以接受的请求方法。
  • 拓展了django原来的request对象。新的request对象不仅仅支持request.POST提交的数据,还支持其它请求方式如PUT或PATCH等方式提交的数据,所有的数据都在request.data字典里。这对开发Web API非常有用。
request.POST  # 只处理表单数据  只适用于'POST'方法
request.data  # 处理任意数据  适用于'POST','PUT'和'PATCH'方法

注意: 不再显式地将请求或响应绑定到特定的内容类型比如HttpResponse和JSONResponse,统一使用Response方法返回响应,该方法支持内容协商,可根据客户端请求的内容类型返回不同的响应数据。

请求地址添加可选的格式后缀(urls.py)

     为了充分利用的响应不再与单一内容类型连接,可以为API路径添加对格式后缀的支持。使用格式后缀,明确指定了给定格式的URL,这意味着API将能够处理诸如http://example.com/api/items/4.json之类的URL。
     像下面这样在这两个视图中添加一个format关键字参数。
     def article_list(request, format=None):
     和
     def article_detail(request, pk, format=None):
     现在更新blog/urls.py文件,给现有的URL后面添加一组format_suffix_patterns。
  1. from django.urls import re_path
  2. from rest_framework.urlpatterns import format_suffix_patterns
  3. from . import views
  4. urlpatterns = [
  5. re_path(r'^articles/$', views.article_list),
  6. re_path(r'^articles/(?P<pk>[0-9]+)$', views.article_detail),
  7. ]
  8. urlpatterns = format_suffix_patterns(urlpatterns=urlpatterns)
app的urls加入到项目URL配置django_rest_framework_pro/urls.py文件中,如下所示:
  1. from django.contrib import admin
  2. from django.urls import path, include
  3. urlpatterns = [
  4. url(r'^admin/', admin.site.urls),
  5. # 引入APP中的urls
  6. path('v1/', include('drf_pro.urls')),
  7. ]

服务验证-API测试

启动Django服务器

获取

[GET] http://127.0.0.1:8000/v1/articles
发送GET请求到/v1/articles, 可以看HTTP=200 OK的字样和json格式的文章列表数据。

注意:DRF默认是以可浏览的api形式展示返回响应结果的(articles.api),如果只需要返回最简单的json格式的数据,只需要在访问地址后面加上.json后缀即可(articles.json),或者点击页面下拉框中的GET,选择json即可,如下所示:

新增

[POST] http://127.0.0.1:8000/v1/articles
发送POST请求到/v1/articles。在GET页面下方下拉框选择json格式数据,数据为由序列化器中定义的非read-only字段组成的json对象,点击POST提交后即可看到新的文章已经添加。
  1. # 测试数据:
  2. {
  3. "title":"DRF实战总结:基于函数的视图API以及自定义序列化器",
  4. "body":"定义序列化器时一定要注意区分read-only字段和常规字段,read-only字段通常对应用户不能自己操作(添加或修改)的数据",
  5. "status":"d"
  6. }

 

修改

[GET] http://127.0.0.1/v1/articles/2
发送get请求到/v1/articles/2,获取第2篇文章详情。

[PUT] http://127.0.0.1:8000/v1/articles/2

发送PUT请求到/v1/articles。在GET页面下方下拉框下选择json格式数据,数据为由序列化器中定义的非read-only字段组成的json对象,点击PUT提交后即可看到第3篇文章标题及状态已经由draft变成published。

删除

点击页面上DELETE按钮即可。

代码示例:https://download.csdn.net/download/zhouruifu2015/87611605

输入才有输出,吸收才能吐纳。——码字不易


更多资料 · 微信公众号搜索【CTO Plus】关注后,获取更多,我们一起学习交流。

关于公众号的描述访问如下链接


关于Articulate“做一个知识和技术的搬运工。做一个终身学习的爱好者。做一个有深度和广度的技术圈。”一直以来都想把专业领域的技https://mp.weixin.qq.com/s/0yqGBPbOI6QxHqK17WxU8Q 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/44692
推荐阅读
相关标签
  

闽ICP备14008679号