如何通过Serializer从SimpleJWT自动填充SQLAlchemy模型的owner_id?
解决方法
方案一:在视图中手动注入owner_id
直接在视图的create方法里将当前用户ID添加到序列化器输入数据中,逻辑简单直接:
def create(self, request): # 复制请求数据,避免修改原始对象 request_data = request.data.copy() # 注入当前用户ID到owner_id字段 request_data['owner_id'] = request.user.id serializer = PlaceInfoSerializer(data=request_data) if serializer.is_valid(): Session = sessionmaker(bind=engine) session = Session() place = PlaceInfoModel(**serializer.validated_data) session.add(place) session.commit() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
同时建议把序列化器里的owner_id设为只读,防止前端传入字段覆盖自动填充的值:
class PlaceInfoSerializer(serializers.Serializer): name = serializers.CharField() address = serializers.CharField() rating = serializers.FloatField() image = serializers.CharField(required=False) owner_id = serializers.IntegerField(read_only=True) # 设置为只读
方案二:通过序列化器上下文传递用户并自动填充
如果希望逻辑封装在序列化器中,可以将请求对象传入序列化器上下文,再在序列化器内处理owner_id填充:
- 修改视图,创建序列化器时传入上下文:
def create(self, request): # 将request传入序列化器上下文 serializer = PlaceInfoSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): Session = sessionmaker(bind=engine) session = Session() place = PlaceInfoModel(**serializer.validated_data) session.add(place) session.commit() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
- 修改序列化器,用
validate方法填充owner_id:
class PlaceInfoSerializer(serializers.Serializer): name = serializers.CharField() address = serializers.CharField() rating = serializers.FloatField() image = serializers.CharField(required=False) owner_id = serializers.IntegerField(required=False) # 设为非必填 def validate(self, attrs): # 从上下文获取当前用户ID并填充 user = self.context['request'].user attrs['owner_id'] = user.id return attrs
或者重写序列化器的create方法,把SQLAlchemy的入库逻辑也移到序列化器中:
class PlaceInfoSerializer(serializers.Serializer): name = serializers.CharField() address = serializers.CharField() rating = serializers.FloatField() image = serializers.CharField(required=False) owner_id = serializers.IntegerField(read_only=True) def create(self, validated_data): # 从上下文获取用户ID并添加到数据中 user = self.context['request'].user validated_data['owner_id'] = user.id Session = sessionmaker(bind=engine) session = Session() place = PlaceInfoModel(**validated_data) session.add(place) session.commit() return place
这种情况下视图的create方法可以简化为:
def create(self, request): serializer = PlaceInfoSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): serializer.save() return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
关于CurrentUserDefault()失败的原因
CurrentUserDefault()需要序列化器上下文包含request对象,且通常要和HiddenField配合。如果想用这个方法,需要做以下修改:
from rest_framework.fields import CurrentUserDefault class PlaceInfoSerializer(serializers.Serializer): # ...其他字段 owner_id = serializers.HiddenField( default=serializers.CreateOnlyDefault( lambda obj: obj['request'].user.id ) )
同时必须在创建序列化器时传入context={'request': request},否则无法获取用户。不过这种方式在SQLAlchemy场景下不如前面的方案直接。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

