首先是将项目建好:

①models:

from django.db import models

# Create your models here.

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


class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name="图书名称")
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = models.IntegerField(choices=CHOICES, verbose_name="图书的类别")
    pub_time = models.DateField(verbose_name="图书的出版日期")

    publisher = models.ForeignKey(to="Publisher", on_delete=None)
    author = models.ManyToManyField(to="Author")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "01-图书表"
        db_table = verbose_name_plural


class Publisher(models.Model):
    title = models.CharField(max_length=32, verbose_name="出版社的名称")

    def __str__(self):
        return self.title

    class Meta:
        verbose_name_plural = "02-出版社表"
        db_table = verbose_name_plural


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name="作者的姓名")

    def __str__(self):
        return self.name

    class Meta:
        verbose_name_plural = "03-作者表"
        db_table = verbose_name_plural
View Code

②urls

from django.urls import path, include
from .views import BookView, BookEditView


urlpatterns = [
    path('list', BookView.as_view()),  # 查看所有的图书
    path('retrieve/<int:id>', BookEditView.as_view()),
]

 

1,使用Django的JSonResponse序列化:

class BookView(View):
    def get(self, request):
        book_list = Book.objects.values("id", "title", "category", "pub_time", "publisher")
        book_list = list(book_list)
        ret = []
        for book in book_list:
            publisher_id = book["publisher"]
            publisher_obj = Publisher.objects.filter(id=publisher_id).first()
            book["publisher"] = {
                "id": publisher_id,
                "title": publisher_obj.title
            }
            ret.append(book)
        # ret = json.dumps(book_list, ensure_ascii=False)
        return JsonResponse(ret, safe=False, json_dumps_params={"ensure_ascii": False})  # 保证中文不乱码

缺点:

涉及到外键的时候,如果不做处理,那么就会仅返回外键的id

 2,使用Django的serializers进行序列化

from django.core import serializers
class BookView(View):

    def get(self, request):
        book_list = Book.objects.all()
        ret = serializers.serialize("json", book_list, ensure_ascii=False)
        return HttpResponse(ret)

优点:

可以直接传入queryset数据

缺点:

给了一些不该传的,和上面的逻辑类似

3,用DRF进行实现

使用pip install djangorestframework

使用pip list 查看

①配置rest_framework

②新建serializers.py这个文件

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
    pub_time = serializers.DateField()

和models的写法是非常类似的,如果说使用choice,序列化得出的还是一个数字而非中文,因此,再加一个source参数即可

那么视图函数的写法就要随之变一变了

改变一:继承的是APIView,而不是View

改变二:返回继承的是框架的response

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

 

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

class BookView(APIView):

    def get(self, request):
        # book_obj = Book.objects.first()  # 序列化单个
        # ret = BookSerializer(book_obj) 
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)  # 要用自己写的serializer的序列化类,当序列化多个的时候需要加上参数many=True
        return Response(ret.data)  # 参数是.data中

那么涉及外键关系的字段,必须在自定义的serializer中添加进去才能实现

class PublisherSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)

class AuthorSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    name = serializers.CharField(max_length=32)

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField()
    title = serializers.CharField(max_length=32)
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display")
    pub_time = serializers.DateField()
   publisher = PublisherSerializer()
   author = AuthorSerializer(many=True)

注意的是:当涉及到manytomany的时候必须加一个参数many=True

这个是区分一对多和多对多的区别的

view都不用修改

4,DRF反序列化

序列化的过程实际上是给前端返回数据,让前端展示;

那如果前端传数据给我们,就好比使用post请求来新增数据

在这前端传入的数据也有可传和必传之分

那就在序列化类中加入:required=False即可

但是我们的model中有choice字段,而前端传过来的时候是str

那就将原serializer中设置为readonly=True,表示仅用于序列化

在增加一个字段w_category用来反序列化;和前端商量好使用使用w开头,并且添加参数write_only=True就表明跳过序列化

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

 总结:

