• DRF


    首先是将项目建好:

    ①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

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

  • 相关阅读:
    RestTemplate proxy 设置方式
    一道关于主键,闭包的软考题------关系代数复习-码,范式,闭包求解
    MyBatis的XML中使用内部类的方式
    MyBatis SpringBoot 杂记
    服务器安装笔记
    UML符号
    npm 设置代理
    国外一家代码网站
    设计模式复习
    docker 列出每个容器的IP
  • 原文地址:https://www.cnblogs.com/zhoulixiansen/p/10822058.html
Copyright © 2020-2023  润新知