使用场景
就拿路飞学城的案例来说:学城里面有很多课程,课程信息存在一个表当中,课程表其中一个外键是教师,教师存在另外一个表当中。那么,我们有两个表。在django中查询课程信息的时候,我们希望老师的一些信息也被展示出来。请求API的时候,返回的结果如下图:
如果只是用一个课程序列化器,我们是完成不了这个工作的。因此,我们还得实现一个教师序列化器,将教师序列化器嵌套在课程序列化器中,就能完成该任务。
- 那么,什么是外键呢?
外键将子表和父表建立关联。引入外键后,外键只能插入参照列表存在的值,参照列被参照的(即父表中被唯一约束的字段)值不能删除,保证了数据的完整性。上面的例子中,教师作为课程的外键,那么在课程表中,教师属性存储的就是教师表的主键。要保证上面说的数据完整性,被参照的教师信息就不能被删除。
嵌套方法
可以看到,除了课程序列化器之外,还实现了一个老师序列化器。然后课程序列化器中引入了教师序列化器,在Meta.fields中也声明了teacher属性。通过这种方式,请求API返回的记过就如上图所示了。
from .models import Teacher
class TeacherModelSerializer(serializers.ModelSerializer):
"""
老师序列化器
"""
class Meta:
model = Teacher
fields = ['id', 'title', 'name', 'signature']
from .models import Course
class CourseModelSerializer(serializers.ModelSerializer):
"""
课程信息序列化器
"""
#序列化器嵌套,返回外键对应的序列化器值,必须是外键
teacher = TeacherModelSerializer()
class Meta:
model = Course
fields = ["id","name","students","lessons","pub_lessons","price","course_img","teacher"]
替代方法
模型嵌套存在一个问题,他对查询数量的控制不太方便,所以还可以通过在模型中通过增加自定义字段来替代序列化器的嵌套。具体做法是:
- 在模型中增加一个方法,使用@property装饰器来进行修饰,使得该方法变成一个属性
- 使用Model.objects.filter().all()来获取查询结果对象
- 将查询结果对象转化成字典,返回
例子:我们要在查询课程的过程中,将课程的课时页展示出来,我们只需要在课程的模型中写入下面的代码(Tips:一般情况下,课程、课程章节、课程课时这三种信息会存在不同的表当值)
def lesson_list(self):
"""展示课程列表页中推荐的4个课时信息"""
data_list = []
lesson_list = CourseLesson.objects.filter(is_show=True, is_delete=False, course_id=self.id, is_show_list=True).all()
for lesson in lesson_list:
data_list.append({
"id" : lesson.id,
"name" : lesson.name,
"free_trail" : lesson.free_trail,
})
return data_list
- python的@property装饰器是什么?
我们可以使用@property装饰器来创建只读属性,@property装饰器会将方法转换为相同名称的只读属性,可以与所定义的属性配合使用,这样可以防止属性被修改。