Procedural node add and edit forms

This commit is contained in:
Francesco Siddi 2015-02-02 20:42:48 +01:00
parent cc534ae4ef
commit be5c33c581
9 changed files with 242 additions and 33 deletions

View File

@ -23,6 +23,7 @@ thumb = Thumbnail(app)
assets = Environment(app) assets = Environment(app)
# Import controllers # Import controllers
from application.modules.nodes import node_types
from application.modules.nodes import nodes from application.modules.nodes import nodes
from application.modules.main import homepage from application.modules.main import homepage
from application.modules.shots import shots from application.modules.shots import shots
@ -32,4 +33,5 @@ from application.modules.projects import projects
app.register_blueprint(filemanager) app.register_blueprint(filemanager)
app.register_blueprint(shots, url_prefix='/shots') app.register_blueprint(shots, url_prefix='/shots')
app.register_blueprint(projects, url_prefix='/projects') app.register_blueprint(projects, url_prefix='/projects')
app.register_blueprint(node_types, url_prefix='/node-types')
app.register_blueprint(nodes, url_prefix='/nodes') app.register_blueprint(nodes, url_prefix='/nodes')

View File

@ -11,19 +11,22 @@ from application import db
from application.modules.nodes.models import Node, NodeType from application.modules.nodes.models import Node, NodeType
from application.modules.nodes.forms import NodeTypeForm from application.modules.nodes.forms import NodeTypeForm
from application.modules.nodes.forms import get_node_form
from application.modules.nodes.forms import process_node_form
# Name of the Blueprint # Name of the Blueprint
node_types = Blueprint('node_types', __name__)
nodes = Blueprint('nodes', __name__) nodes = Blueprint('nodes', __name__)
@nodes.route("/") @node_types.route("/")
def index(): def index():
"""Display the node types """Display the node types
""" """
node_types = [t for t in NodeType.query.all()] node_types = [t for t in NodeType.query.all()]
return render_template('nodes/index.html', return render_template('node_types/index.html',
title='nodes', title='node_types',
node_types=node_types) node_types=node_types)
shots = [] shots = []
@ -45,7 +48,7 @@ def index():
shots=shots) shots=shots)
@nodes.route("/add", methods=('GET', 'POST')) @node_types.route("/add", methods=['GET', 'POST'])
def add(): def add():
form = NodeTypeForm() form = NodeTypeForm()
@ -58,5 +61,52 @@ def add():
db.session.add(node_type) db.session.add(node_type)
db.session.commit() db.session.commit()
return redirect(url_for('nodes.index')) return redirect(url_for('node_types.index'))
return render_template('nodes/add.html', form=form) return render_template('node_types/add.html', form=form)
@nodes.route("/<node_type>/add", methods=['GET', 'POST'])
def add(node_type):
"""Generic function to add a node of any type
"""
form = get_node_form(node_type)
if form.validate_on_submit():
if process_node_form(form):
return redirect('/')
else:
print form.errors
return render_template('nodes/add.html',
node_type=node_type,
form=form)
@nodes.route("/<int:node_id>/edit", methods=['GET', 'POST'])
def edit(node_id):
"""Generic node editing form
"""
node = Node.query.get_or_404(node_id)
form = get_node_form(node.node_type.url)
if form.validate_on_submit():
if process_node_form(form, node_id):
return redirect(url_for('node.edit', node_id=node_id))
form.name.data = node.name
form.description.data = node.description
# We populate the form, basing ourselves on the default node properties
for node_property in node.properties:
for field in form:
if field.name == node_property.custom_field.name_url:
value = node_property.value
# We cast values into the right type
if node_property.custom_field.field_type == 'integer':
value = int(value)
if node_property.custom_field.field_type == 'select':
value = int(value)
field.data = value
return render_template('nodes/edit.html',
node=node,
form=form)

View File