1,涉及到序列化和反序列化的时候,需要注意read_only和write_only字段

2,涉及到是否需要校验的时候就是required=False即可

在数据传到后端之后:

原来django的写法都是request.POST.get……,但是现在不同

现在都存储在request.data中

class BookView(APIView):

    def get(self, request):
        # book_obj = Book.objects.first()
        # ret = BookSerializer(book_obj)
        book_list = Book.objects.all()
        ret = BookSerializer(book_list, many=True)  # 要用自己写的serializer的序列化类
        return Response(ret.data)  # 参数是.data中


    def post(self, request):
        print(request.data)
        serializer = BookSerializer(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

根据restful原则返回的是新增的数据,数据在serializer.data中

在POST请求的时候需要定义create方法:

继续修改:

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data["author_list"])
        return book

需要注意的是vaildated_data是一个字典,因为book中的author是多对多的,因此需要别样添加

但是如果对于单条数据怎么处理呢?

class BookEditView(APIView):

    def get(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        ret = BookSerializer(book_obj)
        return Response(ret.data)
      
    def put(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        serializer = BookSerializer(book_obj, data=request.data, partial=True)  # partial表明准许进行部分更新
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors)

    def delete(self, request, id):
        book_obj = Book.objects.filter(id=id).first()
        book_obj.delete()
        return Response("")

那还需要一个updat方法

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data["author_list"])
        return book
#
    def update(self, instance, validated_data):
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("category", instance.category)
        instance.pub_time = validated_data.get("pub_time", instance.pub_time)
        instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
        if validated_data.get("author_list"):  # 
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance

DRF的验证:

假如现在有个需求,我传过来的字段需要有特殊要求,那怎么办?

class BookSerializer(serializers.Serializer):
    id = serializers.IntegerField(required=False)
    title = serializers.CharField(max_length=32, validators=[my_validate])
    CHOICES = ((1, "Python"), (2, "Go"), (3, "Linux"))
    category = serializers.ChoiceField(choices=CHOICES, source="get_category_display", read_only=True)
    w_category = serializers.ChoiceField(choices=CHOICES, write_only=True)
    pub_time = serializers.DateField()

    publisher = PublisherSerializer(read_only=True)
    publisher_id = serializers.IntegerField(write_only=True)
    author = AuthorSerializer(many=True, read_only=True)
    author_list = serializers.ListField(write_only=True)

    def create(self, validated_data):
        book = Book.objects.create(title=validated_data["title"], category=validated_data["w_category"],
                                pub_time=validated_data["pub_time"], publisher_id=validated_data["publisher_id"])
        book.author.add(*validated_data["author_list"])
        return book
#
    def update(self, instance, validated_data):
        instance.title = validated_data.get("title", instance.title)
        instance.category = validated_data.get("category", instance.category)
        instance.pub_time = validated_data.get("pub_time", instance.pub_time)
        instance.publisher_id = validated_data.get("publisher_id", instance.publisher_id)
        if validated_data.get("author_list"):
            instance.author.set(validated_data["author_list"])
        instance.save()
        return instance

    def validate_title(self, value):
        if "python" not in value.lower():
            raise serializers.ValidationError("标题必须含有python")
        return value

    def validate(self, attrs):
        if attrs["w_category"] == 1 and attrs["publisher_id"] == 1:
            return attrs
        else:
            raise serializers.ValidationError("分类以及标题不符合要求")

注意的是:字段验证哪一个字段就使用validate_  + 字段名,全局验证就是不用加字段

全局验证:其中attrs是所有字段名称和值得字典

当然django也准许我们自定义验证:

def my_validate(value):
    if "敏感信息" in value.lower():
        raise serializers.ValidationError("不能含有敏感信息")
    else:
        return value

添加到所需要验证的字段即可

 

posted on 2019-07-07 20:51  人生苦短use,what?  阅读(358)  评论(0编辑  收藏  举报