首先是将项目建好:
①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
②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
添加到所需要验证的字段即可