以下案例主要以vue为例
安装插件
修改配置信息
corsheaders首先在Vue项目的main.js中全局配置axios
vue获取数据进行渲染删除
创建数据
修改数据
除了使用vuex在vue中的标准解决方案外,还有类似浏览器的内部存储机制,比如
Response是不能直接返回ORM数据的,所以需要我们进行序列化操作,可以通过手动将其转为字典或JSON,也可以使用DRF所提供的序列化器,我们一般建议您使用序列化器,这个更专业,更简单,并且格式更为统一
如果你经常使用的是自己去将数据封装为JSON,那么常见的代码模型就像这样
字段多了的话,这个工作量就会越来越麻烦了,而且有关于时间(***DateTimeField、DateField***)等字段类型的序列化直接通过JSON也是不行的,需要自己手动编写JSON的序列化器,非常麻烦,于是乎 DRF 就提供了更为便捷的两种序列化器,普通序列化器与模型序列化器
普通序列化器,可以按照给定字段,将所匹配的ORM数据字段转换为JSON数据,不光可以对一条数据,也可以对一个QuerySet所对应的结果集
比如一个课程表有如下一些字段
测试数据可以通过数据库手动添加 那么普通序列化器就可以定义如下,按照模型类字段支持即可,非常简单
普通的序列化器,不光可以为数据库模型类定义,也可以为非数据库模型类的数据定义,只是这里为模型类定义时,需要根据模型类字段一一映射
序列化就是将ORM数据放入序列化器加工,诞生出JSON数据对象,序列化器对象的 data 属性即为处理好的 JSON 数据对象
单挑数据的序列化很简单,直接通过序列化器类对象的参数instance传入查询得到的结果即可
如果使用像filter、all这样的一些ORM方法,获取到的是QuerySet结果集,不是单独数据对象,那么使用序列化器时,需要传入many=True参数,用来表示:哇哦~
反序列化的概念很简单,就是把JSON等数据变为ORM数据对象,甚至是入库或者是修改
DRF要求序列化器必须对数据进行校验,才能获取验证成功的数据或保存成模型类对象
在操作过程中,反序列化首先需要通过data**传参**
接着调用
is_valid
进行校验,
验证成功
返回
True
,反之返回
False
对校验过后的对象调用
save
方法,这个
save
方法会触发
序列化器
中的
create
方法
比如现在,还是之前练习需要提交数据创建课程的接口,此时可以这么做
为了能够保证数据成功入库,默认的普通序列化器是不具备入库功能的,需要编写create方法
成功之后,就可以通过像之前一样的数据提交,编写视图完成数据入库,序列化器可以直接处理request所提交的数据data,并且可以剔除在request.data中其他多余的字段,只会处理序列化器里的字段
反序列化经过校验的数据,不光可以创建数据,还可以更新数据呢
默认普通序列化器是没有自带对于数据的更新方法的,现在需要在序列化器里创建update方法
然后通过PUT传递要更新数据的ID,以及更新后的值,来为某条数据更新
之前的序列化器,很明显可以感觉到,如果模型类字段少了,还行,但是模型字段越来越多,那么开发者在序列化器里所要复刻的字段也要越来越多,很麻烦奥
而且还得手动实现update和create方法,而且光写了序列化器字段还不行,还得有字段属性
于是乎,有了现在的与模型类关联的序列化器,可以更加方便的进行字段映射以及内置方法的编写,简直是太棒了
模型类关联序列化器大概总结有如下三个特性,一个缺点
那么模型类关联的序列化器用啥呢?用的是新的序列化器基类
比如一个商品模型类
按照之前的普通序列化写法,你需要同步一个字段,并将字段属性也要记得同步,非常麻烦 但通过与模型类关联的序列化器就很简单了
模型类关联的序列化器和普通的序列化器使用方法一样
使用序列化器返回当前所有的商品数据,还是像之前一样传入instance参数即可,还要记得由于是多个商品,不是单独数据,要记得加many=True参数
模型序列化器的创建就更简单了,不需要手动实现create方法,大致流程如下:
创建商品接口
注意:反序列化自动生成的字段属性中,不会包含原始模型类字段中的default字段属性
更新某一个商品数据,模型序列化器也是自带了update方法
更细商品接口
序列化
时,将模型类对象传入
instance
参数
反序列化创建
时,将要被
反序列化
的数据传入
data
参数
反序列化更新时,将要更新的数据对象传入instance参数,更新后的数据传入data**参数**
模型序列化器比普通序列化器更加方便,自动生成序列化映射字段,create方法等
关联外键序列化,字段属性外键为多时要记得加many=True
之前的序列化,只是简单的对一张表进行处理,那么如果遇到一对一,多对一,多对多的情况该咋序列化呢,我们来看看
比如现在有两张很常见的关联表,老师表和学生表
学生表中,包含外键 teacher,外键可以通过如下一些方式进行序列化
将关联表的主键作为结果返回,使用 PrimaryKeyRelatedField字段,该字段需要包含 queryset或 read_only属性
设置 read_only代表该字段不进行反序列化校验
编写返回一个学生的接口
返回的数据类似如下效果
将关联表的*str*方法作为结果返回
接口返回效果如下
使用关联表的指定字段作为结果返回
效果就很直观了,返回的就是 slug_field字段所对应的模型层里这个字段代表的值
上面几种办法只能返回单独定义的字段,适合某些返回数据简单的情况下,如果希望能返回当前关联字段的详细数据,那么可以通过额外定义关联表的序列化器,让当前外键字段使用关联表序列化器即可
此时外键 teacher 字段所对应的序列化器是关联表的序列化器,需要返回的关联表数据可以通过另外这个序列化器进行单独定义,返回的接口数据如下
pip install django-cors-headers
INSTALLED_APPS = [
...
'corsheaders', # 跨域
...
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', # 添加跨域中间件
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware', # 关闭csrf验证
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
CORS_ORIGIN_ALLOW_ALL = True
import axios from 'axios' // 导入axios
axios.defaults.baseURL = "http://127.0.0.1:8000/" // 设置axios请求的默认域名,即django服务的域名
Vue.prototype.$axios = axios // 全局挂载axios
<template>
<div>
<!-- 三、循环展示所有作者 -->
<table>
<tr v-for="author in authorList" :key="author.id">
<td>{{ author.id }}</td>
<td>{{ author.name }}</td>
<td>{{ author.gender }}</td>
<td>{{ author.age }}</td>
<td>
<!--
内层元素的事件会从内向外依次触发, 叫做冒泡机制
想要阻止冒泡事件,需要 使用 事件修饰符 .stop
-->
<button @click.stop="delAuthor">删除</button>
</td>
</tr>
</table>
</div>
</template>
<script>
export default {
name: "AuthorList",
data() {
return {
authorList: []
}
},
methods: {
// 一、get请求所有作者
getAuthorList() {
this.$axios.get('author/')
.then(resp => {
console.log(resp.data)
this.authorList = resp.data
})
},
delAuthor(id) {
this.$axios.delete('author/' + id + '/')
.then(resp => {
// 删除成功,重新请求数据,刷新页面
this.getAuthorList();
})
.catch(err => {
console.log('删除失败')
})
},
},
mounted() {
// 二、挂载,让请求自动执行
this.getAuthorList();
}
}
</script>
<template>
<div>
<!-- 1. 使用v-model指定从表单获取数据 -->
图书标题: <input type="text" v-model="title">
图书价格: <input type="text" v-model="price">
<!-- 3. 使用事件绑定,将 方法和按钮进行绑定 -->
<button @click="btn">添加</button>
</div>
</template>
<script>
export default {
name: "Book",
data() {
return {
title: '',
price: ''
}
},
methods: {
btn() {
// 2. 定义方法, 使用axios发送post请求,并携带参数
this.$axios.post('book/', {'title': this.title, 'price': this.price})
.then(resp => {
// 添加成功,输出响应数据
console.log(resp.data)
})
.catch(err => {
// 添加失败,输出错误信息
console.log(err.response.data)
})
}
}
}
</script>
<template>
<div>
<!-- 修改之前,需要有原始数据 -->
<!-- 一、修改图书之前,给表单设置默认值, 原本的图书数据 -->
<!-- 二.修改同样也需要获取用户输入的新数据 -->
图书标题: <input type="text" v-model="book.title">
图书价格: <input type="text" v-model="book.price">
<!-- 四、对按钮绑定事件 -->
<button @click="updateBook">修改</button>
</div>
</template>
<script>
export default {
name: "BookUpdate",
data() {
return {
id: 1,
book: {
title: '',
price: ''
}
}
},
methods: {
// 1.1 获取id对应的图书数据
getBook() {
this.$axios.get('book/' + this.id + '/')
.then(resp => {
// 请求成功,将请求到的图书数据赋值给data中的变量,
// 而表单和data中的数据进行双向绑定
// 给data中的数据设置默认值,表单也会有默认值
this.book.title = resp.data.title
this.book.price = resp.data.price
})
},
// 三. 定义方法,使用put提交数据
updateBook() {
this.$axios.put('book/' + this.id + '/', this.book)
.then(resp => {
console.log(resp.data)
})
}
},
mounted() {
// 1.3 挂载
this.getBook();
}
}
</script>
localStorage.setItem('user', this.username) // 用户名存入localStorage,以做状态保持
let username = localStorage.getItem('user') // 取出user信息,可以判断用户是否登录
data = models.objects.all()
json_ = {}
for d in data:
json_['age'] = d.age
json_['name'] = d.name
return Response(json_)
from rest_framework import serializers
class Course(models.Model):
name = models.CharField(max_length=20, verbose_name='课程名字')
created = models.DateField(verbose_name='课程创建时间')
def __str__(self):
return self.name
class CourseSer(serializers.Serializer):
name = serializers.CharField(max_length=20)
created = serializers.DateField(auto_now_add=True)
object = models.objects.get(pk=1)
ser_data = Serializer(instance=object)
ser.data # 这就是这一条数据的 JSON 结果
objects = models.objects.all()
ser_data = Serializer(instance=objects, many=True)
ser_data.data # 这就是这一群数据的 JSON 结果
data = {
'name':"张三",
...
}
ser = Serializer(data=data)
if ser.is_valid():
ser.save() # 只传 data 参数的时候,save 方法会触发序列化器器中的 create 方法
class CourseSer(serializers.Serializer):
name = serializers.CharField(max_length=20)
created = serializers.DateField()
def create(self, validated_data):
object = Course.objects.create(
**validated_data
)
return object
class CourseCreate(APIView):
def post(self, request):
ser = CourseSer(data=request.data)
if ser.is_valid():
ser.save()
error = ser.errors
return Response({'msg': error if error else 'success'})
class CourseSer(serializers.Serializer):
name = serializers.CharField(max_length=20)
created = serializers.DateField()
def update(self, instance, validated_data):
# instance 要更新的数据,validated_data 是新数据
instance.name = validated_data.get('name', instance.name)
instance.type = validated_data.get('create', instance.type)
instance.save()
return instance
class CourseUpdate(APIView):
def put(self, request):
id_ = request.data.get("id") # 获取当前更新数据的 ID
try:
course = Course.objects.get(pk=id_)
except Course.DoesNotExist:
return Response({'msg': '更新失败,不存在这条数据'})
ser = CourseSer(instance=course, data=request.data)
if ser.is_valid():
ser.save()
error = ser.errors
return Response({'msg': error if error else 'success'})
from rest_framework.serializers import ModelSerializer
class Goods(models.Model):
title = models.CharField(max_length=200, verbose_name='商品标题')
description = models.TextField(verbose_name='描述')
inventory = models.IntegerField(default=0, verbose_name='库存量')
price = models.DecimalField(
max_digits=10, decimal_places=2, verbose_name='商品价格')
cover = models.CharField(max_length=200, verbose_name='封面图')
issale = models.BooleanField(default=False, verbose_name='是否促销')
saleprice = models.DecimalField(
max_digits=10, decimal_places=2, verbose_name='促销价格')
ishow = models.BooleanField(default=True,verbose_name='是否上架')
createtime = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
def __str__(self):
return self.title
class Meta:
db_table = 'goods'
class GoodsSer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = '__all__' # 指明所有模型类字段
# exclude = ('createtime',) # 排除掉的字段
# read_only_fields = ('title','description') # 只用于序列化的字段
# fields = ('title','description','inventory') # 手动指明字段
# extra_kwargs = {
# 'price':{'min_value':0, 'required':True},
# } # 修改原有字段的选项参数
class GoodsCreate(APIView):
def post(self, request):
ser = GoodsSer(data=request.data)
if ser.is_valid():
ser.save()
error = ser.errors
return Response({'msg': error if error else 'success'})
class GoodsUpdate(APIView):
def put(self, request):
id_ = request.data.get("id")
try:
goods = Goods.objects.get(pk=id_)
except Goods.DoesNotExist:
return Response({'msg': '更新失败,不存在这条数据'})
ser = GoodsSer(instance=goods, data=request.data)
if ser.is_valid():
ser.save()
error = ser.errors
return Response({'msg': error if error else 'success'})
class Teacher(models.Model):
name = models.CharField(max_length=30, verbose_name='老师名')
age = models.IntegerField(verbose_name='年纪')
def __str__(self):
return self.name
class Student(models.Model):
name = models.CharField(max_length=30, verbose_name='学生名')
teacher = models.ForeignKey(
Teacher, on_delete=models.SET_NULL,
null=True, blank=True,
verbose_name='关联老师'
)
def __str__(self):
return self.name
class StudentSer(serializers.ModelSerializer):
teacher = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Student
fields = '__all__'
class StudentDetail(APIView):
def get(self, request):
id_ = request.query_params.get('id')
# 通过 GET 传参获取当前学生 ID
try:
stu = Student.objects.get(pk=id_)
except Student.DoesNotExist:
return Response({'error': '查不到结果'})
ser = StudentSer(instance=stu)
return Response(ser.data, status=200)
{
"id": 1,
"teacher": 1,
"name": "小红"
}
class StudentSer(serializers.ModelSerializer):
teacher = serializers.StringRelatedField()
class Meta:
model = Student
fields = '__all__'
{
"id": 1,
"teacher": "张老师", # teacher 表的__str__方法所返回的
"name": "小红"
}
class StudentSer(serializers.ModelSerializer):
teacher = serializers.SlugRelatedField(read_only=True, slug_field='name')
class Meta:
model = Student
fields = '__all__'
{
"id": 1,
"teacher": 20,
"name": "小红"
}
class TeacherSer(serializers.ModelSerializer):
class Meta:
model = Teacher
fields = '__all__'
class StudentSer(serializers.ModelSerializer):
teacher = TeacherSer(read_only=True)
class Meta:
model = Student
fields = '__all__'
{
"id": 1,
"teacher": {
"id": 1,
"name": "张老师",
"age": 20
},
"name": "小红"
}