Last active
February 4, 2023 22:12
-
-
Save webjunkie/4ed9c3d132a58a51d857543eb24faaee to your computer and use it in GitHub Desktop.
JSONFieldFormMixin for Django ModelForm with JSON field
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# the mixin | |
class JSONFieldFormMixin(object): | |
""" | |
Given that a model has some kind of TextField ``json_storage_field`` with | |
a string of JSON formatted data inside, this mixin adds handling of this | |
field to a ModelForm. | |
It will read the text field, convert to Python dict, fill the form fields | |
that are given via ``json_fields`` and on saving will write this back to | |
the JSON field, updating just the fields that are included in the ModelForm. | |
Attributes: | |
json_storage_field: which field of the model holds the JSON data, should only be text | |
Attributes on form.Meta: | |
json_fields: the fields to read and save, need to be model fields defined on ModelForm | |
""" | |
json_storage_field = "meta" | |
def get_from_json_field(self): | |
return json.loads(getattr(self.instance, self.json_storage_field) or "{}") | |
def __init__(self, *args, **kwargs): | |
super(JSONFieldFormMixin, self).__init__(*args, **kwargs) | |
if self.instance: | |
meta_json = self.get_from_json_field() | |
for field in self.Meta.json_fields: | |
if meta_json.get(field): | |
self.fields[field].initial = meta_json.get(field) | |
def save(self, *args, **kwargs): | |
meta_json = self.get_from_json_field() | |
for field in self.Meta.json_fields: | |
meta_json[field] = self.cleaned_data[field] | |
setattr(self.instance, self.json_storage_field, json.dumps(meta_json)) | |
return super(JSONFieldFormMixin, self).save(*args, **kwargs) | |
# example model | |
class Solution(models.Model): | |
name = models.CharField(max_length=255) | |
description = models.TextField(blank=True) | |
url = models.URLField("URL", blank=True) | |
meta = models.TextField(blank=True) | |
# example ModelForm | |
class SolutionForm(JSONFieldFormMixin, ModelForm): | |
currency = forms.CharField(required=False) | |
info = forms.CharField(required=False) | |
class Meta: | |
model = Solution | |
json_fields = ('currency', 'info') | |
fields = ('name', 'description', 'url') + json_fields |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment