如何使用DRF修改FileField以在对象ID可用后采用不同的路径?

时间:2017-05-05 22:49:53

标签: python django django-rest-framework

我遇到DRF文件命名问题。感兴趣的文件(我相信)是serializers.py。当我上传文件时,我想要发生的是当对象的id可用时在upload_to目录中创建目录。这很容易覆盖create方法。我还没弄清楚如何更新数据库中的文件以反映新路径。例如,很容易将文件更改为包含所需路径的字符串,但很难将文件更改为具有所需路径的文件。

P.S。我知道我模糊了file关键字。如有必要,我会改变它。

# models.py 
class TestFile(Model):
    file = FileField(storage=FileSystemStorage(location=settings.MEDIA_ROOT), upload_to='files', default='{}/files/empty.zip'.format(settings.MEDIA_ROOT))
    created_at = CreationDateTimeField()
    updated_at = ModificationDateTimeField()
    def __str__(self): 
        return ''.join([str(self.file)])
    def __unicode__(self):
        return unicode(' '.join([str(self.id)]))
    def __id__(self):
        return str(self.id)
    class Meta:
        managed = True
        db_table = 'test_files'
        verbose_name_plural = 'Test Files'

# viewsets.py
class TestFileViewSet(ModelViewSet):
    queryset = TestFile.objects.all()
    serializer_class = TestFileSerializer
    parser_classes = (MultiPartParser, FormParser)
    def perform_create(self, serializer):
        serializer.save(file=self.request.data.get('file')


# serializers.py
class TestFileSerializer(ModelSerializer):
    file = serializers.FileField(required=True)
    def create(self, validated_data):
        # Calling create(), this will create the object in the database, making the ID and PK of obj
        # available to me.
        obj = TestFile.objects.create(**validated_data)
        # Creating a new path so that I can use a detail_route in viewset later to GET file
        new_path = '/'.join ([str(obj.file).split('/')[0],
                              str(obj.id),
                              str(obj.file).split('/')[1]])
        # Try to create the parent directory of our destination. This shouldn't fail
        try:
            os.mkdir(settings.MEDIA_ROOT+ '/files/' +str(obj.id), 0755 )
        except:
            pass
        # Move old file to the new path that we just created.
        shutil.copyfile(settings.MEDIA_ROOT + str(obj.file), settings.MEDIA_ROOT + new_path)
        # Remove the old file after we have already copied it to new destination
        os.rmdir(settings.MEDIA_ROOT + str(obj.file))
        # This is where the next step goes!
        # What do I need to put in here to make obj.file the correct path now?
        return obj    
    class Meta:
        model = TestFile
        fields = ( 'id','file','created_at','updated_at')

1 个答案:

答案 0 :(得分:0)

这是我在models.py中提出的解决问题的方法。我在serializers.py中更改了相关的序列化程序,以使用默认的create()方法。

@python_2_unicode_compatible
class TestFile(models.Model):
    file = models.FileField(storage=FileSystemStorage(location=settings.MEDIA_ROOT),
                            upload_to='files/temporary_storage',
                            blank=True)
    created_at = CreationDateTimeField()
    updated_at = ModificationDateTimeField()

    def save(self, *args, **kwargs):
        super(TestFile, self).save(*args, **kwargs)
    def __str__(self):
        return ' '.join([str(self.file)])
    def __unicode__(self):
        return unicode(' '.join([str(self.id)]))
    def __id__(self):
        return str(self.id)
    class Meta:
        managed = True
        db_table = 'test_file'
        verbose_name_plural = 'Test Files'

@receiver(post_save, sender=TestFile, dispatch_uid="update_filefield")
def update_file(sender, instance, **kwargs):
    filefield = instance.file
    if filefield:
        filename = filefield.name
        new_file_path = ''
    if "temporary_storage" in filename:
        tmp = filename.split("temporary_storage", 1)
        new_file_path = "{}{}{}".format(tmp[0], str(instance.pk), tmp[1])
        if new_file_path != filename:
            instance.file.storage.delete(new_file_path)
            instance.file.storage.save(new_file_path, filefield)
            instance.file.name = new_file_path
            instance.file.close()
            instance.file.storage.delete(filename)
            instance.save()