Flask¶
Initialize Flask app and sqlalchemy
from pprint import pprint
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy_mptt.mixins import BaseNestedSets
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
Make models.
class Category(db.Model, BaseNestedSets):
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(400), index=True, unique=True)
items = db.relationship("Product", backref='item', lazy='dynamic')
def __repr__(self):
return '<Category {}>'.format(self.name)
class Product(db.Model):
__tablename__ = 'products'
id = db.Column(db.Integer, primary_key=True)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
name = db.Column(db.String(475), index=True)
Represent data of tree in table¶
Add data to table with tree.
db.session.add(Category(name="root")) # root node
db.session.add_all( # first branch of tree
[
Category(name="foo", parent_id=1),
Category(name="bar", parent_id=2),
Category(name="baz", parent_id=3),
]
)
db.session.add_all( # second branch of tree
[
Category(name="foo1", parent_id=1),
Category(name="bar1", parent_id=5),
Category(name="baz1", parent_id=5),
]
)
db.drop_all()
db.create_all()
db.session.commit()
The database entries are added:
"id" "name" "lft" "rgt" "level" "parent_id" "tree_id"
1 "root" 1 14 1 1
2 "foo" 2 7 2 1 1
3 "bar" 3 6 3 2 1
4 "baz" 4 5 4 3 1
5 "foo1" 8 13 2 1 1
6 "bar1" 9 10 3 5 1
7 "baz1" 11 12 3 5 1
Lft
of root element every time \(1\).
\(root_{lft} = 1\)
Rgt
of root element always equal 2 * quantity of tree nodes.
\(root_{rgt} = 2 * | P |\)
\(root_{rgt} = 2 * 7 = 14\)
The tree that displays the records in the database is represented schematically below:
level
1 1(root)14
|
---------------------
| |
2 2(foo)7 8(foo1)13
| / \
3 3(bar)6 9(bar1)10 11(baz1)12
|
4 4(baz)5
Drilldown¶
Drilldown tree for a given node.
A drilldown tree consists of a node’s ancestors, itself and its immediate
children. For example, a drilldown tree for a foo1
category might look
something like:
Drilldown for foo1 node
level
1 1(root)14
|
---------------------
| ----------|---------------
2 2(foo)7 | 8(foo1)13 |
| | / \ |
3 3(bar)6 | 9(bar1)10 11(baz1)12 |
| --------------------------
4 4(baz)5
categories = Category.query.all()
for item in categories:
print(item)
pprint(item.drilldown_tree())
print()
<Category root>
[{'children': [{'children': [{'children': [{'node': <Category baz>}],
'node': <Category bar>}],
'node': <Category foo>},
{'children': [{'node': <Category bar1>},
{'node': <Category baz1>}],
'node': <Category foo1>}],
'node': <Category root>}]
<Category foo>
[{'children': [{'children': [{'node': <Category baz>}],
'node': <Category bar>}],
'node': <Category foo>}]
<Category bar>
[{'children': [{'node': <Category baz>}], 'node': <Category bar>}]
<Category baz>
[{'node': <Category baz>}]
<Category foo1>
[{'children': [{'node': <Category bar1>}, {'node': <Category baz1>}],
'node': <Category foo1>}]
<Category bar1>
[{'node': <Category bar1>}]
<Category baz1>
[{'node': <Category baz1>}]
Represent it to JSON format:
def cat_to_json(item):
return {
'id': item.id,
'name': item.name
}
for item in categories:
pprint(item.drilldown_tree(json=True, json_fields=cat_to_json))
print()
[{'children': [{'children': [{'children': [{'id': 4,
'label': '<Category baz>',
'name': 'baz'}],
'id': 3,
'label': '<Category bar>',
'name': 'bar'}],
'id': 2,
'label': '<Category foo>',
'name': 'foo'},
{'children': [{'id': 6,
'label': '<Category bar1>',
'name': 'bar1'},
{'id': 7,
'label': '<Category baz1>',
'name': 'baz1'}],
'id': 5,
'label': '<Category foo1>',
'name': 'foo1'}],
'id': 1,
'label': '<Category root>',
'name': 'root'}]
[{'children': [{'children': [{'id': 4,
'label': '<Category baz>',
'name': 'baz'}],
'id': 3,
'label': '<Category bar>',
'name': 'bar'}],
'id': 2,
'label': '<Category foo>',
'name': 'foo'}]
[{'children': [{'id': 4, 'label': '<Category baz>', 'name': 'baz'}],
'id': 3,
'label': '<Category bar>',
'name': 'bar'}]
[{'id': 4, 'label': '<Category baz>', 'name': 'baz'}]
[{'children': [{'id': 6, 'label': '<Category bar1>', 'name': 'bar1'},
{'id': 7, 'label': '<Category baz1>', 'name': 'baz1'}],
'id': 5,
'label': '<Category foo1>',
'name': 'foo1'}]
[{'id': 6, 'label': '<Category bar1>', 'name': 'bar1'}]
[{'id': 7, 'label': '<Category baz1>', 'name': 'baz1'}]
Path to root¶
Returns a list containing the ancestors and the node itself in tree order.
Path to root of bar node
level ---------------------
1 | 1(root)14 |
| | |
| ---------------|-----
| | ----------- |
2 | 2(foo)7 | 8(foo1)13
| | | / \
3 | 3(bar)6 | 9(bar1)10 11(baz1)12
-----|-----
4 4(baz)5
for item in categories:
print(item)
print(item.path_to_root()[-1]) # get root
# last element in list
pprint(item.path_to_root().all())
print()
<Category root>
<Category root>
[<Category root>]
<Category foo>
<Category root>
[<Category foo>, <Category root>]
<Category bar>
<Category root>
[<Category bar>, <Category foo>, <Category root>]
<Category baz>
<Category root>
[<Category baz>, <Category bar>, <Category foo>, <Category root>]
<Category foo1>
<Category root>
[<Category foo1>, <Category root>]
<Category bar1>
<Category root>
[<Category bar1>, <Category foo1>, <Category root>]
<Category baz1>
<Category root>
[<Category baz1>, <Category foo1>, <Category root>]
Full code¶
from pprint import pprint
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy_mptt.mixins import BaseNestedSets
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
class Category(db.Model, BaseNestedSets):
__tablename__ = 'categories'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(400), index=True, unique=True)
items = db.relationship("Product", backref='item', lazy='dynamic')
def __repr__(self):
return '<Category {}>'.format(self.name)
class Product(db.Model):
__tablename__ = 'products'
id = db.Column(db.Integer, primary_key=True)
category_id = db.Column(db.Integer, db.ForeignKey('categories.id'))
name = db.Column(db.String(475), index=True)
db.session.add(Category(name="root")) # root node
db.session.add_all( # first branch of tree
[
Category(name="foo", parent_id=1),
Category(name="bar", parent_id=2),
Category(name="baz", parent_id=3),
]
)
db.session.add_all( # second branch of tree
[
Category(name="foo1", parent_id=1),
Category(name="bar1", parent_id=5),
Category(name="baz1", parent_id=5),
]
)
'''
"id" "name" "lft" "rgt" "level" "parent_id" "tree_id"
1 "root" 1 14 1 1
2 "foo" 2 7 2 1 1
3 "bar" 3 6 3 2 1
4 "baz" 4 5 4 3 1
5 "foo1" 8 13 2 1 1
6 "bar1" 9 10 3 5 1
7 "baz1" 11 12 3 5 1
root lft everytime = 1
root rgt = qty_nodes * 2
level
1 1(root)14
|
---------------------
| |
2 2(foo)7 8(foo1)13
| / \
3 3(bar)6 9(bar1)10 11(baz1)12
|
4 4(baz)5
'''
db.drop_all()
db.create_all()
db.session.commit()
categories = Category.query.all()
for item in categories:
print(item)
pprint(item.drilldown_tree())
print()
'''
<Category root>
[{'children': [{'children': [{'children': [{'node': <Category baz>}],
'node': <Category bar>}],
'node': <Category foo>},
{'children': [{'node': <Category bar1>},
{'node': <Category baz1>}],
'node': <Category foo1>}],
'node': <Category root>}]
<Category foo>
[{'children': [{'children': [{'node': <Category baz>}],
'node': <Category bar>}],
'node': <Category foo>}]
<Category bar>
[{'children': [{'node': <Category baz>}], 'node': <Category bar>}]
<Category baz>
[{'node': <Category baz>}]
<Category foo1>
[{'children': [{'node': <Category bar1>}, {'node': <Category baz1>}],
'node': <Category foo1>}]
<Category bar1>
[{'node': <Category bar1>}]
<Category baz1>
[{'node': <Category baz1>}]
'''
for item in categories:
print(item)
print(item.path_to_root()[-1])
pprint(item.path_to_root().all())
print()
'''
<Category root>
<Category root>
[<Category root>]
<Category foo>
<Category root>
[<Category foo>, <Category root>]
<Category bar>
<Category root>
[<Category bar>, <Category foo>, <Category root>]
<Category baz>
<Category root>
[<Category baz>, <Category bar>, <Category foo>, <Category root>]
<Category foo1>
<Category root>
[<Category foo1>, <Category root>]
<Category bar1>
<Category root>
[<Category bar1>, <Category foo1>, <Category root>]
<Category baz1>
<Category root>
[<Category baz1>, <Category foo1>, <Category root>]
'''