rest_framwork框架的简单使用

from django.http.response import JsonResponse
class BookListView(View):
    def get(self, request, *args, **kwargs):
        # 返回的 是json格式
        all_books = models.Book.objects.all().values('id', 'title', 'pub_date')
        return JsonResponse(all_books)

错误:

In order to allow non-dict objects to be serialized set the safe parameter to False. 
为了一个非字典的对象可以被序列化需要设置 safe=False
return JsonResponse(all_books,safe=False)

错误:

Object of type 'QuerySet' is not JSON serializable
all_books是QuerSet类型
return JsonResponse(list(all_books),safe=False)

得到的文字是ascii类型

return JsonResponse(list(all_books), safe=False, json_dumps_params={'ensure_ascii': False})

 

django中的序列化器

复制代码
from django.core import serializers


class BookListView(View):
    def get(self, request, *args, **kwargs):
        all_books = models.Book.objects.all()
        data = serializers.serialize('json', all_books)
        return HttpResponse(data)
复制代码

得到的结果

 View Code

灵活度不高 

 

 

django的rest_framwork框架 做序列化 

get请求

需要有djangorestframework包

复制代码
from rest_framework.views import APIView
from rest_framework.response import Response


class BookListView(APIView):
    def get(self, request, *args, **kwargs):
        all_books = models.Book.objects.all()
        return Response(all_books)
复制代码

错误

rest_framework/api.html
没有注册 在settings中注册app
'rest_framework'

错误

Object of type 'Book' is not JSON serializable
不能被序列化
all_books = models.Book.objects.all().values()

得到页面 里面的内容就是book表中的数据   还需要得到 表中关联的数据   

需要序列化器  去序列化出想得到的结果

现在的问题是 一本书有多个作者   拿到的all_books的 是一本书对应一个作者  多个作者就有多条数据  这种情况是 默认序列化导致的

现在需要自己 创建序列化器  然后序列化之后的值再传给前端

创建一个序列化文件 serializer并在里面写   需要与models中'大体一样'

复制代码
from rest_framework import serializers


class BookSerializers(serializers.Serializer):
    title = serializers.CharField()
    price = serializers.DecimalField(max_digits=6, decimal_places=2)
    pub_data = serializers.DateTimeField()
复制代码

在views中

复制代码
from app01.serializer import BookSerializers


class BookListView(APIView):
    def get(self, request, *args, **kwargs):
        all_books = models.Book.objects.all()
        ser_obj = BookSerializers(all_books)            #ser_obj是对象
        return Rseponse(ser_obj.data)                     #ser_obj是序列化的结果
复制代码

报错

 'QuerySet' object has no attribute 'title'.
queryset对象没有title的属性
因为all_books中是多个对象
ser_obj = BookSerializers(all_books, many=True)

all_books = models.Book.objects.all().first()
#这样就值拿到了第一个  只序列化一个对象

这样就拿到了这些普通的字段

然后 在serializer中写    pub是外键关联的是出版社    author是多对多 关联作者表

pub= serializers.IntegerField()

报错

int() argument must be a string, a bytes-like object or a number, not 'Publisher'
pub_id = serializers.IntegerField()

这样的到的还是出版社的id

复制代码
class PublisherSerializers(serializers.Serializer):
    name = serializers.CharField()

class BookSerializers(serializers.Serializer):
    title = serializers.CharField()
    price = serializers.DecimalField(max_digits=6, decimal_places=2)
    pub_date = serializers.DateTimeField()
    pub = PublisherSerializers()
复制代码

这样就得到了

复制代码
 {
        "title": "没事就念经",
        "price": "999.99",
        "pub_date": "2019-01-01T10:10:10Z",
        "pub": {
            "name": "冰棍"
        }
    },
复制代码

再写authors

authors = serializers.SerializerMethodField()

报错

'BookSerializers' object has no attribute 'get_authors'
    pub = PublisherSerializers()
    authors = serializers.SerializerMethodField()

    def get_authors(self, obj):
        print(obj)

authors是 null  但是print(obj) 是Book object

复制代码
    pub = PublisherSerializers()
    authors = serializers.SerializerMethodField()   #.Ser之后就去调用get_字段名的方法


    def get_authors(self, obj):       #obj是当前循环book的对象
        ser_obj = AuthorSerializers(obj.authors.all(),many=True)   #进行序列化
        return ser_obj.data
