让我们通过例子来理解它。
说,我想创建FileUploader API,它将在数据库中存储id,file_path,file_name,size,owner等字段。请参阅以下示例模型:
class FileUploader(models.Model):
file = models.FileField()
name = models.CharField(max_length=100) #name is filename without extension
version = models.IntegerField(default=0)
upload_date = models.DateTimeField(auto_now=True, db_index=True)
owner = models.ForeignKey('auth.User', related_name='uploaded_files')
size = models.IntegerField(default=0)
现在,对于API,这就是我想要的:
GET: 当我触发GET端点时,我希望每个上传文件的所有上述字段。
POST: 但是对于用户创建/上传文件,她为什么要担心传递所有这些字段。她可以上传文件然后,我想,序列化程序可以从上传的文件中获取其余字段。
Searilizer: 问题:我创建了以下序列化程序以满足我的目的。但不确定它是否是实施它的正确方法。
class FileUploaderSerializer(serializers.ModelSerializer):
#overwrite = serializers.BooleanField()
class Meta:
model = FileUploader
fields = ('file','name','version','upload_date', 'size')
read_only_fields = ('name','version','owner','upload_date', 'size')
def create(self, validated_data):
return FileUploader.objects.create(**validated_data)
视图集供参考:
class FileUploaderViewSet(viewsets.ModelViewSet):
serializer_class = FileUploaderSerializer
parser_classes = (MultiPartParser, FormParser,)
# overriding default query set
queryset = LayerFile.objects.all()
def get_queryset(self, *args, **kwargs):
qs = super(FileUploaderViewSet, self).get_queryset(*args, **kwargs)
qs = qs.filter(owner=self.request.user)
return qs
另外,另一个问题是我希望用户提供名为'overwrite'的额外参数(如果服务器上已存在文件)。
我不知道如何在序列化程序中访问它。
答案 0 :(得分:4)
@AaronLelevier - 我按照你的建议调查了其他stackoverflow解决方案。但最终决定实施我自己的清洁解决方案。
我更喜欢以下解决方案:
我认为这是最干净的方法。
示例代码:(修改后的serializer.py,views.py保持不变)
class LayerFileSerializer(serializers.ModelSerializer):
class Meta:
model = LayerFile
fields = ('id', 'file','name','version','upload_date', 'size', 'maps')
read_only_fields = ('name','version','owner','upload_date', 'size', 'maps')
def validate(self, validated_data):
if self.context['request'].method == 'PATCH':
# catch here: validated_data only contains filed that are valid for serializer
# for post/update/patch method only valid field is the file
# but we need 'name' field as well so trick is to get name from the self.context[request].data
validated_data['name'] = self.context['request'].data.get('name', None)
if validated_data['name'] is None or validated_data['name'] == '':
raise serializers.ValidationError("'name' field cannot be empty!")
return validated_data
validated_data['owner'] = self.context['request'].user
validated_data['name'] = os.path.splitext(validated_data['file'].name)[0]
validated_data['size'] = validated_data['file'].size
#print self.context['request'].overwrite
log.debug("serialized layer data: %s" %validated_data)
try:
layer_obj = LayerFile.objects.get(owner=validated_data['owner'], name=validated_data['name'])
except LayerFile.DoesNotExist:
layer_obj = None
if layer_obj:
raise serializers.ValidationError('Layer with same name already exist. Use overwrite flag to overwrite it.')
return validated_data
# This will handle rename
def partial_update(self, instance, validated_data):
instance.name = validated_data['name']
return instance
# this will handle POST - or layer upload
def create(self, validated_data):
return LayerFile.objects.create(**validated_data)