ModelSerializer

参考: https://www.django-rest-framework.org/api-guide/serializers/#modelserializer

ModelSerializer是Serializer的子类除了具有Serializer的功能外:

  • 根据Model类,自动生成字段
  • 为序列化器自动生成校验器
  • 为序列化器提供了简单的create()和update()方法实现,所以可以直接save()
    • 注意虽然感觉上序列化器sava(create、update),但是真正操作数据库是通过Model类

image

序列化器

需要解决2个问题

  • 依照哪个Model类
  • 需要哪些字段
from rest_framework import serizlizers
from .models import Employee
class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees  #参照谁,谁save
        fields = "__all__"  #有哪些字段

#输出
EmployeeSerizlizer():
    emp_no = IntegerField(max_value=2147483647, min_value=-2147483648, validators=[<UniqueValidator(queryset=Employees.objects.all())>])
    birth_date = DateField()
    first_name = CharField(max_length=14)
    last_name = CharField(max_length=16)
    gender = ChoiceField(choices=[(1, '男'), (2, '女')], validators=[<django.core.validators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
    hire_date = DateField()

指定字段

class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees
        fields = ['birth_date','last_name','gender','hire_date']  #指定字段

排除字段

class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees
        fields = ['birth_date','last_name','gender','hire_date']

单独指定readonly字段

class EmpSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = '__all__'
        read_only_fields = ['hire_date'] # 单独指定readonly字段
class EmpSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = '__all__'
        read_only_fields = ['hire_date'] # 单独指定readonly字段
        extra_kwargs = {'gender': {'write_only': True}} 
        # 额外字段选项定义,gender为write_only

序列化

class EmpSerializer(serializers.ModelSerializer):
    class Meta:
        model = Employee
        fields = '__all__'
import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False)
# 所有测试代码,都要在上面4行之下
from employee.models import Employee
from employee.serializers import EmpSerializer
emgr = Employee.objects
emp = emgr.get(pk=10010)
serializer = EmpSerializer(emp)
print(serializer.data)
#输出
{'emp_no': 10010, 'birth_date': '1963-06-01', 'first_name': 'Duangkaew', 
'last_name': 'Piveteau', 'gender': 2, 'hire_date': '1989-08-24'}
emgr = Employee.objects
emps = emgr.filter(pk__gt=10018)
serializer = EmpSerializer(emps, many=True) # 多个
print(serializer.data)

#输出
[OrderedDict([('emp_no', 10019), ('birth_date', '1953-01-23'), ('first_name', 
'Lillian'), ('last_name', 'Haddadi'), ('gender', 1), ('hire_date', '1999-04-
30')]), OrderedDict([('emp_no', 10020), ('birth_date', '1952-12-24'), 
('first_name', 'Mayuko'), ('last_name', 'Warwick'), ('gender', 1), 
('hire_date', '1991-01-26')]), OrderedDict([('emp_no', 10021), ('birth_date', 
'1963-06-01'), ('first_name', 'si'), ('last_name', 'li'), ('gender', 1), 
('hire_date', '1989-08-24')])]

反序列化

ModelSerializer提供了create、update方法。

import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=False)
# 所有测试代码,都要在上面4行之下
from employee.models import Employee
from employee.serializers import EmpSerializer
data = {
    'emp_no': 10022, 'birth_date': '1963-06-01',
    'first_name': 'wu', 'last_name': 'wang',
    'gender': 1, 'hire_date': '1989-08-24',
} # 注意,这是字典数据是data,不是Employee的实例
# 只有data,是新增
serializer = EmpSerializer(data=data)
serializer.is_valid(True)
x = serializer.save() # 返回持久化的实例
print(type(x), x)
emgr = Employee.objects
emp = emgr.get(pk=10022) # 查实例
data = {
    'emp_no': 10022, 'birth_date': '1963-06-01',
    'first_name': '三', 'last_name': '张',
    'gender': 1, 'hire_date': '1989-08-24',
} # 注意,这是字典数据是data,不是Employee的实例
# 有实例,有data,是更新
serializer = EmpSerializer(emp, data=data)
serializer.is_valid(True)
x = serializer.save() # 更新
print(type(x), x) # 返回实例

外键关系

员工和工资,是一对多关系

Model类
from django.db import models
class Employees(models.Model):
    class Gender(models.IntegerChoices):
        MAN = 1,"男"
        WOMEN = 2,"女"
    class Meta:
        db_table = "employees"
    emp_no = models.IntegerField(primary_key=True)
    birth_date = models.DateField()
    first_name = models.CharField(max_length=14)
    last_name = models.CharField(max_length=16)
    gender = models.SmallIntegerField(choices=Gender.choices)
    hire_date = models.DateField()

    @property
    def name(self):
        return "<{}{}>".format(self.first_name,self.last_name)

    def __str__(self):
        return "{},{},{}".format(self.emp_no,self.first_name,self.last_name)
    __repr__ = __str__

class Salarise(models.Model):
    class Meta:
        db_table = "salaries"
    emp_no = models.ForeignKey(Employees,on_delete=models.CASCADE,db_column='emp_no',
                               related_name='salaries')
    salary = models.IntegerField()
    from_date = models.DateField()
    to_date = models.DateField()
序列化器
from rest_framework import serializers
from .models import Employees,Salarise


class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees
        fields = '__all__'
        # exclude = ['gender']
        # fields = ['birth_date','last_name','gender','hire_date']

class SalariesSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Salarise
        fields = '__all__'
print(EmployeeSerizlizer())
print(SalariesSerizlizer())

序列化器如下:

EmployeeSerizlizer():
    emp_no = IntegerField(max_value=2147483647, min_value=-2147483648, validators=[<UniqueValidator(queryset=Employees.objects.all())>])
    birth_date = DateField()
    first_name = CharField(max_length=14)
    last_name = CharField(max_length=16)
    gender = ChoiceField(choices=[(1, '男'), (2, '女')], validators=[<django.core.validators.MinValueValidator object>, <django.core.validators.MaxValueValidator object>])
    hire_date = DateField()
SalariesSerizlizer():
    id = IntegerField(label='ID', read_only=True)
    salary = IntegerField(max_value=2147483647, min_value=-2147483648)
    from_date = DateField()
    to_date = DateField()
    emp_no = PrimaryKeyRelatedField(queryset=Employees.objects.all())

SalariesSerizlizer

  • id是read_only,因为自增字段,入库时不用手动指定id
  • emp_no是主键关联
序列化

####### 1、各自独立查询
先查员工,再去查相关工资信息

import os
import django
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'salary.settings')
django.setup(set_prefix=Falshas)
# 所有测试代码,都要在上面4行之下
from employee.models import Employee
from employee.serializers import EmpSerializer, SalarySerializer
emgr = Employee.objects
emp = emgr.get(pk=10003)
print(emp)
print(emp.salaries.all())
print(EmpSerializer(emp).data)
print(SalarySerializer(emp.salaries.all(), many=True).data)

