POST -> 验证model类型 ->is_valid-> validate(当前) -> create -> validate(子序列化器)-> perform_create(serializer)
借用这种模式可以使用一主多辅的方式,通过一个viewset处理多张关联表的增删改查。
比如:
class Brand(BaseModel):
pass
@property
def fonts(self):
"""Return all fonts associated with the brand."""
return self.fontstyle_set.all()
def sync_fonts(self, fonts: list[dict]):
from assets.serializers import FontUploadSerializer
current_fonts = self.fontstyle_set.all()
current_font_keys = {
(font.series.name, font.style_name): font for font in current_fonts
}
new_font_keys = {
(font["family_name"], font["style_name"]): font for font in fonts
}
fonts_to_add = set(new_font_keys.keys()) - set(current_font_keys.keys())
fonts_to_delete = set(current_font_keys.keys()) - set(new_font_keys.keys())
# Add new fonts
for key in fonts_to_add:
font = new_font_keys[key]
font_serializer = FontUploadSerializer(
data=font,
context={
"brand": self,
"user": self.creator,
"workspace": self.workspace,
},
)
font_serializer.is_valid(raise_exception=True)
font_serializer.save()
# Delete fonts that are no longer present
for key in fonts_to_delete:
current_font_keys[key].delete()
# refresh the brand instance to ensure it has the latest fonts
self.refresh_from_db()
for series in self.fontseries_set.all():
if not series.styles.exists():
series.delete()
class FontStyle(BaseModel):
pass
brand = models.ForeignKey( "accounts.Brand", on_delete=models.SET_NULL, null=True, blank=True, )
viewset:class BrandViewSet(viewsets.ModelViewSet):
class BrandSerializer(serializers.ModelSerializer):
queryset = Brand.active_objects.all()
serializer_class = BrandSerializer
fonts = FontUploadSerializer(many=True, required=False)
def update(self, instance: Brand, validated_data):
brand.sync_fonts(fonts)
class FontUploadSerializer(serializers.ModelSerializer):
series_name = serializers.CharField(max_length=255, required=True)
注意:这种用法携带了整张表的数据在处理,并且配置和调试相对复杂,所以尽可能是比较小数据量使用,且本例只为了更理解整个viewset的执行逻辑。
另外,如文章开头所述,在FontUploadSerializer中的验证函数会被执行两次,第一次是由主序列化器发起的关联验证,不会带起context,第二次则是由函数发起,会带上。
浙公网安备 33010602011771号