From 2badde4ff42c2d7789d5881d979dd4cd0c3adcb9 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Wed, 4 Feb 2015 01:45:11 +0100 Subject: [PATCH] Node type editing, with FormField and FormList This allows adding and removing custom fields from node types. Currently does not work if the Node Type does not have any initial custom field. --- attract/application/modules/nodes/__init__.py | 36 +++++++ attract/application/modules/nodes/forms.py | 39 ++++++- attract/application/modules/nodes/models.py | 4 +- attract/application/templates/layout.html | 3 +- .../application/templates/node_types/add.html | 65 ++++++++++++ .../templates/node_types/edit.html | 100 ++++++++++++++++++ .../templates/node_types/index.html | 2 +- 7 files changed, 244 insertions(+), 5 deletions(-) create mode 100644 attract/application/templates/node_types/edit.html diff --git a/attract/application/modules/nodes/__init__.py b/attract/application/modules/nodes/__init__.py index 48d57a15..8b0ed52e 100644 --- a/attract/application/modules/nodes/__init__.py +++ b/attract/application/modules/nodes/__init__.py @@ -11,6 +11,7 @@ from application import db from application.modules.nodes.models import Node, NodeType from application.modules.nodes.forms import NodeTypeForm +from application.modules.nodes.forms import CustomFieldForm from application.modules.nodes.forms import get_node_form from application.modules.nodes.forms import process_node_form @@ -65,6 +66,41 @@ def add(): return render_template('node_types/add.html', form=form) +@node_types.route("//edit", methods=['GET', 'POST']) +def edit(node_type_id): + node_type = NodeType.query.get_or_404(node_type_id) + + form = NodeTypeForm(obj=node_type) + + if form.validate_on_submit(): + node_type.name = form.name.data + node_type.description = form.description.data + node_type.url = form.url.data + # Processing custom fields + for field in form.custom_fields: + print field.data['id'] + + db.session.commit() + else: + print form.errors + + + # if form.validate_on_submit(): + # node_type = NodeType( + # name=form.name.data, + # description=form.description.data, + # url=form.url.data) + + # db.session.add(node_type) + # db.session.commit() + + # return redirect(url_for('node_types.index')) + return render_template('node_types/edit.html', + node_type=node_type, + form=form) + + + @nodes.route("/", methods=['GET', 'POST']) def index(): """Generic function to list all nodes diff --git a/attract/application/modules/nodes/forms.py b/attract/application/modules/nodes/forms.py index e1caa6ee..90889729 100644 --- a/attract/application/modules/nodes/forms.py +++ b/attract/application/modules/nodes/forms.py @@ -5,6 +5,9 @@ from wtforms import SelectField from wtforms import TextAreaField from wtforms import IntegerField from wtforms import HiddenField +from wtforms import FieldList +from wtforms import FormField +from wtforms import Form as BasicForm from application.modules.nodes.models import CustomFields from wtforms.validators import DataRequired @@ -13,19 +16,51 @@ from application import db from application.modules.nodes.models import Node, NodeType, NodeProperties -class CustomFieldForm(Form): +class CustomFieldForm(BasicForm): + id = HiddenField() field_type = TextField('Field Type', validators=[DataRequired()]) name = TextField('Name', validators=[DataRequired()]) name_url = TextField('Url', validators=[DataRequired()]) - description = TextAreaField('Description', validators=[DataRequired()]) + description = TextAreaField('Description') is_required = BooleanField('Is extended') + def __init__(self, csrf_enabled=False, *args, **kwargs): + super(CustomFieldForm, self).__init__(csrf_enabled=False, *args, **kwargs) +class ModelFieldList(FieldList): + def __init__(self, *args, **kwargs): + self.model = kwargs.pop("model", None) + super(ModelFieldList, self).__init__(*args, **kwargs) + if not self.model: + raise ValueError("ModelFieldList requires model to be set") + + def populate_obj(self, obj, name): + while len(getattr(obj, name)) < len(self.entries): + newModel = self.model() + db.session.add(newModel) + getattr(obj, name).append(newModel) + while len(getattr(obj, name)) > len(self.entries): + db.session.delete(getattr(obj, name).pop()) + super(ModelFieldList, self).populate_obj(obj, name) + +class ChildInline(Form): + title = TextField('Title',) class NodeTypeForm(Form): name = TextField('Name', validators=[DataRequired()]) url = TextField('Url', validators=[DataRequired()]) description = TextAreaField('Description', validators=[DataRequired()]) is_extended = BooleanField('Is extended') + custom_fields = ModelFieldList(FormField(CustomFieldForm), model=CustomFields) + + +class IMForm(Form): + protocol = SelectField(choices=[('aim', 'AIM'), ('msn', 'MSN')]) + username = TextField() + +class ContactForm(Form): + first_name = TextField() + last_name = TextField() + im_accounts = FieldList(BooleanField('Is extended'),) def get_node_form(node_type): diff --git a/attract/application/modules/nodes/models.py b/attract/application/modules/nodes/models.py index 5ecb9e80..199b97dd 100644 --- a/attract/application/modules/nodes/models.py +++ b/attract/application/modules/nodes/models.py @@ -37,6 +37,9 @@ class NodeType(db.Model): description = db.Column(db.Text) url = db.Column(db.String(120), nullable=False) + custom_fields = db.relationship('CustomFields', backref='NodeType', + cascade="all, delete, delete-orphan") + def __str__(self): return self.name @@ -74,7 +77,6 @@ class Node(db.Model): class CustomFields(db.Model): id = db.Column(db.Integer, primary_key = True) node_type_id = db.Column(db.Integer(), db.ForeignKey(NodeType.id)) - node_type = db.relationship(NodeType, backref='CustomField') field_type = db.Column(db.String(128)) order = db.Column(db.Integer()) diff --git a/attract/application/templates/layout.html b/attract/application/templates/layout.html index f2c3a248..1f0414ab 100644 --- a/attract/application/templates/layout.html +++ b/attract/application/templates/layout.html @@ -94,7 +94,8 @@ "assets/js/jquery.attract.js" %} {% endassets %} - + {% block footer_scripts %} + {% endblock %} diff --git a/attract/application/templates/node_types/add.html b/attract/application/templates/node_types/add.html index 11922c68..984ca400 100644 --- a/attract/application/templates/node_types/add.html +++ b/attract/application/templates/node_types/add.html @@ -23,9 +23,74 @@ {{ form.is_extended.label }} {{ form.is_extended(class='form-control') }} + +
+ {{ form.custom_fields.label }} + + + + + + + + + {% for custom_field in form.custom_fields %} + + + {% for field in custom_field %} + {% if field.type == 'HiddenField' %} + {{field}} + {% else %} + + {% endif %} + {% endfor %} + + + {% endfor %} +
NameUrlDescriptionIs required
{{field}}
+
+ {% endblock %} + +{% block footer_scripts %} + + +{% endblock %} diff --git a/attract/application/templates/node_types/edit.html b/attract/application/templates/node_types/edit.html new file mode 100644 index 00000000..568f9dff --- /dev/null +++ b/attract/application/templates/node_types/edit.html @@ -0,0 +1,100 @@ +{% extends 'layout.html' %} + +{% block body %} +
+

Edit Node type

+
+
+
+ {{ form.hidden_tag() }} +
+ {{ form.name.label }} + {{ form.name(size=20, class='form-control') }} +
+
+ {{ form.description.label }} + {{ form.description(size=20, class='form-control') }} +
+
+ {{ form.url.label }} + {{ form.url(size=20, class='form-control') }} +
+
+ {{ form.is_extended.label }} + {{ form.is_extended(class='form-control') }} +
+ +
+ {{ form.custom_fields.label }} + + + + + + + + + + + + + {% for custom_field in form.custom_fields %} + + + {% for field in custom_field %} + {% if field.type == 'HiddenField' %} + {{field}} + {% else %} + + {% endif %} + {% endfor %} + + + {% endfor %} +
TypeNameUrlDescriptionIs required
{{field}}
+
+ + +
+
+
+
+{% endblock %} + +{% block footer_scripts %} + + +{% endblock %} diff --git a/attract/application/templates/node_types/index.html b/attract/application/templates/node_types/index.html index 839ef571..0588fa7f 100644 --- a/attract/application/templates/node_types/index.html +++ b/attract/application/templates/node_types/index.html @@ -24,7 +24,7 @@ {% endif %} - Edit + Edit {% endfor %}