@ -4,13 +4,112 @@ from wtforms import BooleanField
from wtforms import SelectField from wtforms import SelectField
from wtforms import TextAreaField from wtforms import TextAreaField
from wtforms import IntegerField from wtforms import IntegerField
from wtforms import HiddenField
from application.modules.nodes.models import CustomFields
from wtforms.validators import DataRequired from wtforms.validators import DataRequired
from application.modules.nodes.models import Node, NodeType from application import db
from application.modules.nodes.models import Node, NodeType, NodeProperties
class NodeTypeForm(Form): class NodeTypeForm(Form):
name = TextField('Node Name', validators=[DataRequired()]) name = TextField('Name', validators=[DataRequired()])
url = TextField('Url', validators=[DataRequired()]) url = TextField('Url', validators=[DataRequired()])
description = TextAreaField('Description', validators=[DataRequired()]) description = TextAreaField('Description', validators=[DataRequired()])
is_extended = BooleanField('Is extended') is_extended = BooleanField('Is extended')
def get_node_form(node_type):
node_type = NodeType.query.filter_by(url=node_type).first()
class ProceduralForm(Form):
pass
setattr(ProceduralForm,
'name',
TextField('Name', validators=[DataRequired()]))
setattr(ProceduralForm,
'description',
TextAreaField('Description', validators=[DataRequired()]))
setattr(ProceduralForm,
'node_type_id',
HiddenField(default=node_type.id))
for custom_field in CustomFields.query\
.join(NodeType)\
.filter(NodeType.url == node_type.url):
if custom_field.field_type == 'text':
field_properties = TextAreaField(custom_field.name,
validators=[DataRequired()])
elif custom_field.field_type == 'string':
field_properties = TextField(custom_field.name,
validators=[DataRequired()])
elif custom_field.field_type == 'integer':
field_properties = IntegerField(custom_field.name,
validators=[DataRequired()])
elif custom_field.field_type == 'select':
options = Node.query\
.join(NodeType)\
.filter(NodeType.url==custom_field.name_url)\
.all()
field_properties = SelectField(custom_field.name,
coerce=int,
choices=[(option.id, option.name) for option in options] )
setattr(ProceduralForm, custom_field.name_url, field_properties)
return ProceduralForm()
def process_node_form(form, node_id=None):
"""Generic function used to process new nodes, as well as edits
"""
if form.validate_on_submit():
node_type = NodeType.query.get(form.node_type_id.data)
if node_id:
node = Node.query.get(node_id)
node.name = form.name.data
node.description = form.description.data
else:
node = Node(
name=form.name.data,
description=form.description.data,
node_type_id=form.node_type_id.data)
db.session.add(node)
db.session.commit()
for custom_field in CustomFields.query\
.join(NodeType)\
.filter(NodeType.url == node_type.url):
for field in form:
if field.name == custom_field.name_url:
if node_id:
# Query for the indivitual property
# TODO: collect all properties and loop through them
node_property = NodeProperties.query\
.filter_by(node_id=node_id)\
.filter_by(custom_field_id=custom_field.id)\
.first()
if node_property:
# Update the value of the property
node_property.value = field.data
else:
# If the property is missing we add it
node_property = NodeProperties(
node_id=node.id,
custom_field_id=custom_field.id,
value=field.data)
db.session.add(node_property)
else:
node_property = NodeProperties(
node_id=node.id,
custom_field_id=custom_field.id,
value=field.data)
db.session.add(node_property)
db.session.commit()
return True
else:
return False

View File

@ -47,10 +47,12 @@
<li><a role="menuitem" tabindex="-1" href="">Tasks</a></li> <li><a role="menuitem" tabindex="-1" href="">Tasks</a></li>
<li><a role="menuitem" tabindex="-1" href="">Profile</a></li> <li><a role="menuitem" tabindex="-1" href="">Profile</a></li>
<li class="divider"></li> <li class="divider"></li>
<li><a role="menuitem" tabindex="-1" href="{{url_for('node_types.index')}}">Task Types</a></li>
<li class="divider"></li>
<li><a role="menuitem" tabindex="-1" href="">Log out</a></li> <li><a role="menuitem" tabindex="-1" href="">Log out</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</div><!--/.navbar-collapse --> </div><!--/.navbar-collapse -->
</div> </div>

