django rest framework暴露api

一、创建序列化模型文件serializers.py

class Course(models.Model):
    """
    课程
    """
    title = models.CharField(verbose_name="课程名称", max_length=128)
    course_img = models.CharField(verbose_name="课程图片", max_length=128)
    level_choices = (
        (1,"初级"),
        (2,"中级"),
        (3,"高级"),
    )
    level = models.IntegerField(verbose_name="难易程度", choices=level_choices, default=1)

    def __str__(self):
        return self.title

class CourseDetail(models.Model):
    """
    课程详细
    """
    course = models.OneToOneField(to="Course", on_delete=models.CASCADE)
    slogon = models.CharField(verbose_name="口号", max_length=255)
    why = models.CharField(verbose_name="为什么要学?", max_length=255)
    recommend_course = models.ManyToManyField(verbose_name="推荐课程", to="Course", related_name="rc")

    def __str__(self):
        return "课程详细"+self.course.title

class Chapter(models.Model):
    """
    章节
    """
    num = models.IntegerField(verbose_name="章节")
    name = models.CharField(verbose_name="章节名称",max_length=32)
    course = models.ForeignKey(verbose_name="所属课程", to="Course", on_delete=models.CASCADE)

    def __str__(self):
        return self.name
models.py
from api.models import *
from rest_framework import serializers


class CourseSerializer(serializers.ModelSerializer):
    level = serializers.CharField(source="get_level_display")

    class Meta:
        model = Course
        fields = '__all__'


class CourseDetailSerializer(serializers.ModelSerializer):
    # one2one/fk/choice字段可以直接取出数据,m2m字段会返回一个queryset列表
    title = serializers.CharField(source="course.title")    # source引用本model字段的外键值作为新增"fields"的值
    img = serializers.CharField(source="course.course_img")
    level = serializers.CharField(source="course.get_level_display") # 获取choice的对应值,需要使用get_field_display()方法
                                                                    # restframework源码内部会判断"()"是否该添加

    # m2m字段取数据,需要自定义方法,这里使用SerializerMethodField,方法名称get_field(),这里定义get_recommends()方法。
    # class Meta中的fields需要明确字段值,字段值必须与通过这里使用SerializerMethodField()生成的实例对象名相等。
    recommends = serializers.SerializerMethodField()
    chapter = serializers.SerializerMethodField()

    class Meta:
        model = CourseDetail
        fields = ["course","title","img","level","slogon","why","recommends","chapter"]
        # depth = 2 # 定义返回数据的深度,可以将外键数据库中对应的值全部返回。

    # m2m字段取数据
    def get_recommends(self, obj):
        queryset = obj.recommend_course.all()
        return [{"id":row.id, "title":row.title} for row in queryset]

    # 字段为外键,并且需要反向查找取数据
    def get_chapter(self, obj):
        queryset = obj.course.chapter_set.all()
        return [{"id":row.id, "name":row.name} for row in queryset]

二、使用序列化文件,并对queryset进行序列化

from rest_framework.views import APIView
from rest_framework.response import Response

from api import models
from api.serializers import CourseSerializer,CourseDetailSerializer

class CourseView(APIView):
    # renderer_classes = [JSONRenderer,]
    def get(self, request, *args, **kwargs):
        ret = {"code":1000, "data":None}
        try:
            pk = kwargs.get("pk")
            if pk:
                obj = models.Course.objects.filter(pk=pk).first()
                ser = CourseSerializer(instance=obj, many=False)
            else:
                queryset = models.Course.objects.all()
                ser = CourseSerializer(instance=queryset, many=True)
            ret["data"] = ser.data
        except Exception as e:
            ret["code"] = 1001
            ret["error"] = "获取课程失败"
        return Response(ret)

三、在路由文件中添加路由

from api.views import course

urlpatterns = [
    path("course/", course.CourseView.as_view()),
    re_path("course/(?P<pk>d+)", course.CourseView.as_view()),
]

优化

urlpatterns = [
    path("course/", course.CourseView.as_view({"get":"list"})),
    re_path("course/(?P<pk>d+)", course.CourseView.as_view({"get":"retrieve"})),
]
from rest_framework.viewsets import ViewSetMixin

class CourseView(ViewSetMixin, APIView):
    def list(self, request, *args, **kwargs):
        ret = {"code": 1000, "data": None}
        try:
            queryset = models.Course.objects.all()
            ser = CourseSerializer(instance=queryset, many=True)
            ret["data"] = ser.data
        except Exception as e:
            ret["code"] = 1001
            ret["error"] = "获取课程失败"
        return Response(ret)

    def retrieve(self, request, *args, **kwargs):
        ret = {"code": 1000, "data": None}
        try:
            pk = kwargs.get("pk")
            queryset = models.CourseDetail.objects.filter(course_id=pk)
            ser = CourseDetailSerializer(instance=queryset, many=True)
            ret["data"] = ser.data
        except Exception as e:
            ret["code"] = 1001
            ret["error"] = "获取课程详细信息失败"
        return Response(ret)

rest framework中,如果想要在as_view()中添加变量来确定请求方式,需要继承ViewSetMixin

四、说明

rest framework中,如果想要对特殊的字段进行序列化设置,比如:ForeignKey、OneToOneField、ManyToManyField,需要单独配置。另外,如果需要进行字段反向查询,也需要单独设置。choice数据取出中文,需要使用get_field_display()方法

one2one/fk/choice字段设置
# one2one/fk/choice字段可以直接取出数据,m2m字段会返回一个queryset列表
    title = serializers.CharField(source="course.title")    # source引用本model字段的外键值作为新增"fields"的值
    img = serializers.CharField(source="course.course_img")
    level = serializers.CharField(source="course.get_level_display") # 获取choice的对应值,需要使用get_field_display()方法
                                                                    # restframework源码内部会判断"()"是否该添加

m2m查询数据

# m2m字段取数据,需要自定义方法,这里使用SerializerMethodField,方法名称get_field(),这里定义get_recommends()方法。
    # class Meta中的fields需要明确字段值,字段值必须与通过这里使用SerializerMethodField()生成的实例对象名相等。
    recommends = serializers.SerializerMethodField()

def get_recommends(self, obj):
queryset = obj.recommend_course.all()
return [{"id":row.id, "title":row.title} for row in queryset]

# 二者与class Meta同级,直接定义在class下

反向查询数据

chapter = serializers.SerializerMethodField()

def get_chapter(self, obj):
        queryset = obj.course.chapter_set.all()
        return [{"id":row.id, "name":row.name} for row in queryset]

# 二者与class Meta同级,直接定义在class下

depth定义返回的数据深浅

  因为接口返回的数据包含外键,所以外键的值为整数,默认depth=0,如果设置depth=1,那么外键的值会从整数变为外键值在关联表中对应的数据,如果外键关联表中返回数据中让然包含外键,并且depth=2或者更大,那么这个外键值会像一级外键一样,返回关联表对应的数据。

原文地址:https://www.cnblogs.com/ttyypjt/p/10999458.html