Since you haven't provided any codes am going to try to make something and then you can refactor the code to suit your needs !
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)
An alternative is creating a fields.py and try this solution:
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)
And forms.py to handle the fields , it's not the perfect solution, it's to give you an idea on how to go about it.
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)