View File

@ -0,0 +1,31 @@
{% extends 'layout.html' %}
{% block body %}
<div class="col-md-9">
<h2>Add Node type</h2>
<div class="row">
<div class="col-md-6">
<form method="POST" action="{{url_for('node_types.add')}}">
{{ form.hidden_tag() }}
<div class="form-group">
{{ form.name.label }}
{{ form.name(size=20, class='form-control') }}
</div>
<div class="form-group">
{{ form.description.label }}
{{ form.description(size=20, class='form-control') }}
</div>
<div class="form-group">
{{ form.url.label }}
{{ form.url(size=20, class='form-control') }}
</div>
<div class="form-group">
{{ form.is_extended.label }}
{{ form.is_extended(class='form-control') }}
</div>
<input class="btn btn-default" type="submit" value="Add Node Type">
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -44,7 +44,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<a href="{{url_for('nodes.add')}}" class="btn btn-default">Add</a> <a href="{{url_for('node_types.add')}}" class="btn btn-default">Add</a>
</div> </div>
</div> </div>
</div> </div>

View File

@ -2,28 +2,25 @@
{% block body %} {% block body %}
<div class="col-md-9"> <div class="col-md-9">
<h2>Add Node type</h2> <h2>Add {{ node_type }}</h2>
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<form method="POST" action="{{url_for('nodes.add')}}"> <form method="POST" action="{{url_for('nodes.add', node_type=node_type)}}">
{{ form.hidden_tag() }} {% for field in form %}
<div class="form-group"> {% if field.name == 'csrf_token' %}
{{ form.name.label }} {{ field }}
{{ form.name(size=20, class='form-control') }} {% else %}
</div> {% if field.type == "HiddenField" %}
<div class="form-group"> {{ field }}
{{ form.description.label }} {% else %}
{{ form.description(size=20, class='form-control') }} <div class="form-group">
</div> {{ field.label }}
<div class="form-group"> {{ field(class='form-control') }}
{{ form.url.label }} </div>
{{ form.url(size=20, class='form-control') }} {% endif %}
</div> {% endif %}
<div class="form-group"> {% endfor %}
{{ form.is_extended.label }} <input class="btn btn-default" type="submit" value="Create {{ node_type.name }}">
{{ form.is_extended(class='form-control') }}
</div>
<input class="btn btn-default" type="submit" value="Add Node Type">
</form> </form>
</div> </div>
</div> </div>

View File

@ -0,0 +1,28 @@
{% extends 'layout.html' %}
{% block body %}
<div class="col-md-9">
<h2>Edit {{ node.node_type.name }}</h2>
<div class="row">
<div class="col-md-6">
<form method="POST" action="{{url_for('nodes.edit', node_id=node.id)}}">
{% for field in form %}
{% if field.name == 'csrf_token' %}
{{ field }}
{% else %}
{% if field.type == "HiddenField" %}
{{ field }}
{% else %}
<div class="form-group">
{{ field.label }}
{{ field(class='form-control') }}
</div>
{% endif %}
{% endif %}
{% endfor %}
<input class="btn btn-default" type="submit" value="Edit {{ node.node_type.name }}">
</form>
</div>
</div>
</div>
{% endblock %}

View File

@ -34,7 +34,7 @@
{% endif %} {% endif %}
</td> </td>
<td> <td>
<a class="btn btn-default btn-xs" href="{{url_for('shots.edit', shot_id=shot['id'])}}"><i class="glyphicon glyphicon-edit"></i> Edit</a> <a class="btn btn-default btn-xs" href="{{url_for('nodes.edit', node_id=shot['id'])}}"><i class="glyphicon glyphicon-edit"></i> Edit</a>
</td> </td>
</tr> </tr>
{% endfor %} {% endfor %}
@ -56,7 +56,7 @@
</div> </div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<a href="{{url_for('shots.add')}}" class="btn btn-default">Add</a> <a href="{{url_for('nodes.add', node_type='shot')}}" class="btn btn-default">Add</a>
</div> </div>
</div> </div>
</div> </div>