Reputation: 65
I have searched for a couple days to try to find a DRY way to create dynamic forms from a JsonField using django's built in validation and form rendering. I have yet to find a solution that will incorporate django's validation and rendering so I would like to create a module for this but I am having a hard time figuring out how the classes work.
I have tried a couple different things such as the following:
from django.contrib.postgres.fields import JSONField
from django.db import models
class Forklift(models.Model):
name = models.CharField(max_length=50)
json_fields = JSONField()
from django import forms
from .models import Forklift
fields_dict = {
'name': forms.CharField(max_length=25),
'number': forms.IntegerField()
}
class ModelForm(forms.ModelForm):
class Meta:
model = Forklift
exclude = ['json_fields']
class DynamicForm(forms.Form):
pass
This is the error I get:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
It looks like forms.Form
subclasses forms.BaseForm
and forms.DeclaritaveFieldsMetaclass
but I can'f figure out how to subclass forms.Form to pass in dynamic fields from a dictionary. I have also tried the following:
from django import forms
from django.shortcuts import render
from .forms import fields_dict
def dynamic_form(request): #__init_subclass__() takes no keyword arguments
class NewForm(forms.BaseForm, fields=fields_dict): # also tried with fields=fields_dict
pass
form = NewForm(request.POST or None)
return render(request, 'template.html', {'form': form})
def dynamic_form(request): # form will only render once then disappear
content = {}
context = {}
dynamic_form = type('dynamic_form', (DynamicForm,), fields_dict)
form = dynamic_form(content)
context = {
'form': form,
}
return render(request, 'activity/dynamic_form.html', context)
def dynamic_form(request): # module 'django.forms' has no attribute 'DeclaritaveFieldsMetaclass'
class NewForm(forms.BaseForm, metaclass=DeclarativeFieldsMetaclass(MediaDefiningClass), data=fields_dict):
pass
form = NewForm(request.POST or None)
return render(request, 'template.html', {'form': form})
I am not just asking f an answer, what I would really like to know is how someone walks through all these classes to figure out how to subclass them. I think I can figure out how to make this work by coding all the logic, validation etc myself but I would like this to be a module that other people can use.
from django.urls import path
from .views import dynamic_form, test
urlpatterns = [
path('form/', dynamic_form),
]
I originally typed the code from memory and had some typos. I Copied the code from my codebase and included urls.py.
Upvotes: 5
Views: 2896
Reputation: 1695
Have a look at this third party package django-entangled, then rewrite your form as
from entangled.forms import EntangledModelForm
class DynamicForm(EntangledModelForm):
name = forms.CharField(max_length=25)
number = forms.IntegerField()
class Meta:
model = Forklift
entangled_fields = {'json_fields': ['name', 'number']}
Then render the form as you usually would, when using a standard Django form.
Upvotes: 1