rest-framework项目示例

models.py

from django.db import models

# Create your models here.
class Book(models.Model):
    title=models.CharField(max_length=32)
    price=models.IntegerField()
    pub_date=models.DateField()
    publish=models.ForeignKey("Publish")
    authors=models.ManyToManyField("Author")
    def __str__(self):
        return self.title

class Publish(models.Model):
    name=models.CharField(max_length=32)
    email=models.EmailField()
    def __str__(self):
        return self.name

class Author(models.Model):
    name=models.CharField(max_length=32)
    age=models.IntegerField()
    def __str__(self):
        return self.name

 urls.py

from django.conf.urls import url
from django.contrib import admin
from api import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'books/$',views.BookView.as_view(),name="book_list"),
    url(r'publishes/$',views.PublishView.as_view(),name="publish_list"),
    url(r'books/(\d+)/$',views.BookDetailView.as_view(),name="book_detial"),
    url(r'publishes/(?P<pk>\d+)/$',views.PublishDetailView.as_view(),name="publish_detial"),
]

 

serializers组件
from rest_framework import serializers
from ..models import *

# 相当于是form的用法
# class Bookserializers(serializers.Serializer):
#     title = serializers.CharField(max_length=32)
#     price=serializers.IntegerField()
#     pub_date = serializers.DateField()
#     # publish = serializers.CharField()   #form组件中对于外键关联的字段是使用ChoiceField,但在rest_framework中是使用的CharField
#     publish = serializers.CharField(source="publish.pk")   #通过是用source来指定显示某个字段,如果不指定默认是显示的对象
#     # authors = serializers.CharField(source="authors.all")
#     '''
#     [
#     {
#         "title": "python",
#         "price": 111,
#         "pub_date": "2018-04-08",
#         "publish": "1",
#         "authors": "<QuerySet [<Author: alex>, <Author: egon>]>"    显示的是字符串queryset这个,不是太好看,所以我们可以通过自定义方法来解决这个问题
#     },
#     '''
#     # 针对多对多
#     authors=serializers.SerializerMethodField()
#     def get_authors(self,obj):  #固定用法,必须是get_多对多关系字段,需要传入一个对象,book对象
#         temp=[] #返回结果是什么类型的可以自己定义
#         for author in obj.authors.all():
#             temp.append({
#                 "pk":author.pk,
#                 "name":author.name
#             })
#         return temp

# 相当于是modelform的用法
class Bookserializers(serializers.ModelSerializer):
    # 重定义publish的显示,让它显示成url,一点就可以进入到和这个book关联的publish的信息,看到的是这样的形式的"publish": "http://127.0.0.1:8001/publishes/1/",
    '''
    [
    {
        "id": 1,
        "publish": "http://127.0.0.1:8001/publishes/1/",
        "authors": [
            {
                "pk": 1,
                "name": "alex"
            },
            {
                "pk": 2,
                "name": "egon"
            }
        ],
        "title": "python",
        "price": 111,
        "pub_date": "2018-04-08"
    },
    '''
    # publish=serializers.HyperlinkedIdentityField(
    #     view_name="publish_detial", #url中的别名,这里指定url中的别名,是可以反向解析出url
    #     lookup_field="publish_id",#出版社的url中的(\d+),指的是出版社的id
    #     lookup_url_kwarg="pk"   #分组命名中的名字
    #     # publishs/(?P<pk>\d+)/$
    # )

    class Meta:
        model = Book
        fields = "__all__"  #取出所有字段的这种方式中多对多的字段中找出的是"authors": [1,2],里面装的是主键id,但是我不想使用这种方式,可以通过自定义的方法来解决

    authors = serializers.SerializerMethodField()   #自定义的方法可以覆盖掉多对多的显示方式,而使用自定义的显示字段"authors": {"pk": 1,"name": "alex"}

    def get_authors(self,obj):  #固定用法,必须是get_多对多关系字段,需要传入一个对象,book对象
        temp=[] #返回结果是什么类型的可以自己定义
        for author in obj.authors.all():
            temp.append({
                "pk":author.pk,
                "name":author.name
            })
        return temp


class Publishserializers(serializers.ModelSerializer):
    class Meta:
        model=Publish
        fields="__all__"

 

views.py

from django.shortcuts import render, HttpResponse

# Create your views here.
from .models import *
from rest_framework.views import APIView

import json
from rest_framework.response import Response

from api.service.serializers import *


# 把serializers封装成一个组件了,在api/service/serializers中


