ModelSerializer
ModelSerializer
参考: https://www.django-rest-framework.org/api-guide/serializers/#modelserializer
ModelSerializer是Serializer的子类除了具有Serializer的功能外:
- 根据Model类,自动生成字段
- 为序列化器自动生成校验器
- 为序列化器提供了简单的create()和update()方法实现,所以可以直接save()
- 注意虽然感觉上序列化器sava(create、update),但是真正操作数据库是通过Model类
序列化器
需要解决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
来关联。
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
直接获取所有关联对象的字符串表达,需要在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"}