复制代码
 结果

 

post请求

    def post(self, request, *args, **kwargs):
        print(request.data)

注意的是 在添加时 需要将外键和多对多 添加的数据变为id    

request.data得到的就是 提交的所有护数据

 

复制代码
    def post(self, request, *args, **kwargs):
        ser_obj = BookSerializers(data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        else:
            return Response(ser_obj.errors)
复制代码

 

 添加

报错

复制代码
HTTP 200 OK
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "pub": {
        "non_field_errors": [
            "Invalid data. Expected a dictionary, but got int."
        ]
    }
}
复制代码

这个错误是因为 添加的时的数据是int型  但是pub不是int类型字段 

所以需要在serializer的Book中添加

    post_pub = serializers.IntegerField()   #写入时   post
    post_authors = serializers.ListField()

报错

'Book' object has no attribute 'post_pub'.
在发出get请求时 没有post_pub字段
这时需要在字段里填写
read_only=True   #在读的时候   get
write_only=True  #在写入的时候  post

    pub = PublisherSerializers(read_only=True)
    authors = serializers.SerializerMethodField(read_only=True)   #读的时候   get

    post_pub = serializers.IntegerField(write_only=True)   #写入时   post
    post_authors = serializers.ListField(write_only=True)

再继续添加  

 添加

报错

`create()` must be implemented.
需要执行'create'方法
复制代码
    def create(self, validated_data):          #validated_data 是传过来的所有数据
        book_obj = models.Book.objects.create(
            title=validated_data['title'],
            price=validated_data['price'],
            pub_date=validated_data['pub_date'],
            pub_id=validated_data['post_pub'],
        )
        book_obj.authors.set(validated_data['post_authors'])
        return book_obj
复制代码

 

put请求

先设计urls地址   因为需要知道是需要修改的具体id  需要再单独写一个视图

class BookView(APIView):
    def get(self, request, pk, *args, **kwargs):
        book_obj = models.Book.objects.filter(pk=pk).first()
        ser_obj = BookSerializers(book_obj)
        return Response(ser_obj.data)

这是拿到的一个对象   然后

复制代码
    def put(self, request, pk, *args, **kwargs):
        book_obj = models.Book.objects.filter(pk=pk).first()
        ser_obj = BookSerializers(instance=book_obj,data=request.data)
        if ser_obj.is_valid():
            ser_obj.save()
            return Response(ser_obj.data)
        return Response(ser_obj.errors)
复制代码
 更新

报错

`update()` must be implemented.
需要'update'这个方法来更新
在serializer中写
复制代码
    def update(self, instance, validated_data): #instance 是要修改的数据       
                                                                 #validated_data是提交的数据
        instance.title = validated_data['title']
        instance.price = validated_data['price']
        instance.pub_date = validated_data['pub_date']
        instance.pub_id = validated_data['post_pub']
        instance.save()
        instance.authors.set(validated_data['post_authors'])
        return instance    
复制代码

这样是只能修改所有数据  

我想要的是提交我想要修改的数据就没办法改了

允许部分进行修改

ser_obj = BookSerializers(instance=book_obj, data=request.data, partial=True)

还是报错

这就可以用get取  取不到 就添加一个默认值

复制代码
    def update(self, instance, validated_data):  # instance 是要修改的数据   validated_data是提交的数据
        instance.title = validated_data.get('title', instance.title)
        instance.price = validated_data.get('price', instance.price)
        instance.pub_date = validated_data.get('pub_date', instance.pub_date)
        instance.pub_id = validated_data.get('post_pub', instance.pub_id)
        instance.save()
        instance.authors.set(validated_data.get('post_authors', instance.authors.all()))
        return instance
复制代码

然后修改数据

{
"title": "没事就念念经77777",
}

报错

 "detail": "JSON parse error - Expecting property name enclosed in double quotes: line 3 column 1 (char 30)"

原因就是因为 修改的数据后面有一个逗号

delete请求

    def delete(self, request, pk, *args, **kwargs):
        obj = models.Book.objects.filter(pk=pk).first()
        if obj:
            obj.delete()
            return Response({'smg': '删除成功'})
        return Response({'error': '删除的数据不存在'})

 

