I've been struggling with this issue all day and hope someone can help. I have all my hierarchies classified by category in the same table. during the form creation, I want to separate each hierarchy by category and render it using a ModelMutipleChoiceField his way not all hierarchies are displayed together.
The problem comes when the form is submitted, as I need to go through each ModelMutipleChoiceField field and get the selected values and copy these to the model field before saving the form. however, I am not able to iterate through the ModelMutipleChoiceField and get the selected values. I also don't know how to set these values on the ModelField
NOTE: The number of hierarchies can vary.
here is my code:
I'm using Django MPTT and create my hierarchy structure using 2 models. one is the category(Hierarchy) and the other is the nodes of the hierarchy (HierarchyNode_MPTT).
Then I created a separate model that has ManyToManyField pointing to the HierarchyNode_MPTT.
Models.py
class Hierarchy(models.Model):
ID = kp.ObjectIDField()
name = kp.ObjectNameField()
ext_hierarchy = kp.ObjectTechnicalID()
seq_no = kp.SeqNoField(unique=True)
mptt_seq_no = models.PositiveIntegerField()
class HierarchyNode_MPTT(MPTTModel):
id = kp.ObjectIDField()
name = kp.ObjectNameField()
description = kp.ObjectDescriptionField()
ext_node_id = kp.ObjectShortNameField()
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True, related_name='children')
hierarchy = models.ForeignKey(Hierarchy, on_delete=models.CASCADE, null=True, blank=True, related_name='children')
class Configuration(models.Model):
uuid = kp.ObjectIDField()
name = kp.ObjectNameField()
description = kp.ObjectDescriptionField()
hierarchy_nodes = models.ManyToManyField(HierarchyNode_MPTT)
Then I created the form and implement the init method to automatically create as many hierarchies as I need.
form.py
class ConfigurationCreateForm(forms.ModelForm):
class Meta:
model = ForecastConfiguration
exclude = ['uuid', 'hierarchy_nodes']
def __init__(self, user, *args, **kwargs):
super().__init__(*args, **kwargs)
hierarchies = Hierarchy.objects.all()
for hierarchy in hierarchies:
field_name = 'hierarchy_%s' % (hierarchy.mptt_seq_no,)
self.fields[field_name] = TreeNodeMultipleChoiceField(queryset=HierarchyNode_MPTT.objects.all().filter(hierarchy=hierarchy),label=hierarchy.name, required=True)
try:
self.initial[field_name] = HierarchyNode_MPTT.objects.root_node(tree_id=hierarchy.mptt_seq_no)
except IndexError:
self.initial[field_name] = ''
def copy_hierarchies(self, *args, **kwargs):
hierarchies = Hierarchy.objects.all()
choice_list = list()
for hierarchy in hierarchies:
field_name = 'hierarchy_%s' % (hierarchy.mptt_seq_no,)
selected_values = self.cleaned_data.get(field_name)
for selection in selected_values:
choice_list.append(selection)
self.initial['hierarchy_nodes'] = choice_list
Finally, the idea was to implement the post method on the View to loop over the created hierarchies and then assign the value to the model field called 'hierarchy_nodes'
view.py
class ConfigurationCreateView(CreateView):
model = Configuration
form_class = ConfigurationCreateForm
template_name = 'frontend/base/config_create.html'
def get(self, request, *args, **kwargs):
form = ConfigurationCreateForm(user=request.user)
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
form.copy_hierarchies(*args, **kwargs)
if form.is_valid():
fcc_form = form.save(commit=True)
messages.add_message(self.request, messages.INFO, 'Your Forecast Configurations has been saved')
return redirect(reverse('planning_detail', kwargs={'uuid': self.fcc_form.uuid}))
else:
messages.add_message(self.request, messages.ERROR, 'Error when creating the Forecast Configuration')
return render(request, self.template_name, {'form': form})
As you can see I created a method in my form called copy_hierarchies which is where I was planning to copy the hierarchy values, this is the method where I'm having problems.
if there is an easier way to perform this using Javascript, I'm open to these options.
Thanks in advance.