####### 2、关联主键
参考 https://www.django-rest-framework.org/api-guide/relations/#primarykeyrelatedfield

在Employee模型类中并没有显式的定义域Salary模型类关联的字段,但是Salary模型类中的ForeignKey会提供给Employee一个字段,这个字段可以用,但是需要在序列化器中显式定义。

获取所有关联pk,利用serializers.PrimaryKeyRelatedField来关联。

image

from rest_framework import serializers
from .models import Employees,Salarise


class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees
        fields = '__all__'
        # exclude = ['gender']
        # fields = ['birth_date','last_name','gender','hire_date']
    salaries = serializers.PrimaryKeyRelatedField(many=True,read_only=True)


class SalariesSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Salarise
        fields = '__all__'
print(EmployeeSerizlizer())
print(SalariesSerizlizer())
  • read_only=True 表示salaries字段仅用于读取,也就是仅用于序列化的时候
  • many=True ,因为一个员工可以有多条工资记录
from employee.models import Employee
from employee.serializers import EmpSerializer, SalarySerializer
emgr = Employee.objects
emp = emgr.get(pk=10003)
print(EmpSerializer(emp).data)
#输出  ,salaries对应的是主键id
{'emp_no': 10003, 'salaries': [24, 25, 26, 27, 28, 29, 30], 'birth_date': '1959-12-03', 'first_name': 'Parto', 'last_name': 'Bamford', 'gender': 1, 'hire_date': '1986-08-28'}
3、关联字符串表达

