# если пост запрос
RequirementForm4(data=request.POST, all_functions=Function.objects.filter(id__lt=7))
# если гет запрос
RequirementForm4(all_functions=Function.objects.filter(id__lt=7))
# если без разницы какой запрос
RequirementForm4(data=request.POST or None, all_functions=Function.objects.filter(id__lt=7))
class RequirementForm2(forms.Form):
def __init__(self, *args, **kwargs):
self.function_field = 'function_{}'
self.instance = kwargs.pop('instance')
if self.instance.id:
kwargs.update(initial={self.function_field.format(f): True
for f in self.instance.function.values_list('id', flat=True)})
super(RequirementForm2, self).__init__(*args, **kwargs)
self.functions = Function.objects.all().select_related('task', 'task__group')
self.tree = {}
for f in self.functions:
field_name = self.function_field.format(f.id)
self.fields[field_name] = forms.BooleanField(
label=f.name,
widget=forms.CheckboxInput(attrs={'value': f.id}),
required=False,
)
self.tree.setdefault(f.task.group.name, {}).setdefault(
f.task.name, []
).append(BoundField(self, self.fields[field_name], field_name))
def clean(self):
cd = super(RequirementForm2, self).clean()
print '---', cd
return cd
def as_tree(self):
return render_to_string('core/tree_form.html', {'tree': self.tree})
def save(self):
ids = self.get_ids()
ids_current = self.instance.function.values_list('id', flat=True)
self.instance.function.remove(*list(set(ids_current) - set(ids)))
self.instance.function.add(*list(set(ids) - set(ids_current)))
return self.instance
def get_ids(self):
print self.cleaned_data
function_field_clean = self.function_field.format('')
return [key.replace(function_field_clean, '')
for key, value in self.cleaned_data.items()
if key.startswith(function_field_clean) and value]
class RequirementForm4(forms.ModelForm):
class Meta:
model = Program
fields = 'name', 'function'
widgets = {
'function': forms.CheckboxSelectMultiple
}
def __init__(self, *args, **kwargs):
all_functions = kwargs.pop('all_functions', None)
super(RequirementForm4, self).__init__(*args, **kwargs)
if all_functions:
self.fields['function'].queryset = all_functions
self.fields['function'].queryset = self.fields['function'].queryset.select_related(
'task', 'task__group')
def data_tree(self):
tree = {}
for f in self.fields['function'].queryset:
tree.setdefault(
f.task.group.name, {}
).setdefault(
f.task.name, []
).append(f.id)
date_tree_template = "<div class='data-tree' data-tree='{}' data-field='{}'></div>"
return mark_safe(date_tree_template.format(json.dumps(tree), 'function'))
def test_view(request):
form = RequirementForm4(request.POST or None, all_functions=Function.objects.filter(id__lt=7))
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect(reverse('test_view'))
context = {
'form': form,
}
return render(request, 'core/test_view.html', context)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
{{ form.errors }}
{{ form.name }}
<div class="tree">{{ form.function }}</div>
{{ form.data_tree }}
<input type="submit">
</form>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<script>
$(function() {
var tree = $('.data-tree').data('tree')
var field = $('.data-tree').data('field')
render_tree()
function render_tree() {
if(tree != undefined && field != undefined)
$(".tree").replaceWith(make_ul(tree))
}
function make_ul(lst) {
var html = $('<ul>');
for(var name in lst)
html.append(make_li(name, lst[name]))
return html;
}
function make_li(name, elem) {
var html = $('<li>');
if (typeof(elem) == 'object') {
html.text(name).append(make_ul(elem));
}
if (typeof(elem) == 'number'){
html.append($('[name='+field+'][value='+elem+']').parent())
}
return html;
}
});
</script>
</body>
</html>
def __init__(self, *args, **kwargs):
...
self.all_functions = kwargs.pop('all_functions')
super(....
class ProgramForm(forms.ModelForm):
class Meta:
model = Program
fields = 'name',
if self.instance.id:
kwargs.update(initial={self.function_field.format(f): True
for f in self.instance.function.values_list('id', flat=True)})
def test_view(request):
instance = Program()
form_function = ProgramForm(request.POST or None, instance=instance)
form = RequirementForm2(request.POST or None, instance=instance)
if request.method == 'POST':
if form_function.is_valid() and form.is_valid():
form_function.save()
form.save()
return redirect(reverse('test_view'))
...
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
{{ form.to_tree }}
<input type="submit">
</form>
</body>
</html>
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render, redirect
from django.urls import reverse
from core.forms import RequirementForm, RequirementForm2
# RequirementForm без редиректа не очень себя ведет)))
from core.models import Program
def test_view(request):
form = RequirementForm(request.POST or None, instance=Program.objects.first())
if request.method == 'POST':
if form.is_valid():
form.save()
return redirect(reverse('test_view'))
context = {
'form': form,
}
return render(request, 'core/test_view.html', context)
from django import forms
from django.forms import BoundField
from django.template.loader import render_to_string
from core.models import Function
class SplitBoundField(BoundField):
def build_widget_attrs(self, attrs, widget=None):
self.initial = widget.attrs.get('value') if widget.attrs.get('value') in self.initial else None
return super(SplitBoundField, self).build_widget_attrs(attrs, widget)
class RequirementForm(forms.Form):
functions = forms.ModelMultipleChoiceField(
queryset=Function.objects.all().select_related(
'task').select_related(
'task__group').order_by(
'task__group__id', 'task__id'),
widget=forms.CheckboxSelectMultiple
)
def __init__(self, *args, **kwargs):
self.instance = kwargs.pop('instance')
self.functions_ids = list(self.instance.function.values_list('id', flat=True))
kwargs.update(initial={'functions': self.functions_ids})
super(RequirementForm, self).__init__(*args, **kwargs)
def to_tree(self):
queryset = self.fields['functions'].queryset
tree = {}
choices = list(self.fields['functions'].choices)
for i, f in enumerate(queryset):
attrs = {'value': choices[i][0]}
tree.setdefault(f.task.group.name, {}).setdefault(
f.task.name, []
).append(SplitBoundField(
self,
forms.MultipleChoiceField(
label=choices[i][1],
widget=forms.CheckboxInput(attrs=attrs),
required=False,
),
'functions')
)
return render_to_string('core/tree_form.html', context={'tree': tree})
def save(self):
ids = self.cleaned_data['functions'].values_list('id', flat=True)
ids_current = self.functions_ids
self.instance.function.remove(*list(set(ids_current) - set(ids)))
self.instance.function.add(*list(set(ids) - set(ids_current)))
return self.instance
class RequirementForm2(forms.Form):
def __init__(self, *args, **kwargs):
self.function_field = 'function_{}'
self.instance = kwargs.pop('instance')
kwargs.update(initial={self.function_field.format(f): True
for f in self.instance.function.values_list('id', flat=True)})
super(RequirementForm2, self).__init__(*args, **kwargs)
self.functions = Function.objects.all().select_related('task').select_related('task__group')
self.tree = {}
for f in self.functions:
field_name = self.function_field.format(f.id)
self.fields[field_name] = forms.BooleanField(
label=f.name,
widget=forms.CheckboxInput(attrs={'value': 100}),
required=False,
)
self.tree.setdefault(f.task.group.name, {}).setdefault(
f.task.name, []
).append(BoundField(self, self.fields[field_name], field_name))
def to_tree(self):
return render_to_string('core/tree_form.html', {'tree': self.tree})
def save(self):
ids = self.get_ids()
ids_current = self.instance.function.values_list('id', flat=True)
self.instance.function.remove(*list(set(ids_current) - set(ids)))
self.instance.function.add(*list(set(ids) - set(ids_current)))
return self.instance
def get_ids(self):
function_field_clean = self.function_field.format('')
return [key.replace(function_field_clean, '')
for key, value in self.cleaned_data.items()
if key.startswith(function_field_clean) and value]
<ul>
{% for name, tasks in tree.items %}
<li>
{{ name }}
<ul>
{% for name, functions in tasks.items %}
<li>
{{ name }}
<ul>
{% for field in functions %}
<li>
{{ field }}{{ field.label }}
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</li>
{% endfor %}
</ul>
</form>
{{ product_form.media.css }}
{{ product_form.media.js }}
А в js, наверное, вместо if (typeof(elem) == 'number'){ надо if (typeof(elem) != 'object'){