{ "info": { "author": "Dillon Bowen", "author_email": "dsbowen@wharton.upenn.edu", "bugtrack_url": null, "classifiers": [ "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3" ], "description": "# SQLAlchemy-Nav\n\nSQLAlchemy-Nav provides [SQLAlchemy Mixins](https://docs.sqlalchemy.org/en/13/orm/extensions/declarative/mixins.html) for creating navigation bars compatible with [Bootstrap](https://getbootstrap.com/docs/4.3/components/navbar/). Its Mixins are:\n\n1. ```NavbarMixin``` for creating navigation bars\n2. ```BrandMixin``` for adding a brand to the navbar\n3. ```NavitemMixin``` for adding nav-items to the navbar\n4. ```DropdownitemMixin``` for adding dropdown-items to nav-items\n\n## License\n\nPublications which use this software should include the following citation for SQLAlchemy-Nav and its dependency, [SQLAlchemy-Mutable](https://pypi.org/project/sqlalchemy-mutable/):\n\nBowen, D.S. (2019). SQLAlchemy-Nav \\[Computer software\\]. [https://github.com/dsbowen/sqlalchemy-nav](https://github.com/dsbowen/sqlalchemy-nav)\n\nBowen, D.S. (2019). SQLAlchemy-Mutable \\[Computer software\\]. [https://github.com/dsbowen/sqlalchemy-mutable](https://github.com/dsbowen/sqlalchemy-mutable)\n\nThis project is licensed under the MIT License [LICENSE](https://github.com/dsbowen/sqlalchemy-nav/blob/master/LICENSE).\n\n## Getting started\n\n### Installation\n\nInstall and update using [pip](https://pip.pypa.io/en/stable/quickstart):\n\n```\n$ pip install -U sqlalchemy-nav\n```\n\n### Setup\n\nThe following code will get you started with SQLAlchemy-Nav as quickly as possible:\n\n```python\n# 1. Import classes from sqlalchemy_nav\nfrom sqlalchemy_nav import BrandMixin, DropdownitemMixin, NavbarMixin, NavitemMixin\n\n# 2. Standard session creation\nfrom sqlalchemy import create_engine, Column, Integer\nfrom sqlalchemy.orm import sessionmaker, scoped_session\nfrom sqlalchemy.ext.declarative import declarative_base\n\nengine = create_engine('sqlite:///:memory:')\nsession_factory = sessionmaker(bind=engine)\nSession = scoped_session(session_factory)\nsession = Session()\nBase = declarative_base()\n\n# 3. Use the SQLAlchemy-Nav Mixins to create database models\nclass Navbar(NavbarMixin, Base):\n __tablename__ = 'navbar'\n\nclass Brand(BrandMixin, Base):\n __tablename__ = 'brand'\n\nclass Navitem(NavitemMixin, Base):\n __tablename__ = 'navitem'\n\nclass Dropdownitem(DropdownitemMixin, Base):\n __tablename__ = 'dropdownitem'\n\n# 4. Create the database\nBase.metadata.create_all(engine)\n```\n\n## Examples\n\n### Example 1. Use with SQLAlchemy\n\nThis example generates html for a Bootstrap Navbar using the SQLAlchemy setup above. You can find the full setup and example [here](https://github.com/dsbowen/sqlalchemy-nav/blob/master/example.py)\n\n```python\nbar = Navbar()\nBrand(bar=bar, url='/my-brand', label='My Brand')\nNavitem(bar=bar, url='/my-navitem', label='My Navitem')\nitem = Navitem(bar=bar, label='Dropdown')\nDropdownitem(item=item, url='/dropdown1', label='Dropdownitem 1')\nDropdownitem(item=item, url='/dropdown2', label='Dropdownitem 2')\nbar.view_html()\n```\n\nOutputs:\n\n```html\n\n```\n\n## Example 2: Toy web app with Flask-SQLAlchemy\n\nThis example shows how to use SQLAlchemy-Nav to create dynamic navigation bars in web apps. You can find the full setup and example [here](https://github.com/dsbowen/sqlalchemy-nav/blob/master/flask_example.py).\n\nOur web app uses [Flask](http://flask.palletsprojects.com/en/1.1.x/), [Flask-Bootstrap](https://pythonhosted.org/Flask-Bootstrap/), and [Flask-SQLAlchemy](https://flask-sqlalchemy.palletsprojects.com/en/2.x/).\n\n### Python file\n\nWe begin by creating the ```Navbar``` instance before the first app request. I name the navigation bar so that we can find it later using ```query.filter_by(name='name')```. We then use the navbar to keep a tally of how many times each link on the dropdown menu was visited.\n\n```python\n# 1. Import Mixins from sqlalchemy_nav\nfrom sqlalchemy_nav import BrandMixin, DropdownitemMixin, NavbarMixin, NavitemMixin\n\n# 2. Import Flask classes, methods, and extensions and initialize app\nfrom flask import Flask, render_template, url_for\nfrom flask_bootstrap import Bootstrap\nfrom flask_sqlalchemy import SQLAlchemy\n\napp = Flask(__name__)\napp.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'\napp.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False\nbootstrap = Bootstrap(app)\ndb = SQLAlchemy(app)\n\n# 3. Use the SQLAlchemy-Nav Mixins to create database models\nclass Navbar(NavbarMixin, db.Model):\n pass\n\nclass Brand(BrandMixin, db.Model):\n pass\n\nclass Navitem(NavitemMixin, db.Model):\n pass\n\nclass Dropdownitem(DropdownitemMixin, db.Model):\n pass\n\n# 4. Create a Navbar instance before the first app request\n@app.before_first_request\ndef before_first_request():\n db.create_all()\n bar = Navbar(name='my navbar')\n Brand(bar=bar, label='SQLAlchemy-Nav')\n Navitem(bar=bar, url=url_for('index'), label='Index ')\n item = Navitem(bar=bar, label='Dropdown')\n Dropdownitem(item=item, url=url_for('page1'), label='Page 1 ')\n Dropdownitem(item=item, url=url_for('page2'), label='Page 2 ')\n db.session.add(bar)\n db.session.commit()\n\n@app.route('/')\ndef index():\n # 5. Recover the Navbar instance by name\n bar = Navbar.query.filter_by(name='my navbar').first()\n # 6. Tally visits to the index route\n bar.navitems[0].label += 'x'\n db.session.commit()\n # 7. Pass the Navbar instance to the html template\n return render_template('index.html', bar=bar, content='Index page')\n\n@app.route('/page1')\ndef page1():\n bar = Navbar.query.filter_by(name='my navbar').first()\n bar.navitems[1].dropdownitems[0].label += 'x'\n db.session.commit()\n return render_template('index.html', bar=bar, content='Page 1')\n\n@app.route('/page2')\ndef page2():\n bar = Navbar.query.filter_by(name='my navbar').first()\n bar.navitems[1].dropdownitems[1].label += 'x'\n db.session.commit()\n return render_template('index.html', bar=bar, content='Page 2')\n\nif __name__ == '__main__':\n app.run()\n```\n\n### Html template\n\nNext, we create an ```index.html``` file in our templates folder. The index template must:\n1. Extend the bootstrap base template.\n2. Execute ```{{ bar.render() }}``` in the ```navbar``` block.\n\nRecall that ```bar``` is the ```Navbar``` instance we passed to the index template in step 7.\n\n```html\n{% extends \"bootstrap/base.html\" %}\n\n{% block navbar %}\n{{ bar.render() }}\n{% endblock %}\n\n{% block content %}\n