class BookView(APIView):
    def get(self, request, *args, **kwargs):#使用方式一,二,三的时候继承的类是View
        # # 方法一:
        # book_list=list(Book.objects.all().values("title","price"))#如果使用json来序列化查询出来的queryset,需要先把queryset转成list类型才能进行序列化,否则会出现报错TypeError: Object of type 'QuerySet' is not JSON serializable
        # ret=json.dumps(book_list)
        # return HttpResponse(ret)

        # 方法二:
        # book_list=Book.objects.all()
        # temp=[]
        # for book in book_list:
        #     temp.append({"title":book.title,"price":book.price})
        # return HttpResponse(json.dumps(temp))

        # 方式三:使用serializers
        # from django.core import serializers
        # book_list=Book.objects.all()
        # ret= serializers.serialize("json",book_list) #将queryset进行序列化
        # print(ret)
        # return HttpResponse(ret)

        # 方式四:使用rest_framework组件中的序列化queryset的方法,方法三和方法四都是序列化queryset,但是方法四中除了序列化,还有其他的方法
        book_list = Book.objects.all()
        ret = Bookserializers(book_list, many=True, context={
            'request': request})  # 通过设置many=True,告诉Bookserializers,我传进去的是一个queryset,而不是一个对象,many默认是False
        # print(ret,type(ret))    #<class 'rest_framework.serializers.ListSerializer'>
        return Response(ret.data)  # 调用data方法可以取到序列化之后的结果

    # 提交请求数据
    def post(self, request, *args, **kwargs):
        print(request.data)
        ret = Bookserializers(data=request.data, context={
            'request': request})  # context={'request': request}传入它的原因是,想要在查询到关联的外键的信息中是一个url,

        if ret.is_valid():
            ret.save()  # 和form组件的用法是一样的
            return Response(ret.data)
        else:
            return Response(ret.errors)


'''
class BookSerializers(serializers.Serializer):
        title=serializers.CharField(max_length=32)
        price=serializers.IntegerField()
        pub_date=serializers.DateField()
        publish=serializers.CharField(source="publish.pk")
        authors=serializers.CharField()

在get()方法中获取到的book_list是一个queryset,相当于是
temp=[]
for book in book_list: 
 #for循环出来的每一个对象都要经过BookSerializers,然后再把需要的信息.出来
     temp.append({
            "title": book.title,
            "price": book.price,
            "pub_date": book.pub_date,
            "publish": book.publish.pk,
            "authors": book.authors,

         })


最终构造出来的数据类型
[
    {
        "title": "python",
        "price": 111,
        "pub_date": "2018-04-08",
        "publish": "1",
        "authors": [
            {
                "pk": 1,
                "name": "alex"
            },
            {
                "pk": 2,
                "name": "egon"
            }
        ]
    },]
'''


class PublishView(APIView):
    #
    def get(self, request, *args, **kwargs):
        publish_list = Publish.objects.all()
        # 将QuerySet序列化成json数据
        bs = Publishserializers(publish_list, many=True, context={'request': request})
        return Response(bs.data)

    # 提交数据请求
    def post(self, request, *args, **kwargs):
        print(request.data)
        # 将json数据转换为Queryset
        bs = Publishserializers(data=request.data, context={'request': request})
        if bs.is_valid():
            bs.save()
            # 数据保存成功
            return Response(bs.data)
        else:
            return Response(bs.errors)


# 针对BOOK表某一个数据操作 查看,编辑,删除一本书

class PublishDetailView(APIView):
    # 查看一本书
    def get(self, request, pk, *args, **kwargs):
        obj = Publish.objects.filter(pk=pk).first()
        if obj:
            bs = Publishserializers(obj, context={'request': request})
            return Response(bs.data)
        else:
            return Response()

    # 编辑一本书
    def put(self, request, pk, *args, **kwargs):
        # obj :编辑书籍对象
        obj = Publish.objects.filter(pk=pk).first()
        bs = Publishserializers(data=request.data, instance=obj, context={'request': request})
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)

    # 删除一本书
    def delete(self, request, pk, *args, **kwargs):
        Publish.objects.filter(pk=pk).delete()
        return Response()


# 根据rest_framework的规则对于表中所有数据的查看的类中,只能有查看和保存数据的方法,所以需要设计一个针对表中某一个对象的操作方法

# 针对Book表某一个数据操作:查看,编辑,删除一本书
class BookDetailView(APIView):
    # 查看一本书
    def get(self, request, pk, *args, **kwargs):
        obj = Book.objects.filter(pk=pk).first()
        if obj:  # 判断obj是否存在,如果存在就返回一个序列化之后的json数据,否则就返回空白文本
            bs = Bookserializers(obj)
            return Response(bs.data)
        else:
            return Response()

    # 编辑一本书
    def put(self, request, pk, *args, **kwargs):
        # obj:编辑书籍对象
        obj = Book.objects.filter(pk=pk).first()
        bs = Bookserializers(data=request.data, instance=obj)  # 同modelform中的用法一样,把提交上来的数据传进去,还需要编辑的对象,是对哪一本书进行的操作
        if bs.is_valid():
            bs.save()
            return Response(bs.data)
        else:
            return Response(bs.errors)

    # 删除一本书
    def delete(self, request, pk, *args, **kwargs):
        Book.objects.filter(pk=pk).delete()
        return Response()  # 删除成功之后返回空白文本

