首页 > 解决方案 > Django中带有ImageField的动态JsonForm

问题描述

我正在 Django 中创建一个动态表单(使用 JSON 格式),该表单需要使用 Django Storage 保存多个图像,并将对文件的引用保存在 JSON 字段中。

这就是我现在所拥有的,它可以工作但真的很难看,Django 已经这样做了,我不知道如何重用相同的功能。

Class SomeModel(models.ModelForm):
    results = JSONField()

class DynamicJsonForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # ... Add dynamic fields to the form
        self.extra = []  # Save the reference for the fields

    class Meta:
        model = SomeModel
        exclude = ("results",)

    def save(self, commit=True):
        results = {}
        for extra in self.extra:
            value = self.cleaned_data.get(extra)
            question = some_query.question
            if "photo" in extra and value:  # value = photo
                filename, ext = value.name.split(".")
                filename = "media/the/path/to/photos/{}_{}.{}".format(filename, uuid4().hex, ext)
                uploaded_file = SimpleUploadedFile(filename, value.read(), value.content_type)
                image = Image.open(uploaded_file)
                if image.mode in ("RGBA", "P"):
                    image = image.convert("RGB")
                image.save(fp=filename)
                results[question][extra] = filename
            else:
                results[question][extra] = value
        self.instance.results = results
        return super().save(commit)

这实际上有效,它将数据保存到 JSONField(结果)并将图像保存到本地文件系统存储。

如何改进以使用 Django Storage 并使其变得简单?使用 DjangoModel.save()似乎要容易得多,但我不能使用普通的ImageField(),因为它需要是动态的

标签: pythondjangodjango-formsdynamic-formsjsonforms

解决方案


我混合FileSystemStorageforms.ImageField,根本不是一个完美的解决方案,但看起来更好。

字段.py

import os

from django import forms
from django.conf import settings
from django.core.files.storage import FileSystemStorage

class FormFileSystemStorageImageField(forms.ImageField, FileSystemStorage):
    def __init__(self, location=None, *args, **kwargs):
        super().__init__(*args, **kwargs)  # Call ImageField __init__, I wonder how to call second parent's __init__
        self._orig_location = location
        self._location = os.path.join(settings.MEDIA_ROOT, location)

    def storage_path(self, name):
        return os.path.join(self._orig_location, name)

表格.py

from .fields import FormFileSystemStorageImageField


    # ... Same as question code
    def save(self, commit=True):
        results = {}
        for extra in self.extra:
            value = self.cleaned_data.get(extra)
            question = some_query.question
            if "photo" in extra and value:  # value = photo
                image_field = self.fields.get(extra)
                image_field.save(value.name, value)
                results[question][extra] = image_field.storage_path(value.name)
            else:
                results[question][extra] = value
        self.instance.results = results
        return super().save(commit)

推荐阅读