参考https://www.django-rest-framework.org/api-guide/relations/#stringrelatedfield

image

直接获取所有关联对象的字符串表达,需要在model类中实现str模式方法,用到__str__。注意,StringRelateField内部read_only写死为True

from rest_framework import serializers
from .models import Employees,Salarise


class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees
        fields = '__all__'
        # exclude = ['gender']
        # fields = ['birth_date','last_name','gender','hire_date']
    # salaries = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
    salaries = serializers.StringRelatedField(many=True)


class SalariesSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Salarise
        fields = '__all__'
print(EmployeeSerizlizer())
print(SalariesSerizlizer())
from employee.models import Employee
from employee.serializers import EmpSerializer, SalarySerializer
emgr = Employee.objects
emp = emgr.get(pk=10003)
print(EmpSerializer(emp).data) # 使用的是Salary模型类的__str__
{'emp_no': 10003, 'salaries': ['40006 10003,Parto,Bamford 1995-12-03', '43616 10003,Parto,Bamford 1996-12-02', '43466 10003,Parto,Bamford 1997-12-02', '43636 10003,Parto,Bamford 1998-12-02', '43478 10003,Parto,Bamford 1999-12-02', '43699 10003,Parto,Bamford 2000-12-01', '43311 10003,Parto,Bamford 2001-12-01'], 'birth_date': '1959-12-03', 'first_name': 'Parto', 'last_name': 'Bamford', 'gender': 1, 'hire_date': '1986-08-28'}

####### 4、关联对象
参考https://www.django-rest-framework.org/api-guide/relations/#nested-relationships

如果需要更加完整的关联数据,可以使用关联对象的方式,要利用对方的序列化器

from rest_framework import serializers
from .models import Employees,Salarise

class SalariesSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Salarise
        fields = '__all__'
class EmployeeSerizlizer(serializers.ModelSerializer):
    class Meta:
        model = Employees
        fields = '__all__'
        # exclude = ['gender']
        # fields = ['birth_date','last_name','gender','hire_date']
    # salaries = serializers.PrimaryKeyRelatedField(many=True,read_only=True)
    # salaries = serializers.StringRelatedField(many=True)
    salaries = SalariesSerizlizer(many=True,read_only=True)



print(EmployeeSerizlizer())
print(SalariesSerizlizer())
from employee.models import Employee
from employee.serializers import EmpSerializer, SalarySerializer
emgr = Employee.objects
emp = emgr.get(pk=10003)
import json
print(json.dumps(EmpSerializer(emp).data))

返回的数据序列化成Json格式如下:

{"emp_no": 10003, "salaries": [{"id": 24, "salary": 40006, "from_date": "1995-12-03", "to_date": "1996-12-02", "emp_no": 10003}, {"id": 25, "salary": 43616, "from_date": "1996-12-02", "to_date": "1997-12-02", "emp_no": 10003}, {"id": 26, "salary": 43466, "from_date": "1997-12-02", "to_date": "1998-12-02", "emp_no": 10003}, {"id": 27, "salary": 43636, "from_date": "1998-12-02", "to_date": "1999-12-02", "emp_no": 10003}, {"id": 28, "salary": 43478, "from_date": "1999-12-02", "to_date": "2000-12-01", "emp_no": 10003}, {"id": 29, "salary": 43699, "from_date": "2000-12-01", "to_date": "2001-12-01", "emp_no": 10003}, {"id": 30, "salary": 43311, "from_date": "2001-12-01", "to_date": "9999-01-01", "emp_no": 10003}], "birth_date": "1959-12-03", "first_name": "Parto", "last_name": "Bamford", "gender": 1, "hire_date": "1986-08-28"}