├── .gitattributes ├── readme.md ├── sample_db.sqlite ├── screenshots └── 2019-01-26_20-24-38.jpg ├── requirements.txt ├── models.py ├── commands.py ├── app.py ├── .gitignore └── views.py /.gitattributes: -------------------------------------------------------------------------------- 1 | * linguist-vendored 2 | *.py linguist-vendored=false 3 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Flask-Admin rows with submit 2 | 3 | ![Summary](screenshots/2019-01-26_20-24-38.jpg) -------------------------------------------------------------------------------- /sample_db.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjcunningham/flask-admin-row-form/HEAD/sample_db.sqlite -------------------------------------------------------------------------------- /screenshots/2019-01-26_20-24-38.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pjcunningham/flask-admin-row-form/HEAD/screenshots/2019-01-26_20-24-38.jpg -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Click==7.0 2 | enum34==1.1.6 3 | Flask==1.0.2 4 | Flask-Admin==1.5.3 5 | Flask-SQLAlchemy==2.3.2 6 | itsdangerous==1.1.0 7 | Jinja2==2.10 8 | MarkupSafe==1.1.0 9 | SQLAlchemy==1.2.17 10 | Werkzeug==0.15.5 11 | WTForms==2.2.1 12 | -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | __author__ = 'Paul Cunningham' 3 | __copyright = 'Copyright 2019, Paul Cunningham' 4 | 5 | from flask_sqlalchemy import SQLAlchemy 6 | 7 | 8 | db = SQLAlchemy() 9 | 10 | 11 | class Student(db.Model): 12 | id = db.Column(db.Integer, primary_key=True) 13 | cost = db.Column(db.Integer(), nullable=False) 14 | is_paid = db.Column(db.Boolean(), nullable=False) 15 | 16 | def __str__(self): 17 | return unicode(self).encode('utf-8') 18 | 19 | def __unicode__(self): 20 | return "ID: {id}; Cost : {cost}".format(id=self.id, cost=self.cost) 21 | -------------------------------------------------------------------------------- /commands.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | __author__ = 'Paul Cunningham' 3 | __copyright = 'Copyright 2019, Paul Cunningham' 4 | 5 | import random 6 | from flask.cli import click, with_appcontext 7 | from models import db, Student 8 | 9 | 10 | @click.command('create-database') 11 | @with_appcontext 12 | def create_database(): 13 | 14 | # Create 100 students 15 | 16 | db.drop_all() 17 | db.create_all() 18 | 19 | for _ in range(0, 100): 20 | _project = Student( 21 | cost=random.randrange(10, 200), 22 | is_paid=False 23 | ) 24 | db.session.add(_project) 25 | 26 | db.session.commit() 27 | 28 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask_admin import Admin 3 | from models import db, Student 4 | from commands import create_database 5 | 6 | app = Flask(__name__) 7 | 8 | # Create dummy secrey key so we can use sessions 9 | app.config['SECRET_KEY'] = '123456790' 10 | app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True 11 | 12 | # Create in-memory database 13 | app.config['DATABASE_FILE'] = 'sample_db.sqlite' 14 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + app.config['DATABASE_FILE'] 15 | db.init_app(app) 16 | 17 | app.cli.add_command(create_database) 18 | 19 | 20 | # Flask views 21 | @app.route('/') 22 | def index(): 23 | return 'Click me to get to Admin!' 24 | 25 | 26 | from views import StudentView 27 | 28 | admin = Admin(app, template_mode="bootstrap3") 29 | admin.add_view(StudentView(Student, db.session)) 30 | 31 | 32 | if __name__ == '__main__': 33 | app.run() 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #PyCharm 2 | .idea 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | env/ 15 | build/ 16 | develop-eggs/ 17 | dist/ 18 | downloads/ 19 | eggs/ 20 | .eggs/ 21 | lib/ 22 | lib64/ 23 | parts/ 24 | sdist/ 25 | var/ 26 | wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | 31 | # PyInstaller 32 | # Usually these files are written by a python script from a template 33 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 34 | *.manifest 35 | *.spec 36 | 37 | # Installer logs 38 | pip-log.txt 39 | pip-delete-this-directory.txt 40 | 41 | # Unit test / coverage reports 42 | htmlcov/ 43 | .tox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | .hypothesis/ 51 | 52 | # Translations 53 | *.mo 54 | *.pot 55 | 56 | # Django stuff: 57 | *.log 58 | local_settings.py 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # dotenv 86 | .env 87 | 88 | # virtualenv 89 | .venv 90 | venv/ 91 | ENV/ 92 | env/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | 107 | # PyCharm 108 | .idea/ 109 | 110 | -------------------------------------------------------------------------------- /views.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | 3 | __author__ = 'Paul Cunningham' 4 | __copyright = 'Copyright 2019, Paul Cunningham' 5 | 6 | from flask import redirect, flash, url_for 7 | from flask_admin import expose 8 | from flask_admin.contrib import sqla 9 | from flask_admin.helpers import get_form_data 10 | from flask_admin.babel import gettext 11 | from markupsafe import Markup 12 | 13 | 14 | class StudentView(sqla.ModelView): 15 | 16 | page_size = 5 17 | 18 | column_list = ('id', 'cost', 'Pay Now') 19 | column_editable_list = ['cost'] 20 | 21 | # override the column labels 22 | column_labels = { 23 | 'id': 'Student ID', 24 | 'cost': 'Total Bill', 25 | } 26 | 27 | def _format_pay_now(view, context, model, name): 28 | 29 | if model.is_paid: 30 | return 'Paid' 31 | 32 | # render a form with a submit button for student, include a hidden field for the student id 33 | # note how checkout_view method is exposed as a route below 34 | checkout_url = url_for('.checkout_view') 35 | 36 | _html = ''' 37 |
38 | 39 | 40 |