-
Notifications
You must be signed in to change notification settings - Fork 8
Commit v0.16
kwmccabe edited this page Apr 17, 2018
·
10 revisions
v0.16 - Item fields (active,item_title,item_text,mod_update), Delete Item confirmation
- +6 -3 [M] mysql/scripts/seeddata.sql
- +8 -1 [M] mysql/scripts/tables.sql
- +5 -0 [M] web/app/item/forms.py
- +8 -0 [M] web/app/item/models.py
- +6 -2 [M] web/app/item/templates/item_create.html
- +15 -2 [M] web/app/item/templates/item_edit.html
- +20 -0 [A] web/app/item/templates/item_index.html
- +12 -3 [M] web/app/item/templates/item_list.html
- +1 -1 [M] web/app/item/templates/item_view.html
- +11 -5 [M] web/app/item/views.py
- +1 -0 [M] web/app/main/templates/base.html
- +3 -3 [M] web/app/main/templates/navbar_main.html
- +1 -1 [M] web/app/main/views.py
- +14 -0 [M] web/app/static/js/flaskapp.js
- Add
item_title
anditem_text
toflaskapp.item
seeddata.
DELETE FROM `item`;
-INSERT INTO `item` (keyname) VALUES ("one");
-INSERT INTO `item` (keyname) VALUES ("two");
-INSERT INTO `item` (keyname) VALUES ("three");
+INSERT INTO `item` (keyname,item_title,item_text) VALUES ("one","One","One here");
+INSERT INTO `item` (keyname,item_title,item_text) VALUES ("two","Two","Two here");
+INSERT INTO `item` (keyname,item_title,item_text) VALUES ("three","Three","Three here");
+INSERT INTO `item` (keyname,item_title,item_text) VALUES ("four","Four","Four here");
+INSERT INTO `item` (keyname,item_title,item_text) VALUES ("five","Five","Five here");
+INSERT INTO `item` (keyname,item_title,item_text) VALUES ("six","Six","Six here");
OPTIMIZE TABLE `item`;
- Add
active
,item_title
,item_text
andmod_update
toCREATE TABLE
statement.
CREATE TABLE `item` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`keyname` varchar(63) NOT NULL,
+ `active` tinyint(1) NOT NULL DEFAULT '1',
+ `item_title` varchar(255) DEFAULT NULL,
+ `item_text` text,
`mod_create` datetime DEFAULT CURRENT_TIMESTAMP,
+ `mod_update` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
- UNIQUE KEY `item_keyname` (`keyname`)
+ UNIQUE KEY `item_keyname` (`keyname`),
+ KEY `item_active` (`active`),
+ KEY `item_title` (`item_title`),
+ KEY `item_update` (`mod_update`)
) ENGINE=InnoDB AUTO_INCREMENT=1000 DEFAULT CHARSET=utf8;
DESCRIBE `item`;
SELECT "table `item` created" AS MSG;
- Add the required column
item_title
toCreateItemForm
. - Add all columns (editable and non-editable) to
EditItemForm
.
class CreatItemForm(FlaskForm):
keyname = StringField('Keyname', validators=[InputRequired(),Length(2,63),validate_keyname], filters=[filter_keyname])
+ item_title = StringField('Title', validators=[InputRequired(),Length(1,255)])
submit = SubmitField('Create Item')
...
class EditItemForm(FlaskForm):
id = HiddenField('id')
keyname = StringField('Keyname', validators=[InputRequired(),Length(2,63),validate_keyname], filters=[filter_keyname])
+ active = BooleanField('Active')
+ item_title = StringField('Title', validators=[InputRequired(),Length(1,255)])
+ item_text = TextAreaField('Text')
mod_create = DateTimeField('Item Created')
+ mod_update = DateTimeField('Item Updated')
submit = SubmitField('Update Item')
- Add
active
,item_title
,item_text
andmod_update
to classItemModel
.
__tablename__ = 'item'
id = db.Column(db.BigInteger, autoincrement=True, primary_key=True)
keyname = db.Column(db.String(63), nullable=False, index=True, unique=True, default='')
+ active = db.Column(db.Boolean, nullable=False, index=True, default=1)
+ item_title = db.Column(db.String(255))
+ item_text = db.Column(db.Text)
mod_create = db.Column(db.DateTime, default=datetime.utcnow)
+ mod_update = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, index=True)
def to_json(self):
json_item = {
#'url': url_for('api.get_item', id=self.id),
'id' : self.id,
'keyname' : self.keyname,
+ 'active' : self.active,
+ 'item_title': self.item_title,
+ 'item_text' : self.item_text,
'mod_create': self.mod_create,
+ 'mod_update': self.mod_update,
}
return json_item
- Add input field for the required column
item_title
.
<!-- BLOCK: breadcrumb -->
{% block breadcrumb %}
{{super()}}
-<li><a href="/admin/">Admin</a></li>
+<li><a href="{{ url_for('main.main_page', page='admin') }}">Admin</a></li>
<li><a href="{{ url_for('.item_list') }}">Items</a></li>
<li><a href="{{ url_for('.item_create') }}">Create</a></li>
{% endblock %}
...
+ <div class="form-group">
+ *{{ form.item_title.label }}
+ {{ form.item_title(class_='form-control',placeholder='Title') }}
+ </div>
{{ form.submit(class_='btn btn-primary') }}
<span class="form-submit-buttons">
- [ <a class="btn btn-default" href="{{ url_for('.item_list') }}">Cancel</a> ]
+ <a class="btn btn-default" href="{{ url_for('.item_list') }}">Cancel</a>
</span>
</form>
- Add input fields for columns
item_title
,item_text
, andactive
. - Add display for column
mod_update
. - Add
data-confirm-link="Delete Item? This action cannot be undone."
to Delete Item link.
<!-- BLOCK: breadcrumb -->
{% block breadcrumb %}
{{super()}}
-<li><a href="/admin/">Admin</a></li>
+<li><a href="{{ url_for('main.main_page', page='admin') }}">Admin</a></li>
<li><a href="{{ url_for('.item_list') }}">Items</a></li>
<li><a href="{{ url_for('.item_edit', id=form.id.data) }}">Edit {{ form.item.keyname }}</a></li>
{% endblock %}
...
+ <div class="form-group">
+ *{{ form.item_title.label }}
+ {{ form.item_title(class_='form-control',placeholder='Title') }}
+ </div>
+ <div class="form-group">
+ {{ form.item_text.label }}
+ {{ form.item_text(class_='form-control',placeholder='Text') }}
+ </div>
+ <div class="form-group">
+ {{ form.active.label }}
+ {{ form.active(class_='form-control') }}
+ </div>
{{ form.submit(class_='btn btn-primary') }}
<span class="form-submit-buttons">
- [ <a href="{{ url_for('.item_delete', id=form.id.data) }}">Delete Item</a> ]
+ [ <a data-confirm-link="Delete Item? This action cannot be undone." href="{{ url_for('.item_delete', id=form.id.data) }}">Delete Item</a> ]
</span>
</form>
{{ form.mod_create.label }} : {{ form.mod_create.data }}<br/>
+{{ form.mod_update.label }} : {{ form.mod_update.data }}<br/>
</div> <!-- end class="panel-body" -->
</div> <!-- end class="panel" -->
- Create template for route
/item/
.
+{% extends "base.html" %}
+
+<!-- BLOCK: breadcrumb -->
+{% block breadcrumb %}
+{{super()}}
+<li><a href="{{ url_for('.item_page') }}">Items</a></li>
+{% endblock %}
+
+<!-- BLOCK: content -->
+{% block content %}
+
+<p>This is public landing page for the Item Module.</p>
+
+{% endblock %}
+
+
+<!-- BLOCK: templates -->
+{% block templates %}{{super()}} - item_index.html{% endblock %}
+
+{# end web/app/item/templates/item_index.html #}
- Add placeholder navigation links for filtering view by
item.active
. - Add
data-confirm-link
to Delete Item link.
<!-- BLOCK: breadcrumb -->
{% block breadcrumb %}
{{super()}}
-<li><a href="/admin/">Admin</a></li>
+<li><a href="{{ url_for('main.main_page', page='admin') }}">Admin</a></li>
<li><a href="{{ url_for('.item_list') }}">Items</a></li>
{% endblock %}
...
<tr>
<td>
Showing {{ rowcnt }} Items
- <br/><br/>[ <a href="{{ url_for('.item_create') }}">Create Item</a> ]
</td>
<td class="text-right">
<span>Page 1 of 1</span>
</td>
</tr>
+<tr>
+<td>
+ [ <a href="{{ url_for('.item_create') }}">Create Item</a> ]
+</td>
+<td class="text-right">
+ [<a href="{{ url_for('.item_list') }}?status=all">All</a>]
+ [<a href="{{ url_for('.item_list') }}?status=active">Active</a>]
+ [<a href="{{ url_for('.item_list') }}?status=inactive">Inactive</a>]
+</td>
+</tr>
</table>
...
<td>
[ <a href="{{ url_for('.item_edit', id=row.id) }}">edit</a> ]
- [ <a href="{{ url_for('.item_delete', id=row.id) }}">delete</a> ]
+ [ <a data-confirm-link="Delete Item? This action cannot be undone." href="{{ url_for('.item_delete', id=row.id) }}">delete</a> ]
</td>
<!-- BLOCK: breadcrumb -->
{% block breadcrumb %}
{{super()}}
-<li><a href="/admin/">Admin</a></li>
+<li><a href="{{ url_for('main.main_page', page='admin') }}">Admin</a></li>
<li><a href="{{ url_for('.item_list') }}">Items</a></li>
<li><a href="{{ url_for('.item_view', id=item.id) }}">{{ item.keyname }}</a></li>
{% endblock %}
- Replace
hello_item()
with new, generic route/item/<page>/
. - Remove
form.mod_update
from database update - applies default as defined inCREATE TABLE
statement.
+from jinja2 import TemplateNotFound
...
-@item.route('/item/')
-def hello_item():
- logging.info("hello_item()")
- return 'Hello FlaskApp : Item Module'
+@item.route('/item/', defaults={'page': 'index'})
+@item.route('/item/<page>/')
+def item_page(page):
+ try:
+ logging.debug( 'item_page( page:%s )' % (page) )
+ return render_template('item_%s.html' % (page))
+ except TemplateNotFound:
+ logging.info('TemplateNotFound: item_%s.html' % (page))
+ abort(404)
...
item = ItemModel.query.get_or_404(id)
form = EditItemForm(item)
if form.validate_on_submit():
- del form.mod_create
+ del form.mod_create, form.mod_update
form.populate_obj(item)
db.session.add(item)
db.session.commit()
<div id="debuginfo"><pre>
DEBUG:
TEMPLATES: {% block templates %}base.html{% endblock %}
+REQUEST.ARGS: {{ request.args }}
</pre></div>
- Link to route
/item/
. - Link to route
/admin/
.
<div class="collapse navbar-collapse" id="navbar-main-collapse">
<ul class="nav navbar-nav">
<!-- li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li -->
- <li><a href="#">Items</a></li>
+ <li><a href="{{ url_for('item.item_page') }}">Items</a></li>
<li><a href="#">Users</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Admin <span class="caret"></span></a>
<ul class="dropdown-menu">
+ <li><a href="{{ url_for('main.main_page', page='admin') }}">Dashboard</a></li>
+ <li role="separator" class="divider"></li>
<li><a href="{{ url_for('item.item_list') }}">Items</a></li>
<li><a href="#">Users</a></li>
- <li role="separator" class="divider"></li>
- <li><a href="#">ItemSix</a></li>
</ul>
</li>
</ul>
@main.route('/<page>/')
def main_page(page):
try:
- logging.debug( "main_page( %s )" % page )
+ logging.debug( 'main_page( page:%s )' % (page) )
return render_template('%s.html' % (page))
except TemplateNotFound:
logging.info('TemplateNotFound: %s.html' % (page))
- New
$(document).ready()
function searches for anchor tags with the attributedata-confirm-link
, and attaches a javascriptconfirm()
dialog. - eg,
<a data-confirm-link="Really do it?" href="/doit/123">Do It</a>
+/**
+ * add confirm dialog for <a> with data-confirm-link attribute
+ * @see item_edit.html
+ */
+$(document).ready(function () {
+ $('a[data-confirm-link]').click(function () {
+ if (confirm($(this).data('confirm-link')))
+ window.location = $(this).attr('href');
+ return false;
+ });
+});
Commit-v0.15 | Commit-v0.16 | Commit-v0.17
- FlaskApp Tutorial
- Table of Contents
- About
- Application Setup
- Modules, Templates, and Layouts
- Database Items, Forms, and CRUD
- List Filter, Sort, and Paginate
- Users and Login
- Database Relationships
- API Module, HTTPAuth and JSON
- Refactoring User Roles and Item Status
- AJAX and Public Pages