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,第二次则是由函数发起,会带上。

posted on 2025-08-22 21:17  hole_cheng  阅读(3)  评论(0)    收藏  举报