class RequirementForm(forms.ModelForm):
function = forms.ModelMultipleChoiceField(required=True, widget=CustomTreeWidget, queryset=Group.objects.none())
class Meta:
model = Requirement
fields = ('function',)
def __init__(self, all_groups, all_user_characteristics, *args, **kwargs):
super(RequirementForm, self).__init__(*args, **kwargs)
self.fields['function'].queryset = all_groups # Cписок всех Групп берутся из view
{% for group in groups %}
<p>{{ group }}</p>
{% for task in group.task_set.all %}
<p>{{ task }}</p>
{% for function in task.function_set.all %}
<input type="checkbox" name="option" value="{{ function }}">{{ function }}<br>
{% endfor %}
{% endfor %}
{% endfor %}
class CustomTreeWidget(Widget):
template_name = 'tree_widget.html'
def render(self, name, value, attrs=None):
template = loader.get_template(self.template_name)
return mark_safe(template)
<!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>
code = models.UUIDField(_('Code'), primary_key=True, default=uuid.uuid4, editable=False)
class RequirementForm2(forms.Form):
name = forms.СharField()
def __init__(self, all_functions, *args, **kwargs):
*SOME CODE*
super(RequirementForm2, self).__init__(*args, **kwargs)
self.functions = all_functions.select_related('task').select_related('task__group')
*SOME CODE*
Traceback (most recent call last):
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\exception.py", line 39, in inner
response = get_response(request)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Nurzhan\PycharmProjects\RMS\project\views.py", line 1076, in group_requirement_detail
form = RequirementForm2(request.POST or None, instance=Requirement.objects.first(), all_functions=all_functions) # TEST FORM
TypeError: __init__() got multiple values for argument 'all_functions'
Traceback (most recent call last):
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\exception.py", line 39, in inner
response = get_response(request)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\base.py", line 187, in _get_response
response = self.process_exception_by_middleware(e, request)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\core\handlers\base.py", line 185, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "C:\Users\Nurzhan\PycharmProjects\RMS\project\views.py", line 1092, in group_requirement_detail
return render(request, 'project/group_requirement_detail.html', context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\shortcuts.py", line 30, in render
content = loader.render_to_string(template_name, context, request, using=using)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\loader.py", line 68, in render_to_string
return template.render(context, request)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\backends\django.py", line 66, in render
return self.template.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 208, in render
return self._render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 199, in _render
return self.nodelist.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 994, in render
bit = node.render_annotated(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\loader_tags.py", line 174, in render
return compiled_parent._render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 199, in _render
return self.nodelist.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 994, in render
bit = node.render_annotated(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\loader_tags.py", line 70, in render
result = block.nodelist.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 994, in render
bit = node.render_annotated(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 1044, in render
output = self.filter_expression.resolve(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 711, in resolve
obj = self.var.resolve(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 852, in resolve
value = self._resolve_lookup(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 915, in _resolve_lookup
current = current()
File "C:\Users\Nurzhan\PycharmProjects\RMS\project\forms.py", line 268, in to_tree
return render_to_string('project/tree_form.html', context={'tree': tree})
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\loader.py", line 68, in render_to_string
return template.render(context, request)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\backends\django.py", line 66, in render
return self.template.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 208, in render
return self._render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 199, in _render
return self.nodelist.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 994, in render
bit = node.render_annotated(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\defaulttags.py", line 209, in render
nodelist.append(node.render_annotated(context))
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\defaulttags.py", line 209, in render
nodelist.append(node.render_annotated(context))
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\defaulttags.py", line 209, in render
nodelist.append(node.render_annotated(context))
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 961, in render_annotated
return self.render(context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 1050, in render
return render_value_in_context(output, context)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\template\base.py", line 1028, in render_value_in_context
value = force_text(value)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\utils\encoding.py", line 76, in force_text
s = six.text_type(s)
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\utils\html.py", line 391, in <lambda>
klass.__str__ = lambda self: mark_safe(klass_str(self))
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\forms\boundfield.py", line 43, in __str__
return self.as_widget()
File "C:\Users\Nurzhan\AppData\Local\Programs\Python\Python35-32\lib\site-packages\django\forms\boundfield.py", line 89, in as_widget
attrs = self.build_widget_attrs(attrs, widget)
File "C:\Users\Nurzhan\PycharmProjects\RMS\project\forms.py", line 232, in build_widget_attrs
self.initial = widget.attrs.get('value') if widget.attrs.get('value') in self.initial else None
AttributeError: can't set attribute
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'))
...
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>
# если пост запрос
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]
Traceback (most recent call last):
File "C:\Users\Nurzhan\PycharmProjects\RMS\project\forms.py", line 360, in data_tree
return mark_safe(date_tree_template.format(json.dumps(tree), 'function'))
raise TypeError(repr(o) + " is not JSON serializable")
TypeError: UUID('79ea5a9c-f3a1-453e-bb37-e5c1182a383e') is not JSON serializable
<ul class='group'>
и <ul class='task'>
? На данный момент есть var html = $('<ul class="">');
но он ко всем ul применяется. html.append(make_li(name, lst[name]))
html.text(name).append(make_ul(elem));
html.text(name).append(make_ul(elem));
// заменить на
var span = $('<span>').text(name)
html.append(span).append(make_ul(elem));
// или
html.append('<span>' + name + '</span>').append(make_ul(elem));
# в форме, в методе data_tree немного поменять последние строки
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)
classes = ['group', 'task', 'function'] # тут
date_tree_template = "<div class='data-tree' data-tree='{}' data-classes='{}' data-field='{}'></div>" # тут
return mark_safe(date_tree_template.format(json.dumps(tree), json.dumps(classes), 'function')) # тут
$(function() {
var tree = $('.data-tree').data('tree')
var field = $('.data-tree').data('field')
var classes = $('.data-tree').data('classes') // тут
render_tree()
function render_tree() {
if(tree != undefined && field != undefined)
$(".tree").replaceWith(make_ul(tree))
}
function make_ul(lst, class_pos) { // тут
if(class_pos == undefined) // тут
class_pos = 0; // тут
else // тут
class_pos++; // тут
var html = $('<ul class="' + classes[class_pos] + '">'); // тут
for(var name in lst)
html.append(make_li(name, lst[name], class_pos)) // тут
return html;
}
function make_li(name, elem, class_pos) { // тут
var html = $('<li>');
if (typeof(elem) == 'object') {
html.text(name).append(make_ul(elem, class_pos)); // тут
}
if (typeof(elem) == 'number'){
html.append($('[name='+field+'][value='+elem+']').parent())
}
return html;
}
});