在BookListView中有 get post

在BookView中有 get put delete

 

较简洁的使用方法

在写serializer时的serializers.Serializer, 感觉就和 forms.form比较相似  

那有forms.ModelForm也就是有serializers.ModelSerializer            

对上面进行补充   is_valid()是对数据进行校验

在这里可以自己来设置校验的约束

def validate_title(value):
    if 'li' in value:
        raise serializers.ValidationError

然后在title放约束条件 也就是上面我自己定义的这个

    title = serializers.CharField(validators=[validate_title])

这样就可以了 

修改数据

{
    "title": "没事li就念经"
}

这样就报错了  因为在修改的数据中有li 当.is_valid()的时候就会调用validate_title方法  发现里面有li就抛出错误.

HTTP 200 OK
Allow: GET, PUT, DELETE, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "title": [
        "Invalid input."
    ]
}

这就是一个简单的

局部钩子   

用上局部钩子会 更灵活

在class中定义局部钩子   title是字段名

    def validate_title(self, value):
        if 'li' in value:
            raise serializers.ValidationError

修改数据 title中有li

报错

NOT NULL constraint failed: app01_book.title
为空
   def validate_title(self, value):
        if 'li' in value:
            raise serializers.ValidationError
        return value

给钩子一个返回值就可以正常使用了

全局钩子

    def validate(self, attrs):
        return attrs

接下里就是ModelSerializer

ModelSerializer的基础使用

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'

这样就 直接拿到了 Book表中的 所有信息   但是外键和多对多的字段 拿到的都是id

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = models.Book
        fields = '__all__'
        depth = 1

depth是深度的意思   这样就拿到了 所有的数据

虽然拿到了 但是也只是能在 显示中方便使用   在提交数据时是没办法使用的

所以这种方法不好用     去掉这个这个方法  还是拿到的是id  id就是book表中数据库的数据  

可以把这些特殊的字段 重写一下

class BookSerializer(serializers.ModelSerializer):
    pub_info = PublisherSerializers()     #重写pub字段

    class Meta:
        model = models.Book
        fields = '__all__'
        # depth = 1

报错

'Book' object has no attribute 'pub_info'.
是因为没有pub_info的这个字段 之前重写字段的时候可以使用是因为在 重写的字段后面加上了write_only=True
class BookSerializer(serializers.ModelSerializer):
    pub_info = serializers.SerializerMethodField()     #重写pub字段
    def get_pub_info(self,obj):
        return PublisherSerializers(obj.pub).data

    class Meta:
        model = models.Book
        fields = '__all__'
        # depth = 1

这样就可以了

在继续重写 多对多字段

class BookSerializer(serializers.ModelSerializer):
    pub_info = serializers.SerializerMethodField()  # 重写pub字段
    authors_info = serializers.SerializerMethodField()
    def get_pub_info(self, obj):
        return PublisherSerializers(obj.pub).data
    def get_authors_info(self, obj):
        return AuthorSerializers(obj.authors.all(), many=True).data
    class Meta:
        model = models.Book
        fields = '__all__'
        # depth = 1

这样就可以了  但是显示的时候 pub和authors字段还显示   pub_info 和authors_info应该在read是使用  pub和authors应该在write时使用

class BookSerializer(serializers.ModelSerializer):
    pub_info = serializers.SerializerMethodField(read_only=True)  # 重写pub字段
    authors_info = serializers.SerializerMethodField(read_only=True)
    def get_pub_info(self, obj):
        return PublisherSerializers(obj.pub).data
    def get_authors_info(self, obj):
        return AuthorSerializers(obj.authors.all(), many=True).data
    class Meta:
        model = models.Book
        fields = '__all__'
        # depth = 1
        extra_kwargs = {
            'pub': {'write_only': True},
            'authors': {'write_only': True},
        }

这样就可以了  比较上一种方法 这种相对简单一些  不用再写那么多方法了  

但是最后要注意的是  与之前相比在添加的时候  post_pub就应该换成pub了  

 

posted @ 2019-07-25 21:36  老李,向我开炮  阅读(339)  评论(0编辑  收藏  举报