# 如果我对关联表publish表进行操作的话,也是如同Book表一样,把Book的上面的两个类复制一份,然后改一下表名,再写一个publish的serliazer,显然会造成代码的重复
# 这里我们引入一个mixin,什么是mixin,mixin就是混合类
# ----------------------------------------------------------mixin--------------------------------------------------------------------------------
# from rest_framework import mixins
# from rest_framework import generics
#
# class BookView(mixins.ListModelMixin,   #根据字面意思也能知道ListModelMixin是查看数据的
#                mixins.CreateModelMixin,    #是保存数据的
#                generics.GenericAPIView  #GenericAPIView继承了APIView
#                ):
#     queryset = Book.objects.all()   #必须查询出来的数据是queryset类型
#     serializer_class = Bookserializers  #serializer_class是源码中规定的,必须是这个名字,把自己定义的Bookserializers类赋值给serializer_class,用来做序列化操作
#
#     def get(self,request,*args,**kwargs):
#         return self.list(request,*args,**kwargs)
#
#     def post(self, request, *args, **kwargs):
#         return self.create(request, *args, **kwargs)
#
# class BookDetailView(
#     mixins.RetrieveModelMixin,  #对于一个对象的数据的查看
#     mixins.DestroyModelMixin,   #对于一个对象的数据的删除
#     mixins.UpdateModelMixin,    #对于一个对象的数据的编辑
#     generics.GenericAPIView,    #继承了APIView类
# ):
#     queryset = Book.objects.all()
#     serializer_class = Bookserializers
#
#     def get(self,request,*args,**kwargs):
#         return self.retrieve(request,*args,**kwargs)    #调用这个方法,会把我我传进去的queryset,serializer_class,经过处理,最终返回给我的是我要查询的这个对象的json数据
#     def put(self,request,*args,**kwargs):
#         return self.update(request,*args,**kwargs)
#     def delete(self,request,*args,**kwargs):
#         return self.destroy(request,*args,**kwargs)




# class PublishView(mixins.ListModelMixin,
#                mixins.CreateModelMixin,
#                generics.GenericAPIView):
#
#     queryset = Publish.objects.all()
#     serializer_class = Publishserializers
#
#     def get(self, request, *args, **kwargs):
#         return self.list(request, *args, **kwargs)
#
#     def post(self, request, *args, **kwargs):
#         return self.create(request, *args, **kwargs)
#
#
# class PublishDetailView(
#     mixins.RetrieveModelMixin,
#     mixins.DestroyModelMixin,
#     mixins.UpdateModelMixin,
#     generics.GenericAPIView
# ):
#     queryset = Publish.objects.all()
#     serializer_class = Publishserializers
#
#     def get(self,request, *args, **kwargs):
#         return self.retrieve(request, *args, **kwargs)
#
#     def delete(self,request, *args, **kwargs):
#         return self.destroy(request, *args, **kwargs)
#
#     def put(self,request, *args, **kwargs):
#         return self.update(request, *args, **kwargs)

# 如果要对publish进行操作,也是上面的方法,也是改一下表名,但是在调用的方法上也是代码的重复,这样是和继承APIView实现的方法没有多大差别,代码还是重复的使用
# 所以我们再引入一个类,可以解决上面的问题
# ------------------------------------------------------------使用通用的基于类------------------------------------------------
# from rest_framework import mixins
# from rest_framework import generics
#
# class BookView(generics.ListCreateAPIView):
#     '''
#     点进去看源码,原来是和我们上面自己写的是一样的,这里只不过是给封装到了类里面
#     class ListCreateAPIView(mixins.ListModelMixin,
#                         mixins.CreateModelMixin,
#                         GenericAPIView):
#                         .....
#     '''
#     queryset = Book.objects.all()
#     serializer_class = Bookserializers
#
#
# class BookDetailView(generics.RetrieveUpdateDestroyAPIView):#RetrieveUpdateDestroyAPIView里面包含了查,更新,和删除一个对象的功能
#     queryset = Book.objects.all()
#     serializer_class = Bookserializers
#
#
#
# class PublishView(generics.ListCreateAPIView):
#     '''
#     点进去看源码,原来是和我们上面自己写的是一样的,这里只不过是给封装到了类里面
#     class ListCreateAPIView(mixins.ListModelMixin,
#                         mixins.CreateModelMixin,
#                         GenericAPIView):
#                         .....
#     '''
#     queryset = Publish.objects.all()
#     serializer_class = Publishserializers
#
#
# class PublishDetailView(generics.RetrieveUpdateDestroyAPIView):#RetrieveUpdateDestroyAPIView里面包含了查,更新,和删除一个对象的功能
#     queryset = Publish.objects.all()
#     serializer_class = Publishserializers

# ps:有没有发现这种方法很简单呢

 

posted @ 2018-04-09 17:50  dwenwen  阅读(490)  评论(0)    收藏  举报