Django CBV-在创建对象后,如何在CreateView中保存到FileField?

时间:2019-02-20 02:22:35

标签: django django-forms django-views

我有一个具有FileField的Django模型,并且在创建 new 对象时,我想使用对象的Id来命名FileField。

这里是模型(为简洁起见,删除了一些字段)。值得注意的是,FileField使用对象的ID作为名称来重命名文件,以避免冲突。

class Product(models.Model):
    name = models.CharField(max_length=255, db_index=True)
    ...

    storage_path = 'foo/'
    image = models.FileField(default="foo/default.png", upload_to=upload_path, blank=True, null=True)


def upload_path(instance, filename):
    """ We don't care what filename the user gave us, use the ID. """
    _, ext = os.path.splitext(filename)
    if hasattr(ext, 'lower'):
        ext = ext.lower()
    path = getattr(instance, 'storage_path', 'UNCATEGORIZED')
    return "{}/{}{}".format(path, instance.id, ext)

但是,在使用CreateView时,我不能简单地包含image字段,因为当保存表单(并且正在上传文件)时,还没有创建对象,因此ID为None。因此,我每次都会节省None.png

我有一个可行的解决方案,但这似乎不是很优雅。

class ProductCreate(CreateView):
    model = Product
    fields = ['name', 'image']

    def dispatch(self, request, *args, **kwargs):
        # We need to save the image after the object is saved because we                                                                                                                                                           
        # use the ID in the image filename                                                                                                                                                                                                        
        self.image_file = request.FILES.pop('image', None)
        if isinstance(self.image_file, list) and len(self.image_file) > 0:
            self.image_file = self.image_file[0]
        return super().dispatch(request, *args, **kwargs)

    def form_valid(self, form):
        ret = super().form_valid(form)

        if self.image_file:
            self.object.image.save(self.image_file.name, self.image_file)

        return ret

因此,基本上,我是在form_valid(或链中较早的内容)可以处理文件之前对其进行拦截,然后稍后再使用该InMemoryUploadedFile实例。它工作正常,但我担心它会在将来崩溃,并且还有更好的方法。

我敢肯定有更好的解决方案。也许只是不使用文件名中的ID?我当然可以使用UUID,但是我喜欢使用ID命名文件。

0 个答案:

没有答案