Building all routes by default

This commit is contained in:
Daniel Tsvetkov 2020-06-05 12:38:25 +02:00
parent 1261536737
commit 958cde4baf
6 changed files with 292 additions and 42 deletions

View File

@ -1,5 +1,6 @@
from flask import render_template from flask import render_template
from webapp.routes import *
from oshipka.webapp import app from oshipka.webapp import app

View File

View File

@ -19,24 +19,44 @@ def get_instance(model_view, uuid):
return instance return instance
def list_view(model_view, template, template_ctx_func=None): def list_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
template = template if template else "{}/list.html".format(model_view.model_name) list_func=None, post_list_func=None, **kwargs):
def inner(): def inner():
serialized_args = request.args
serialized_args = args_process_func(serialized_args) if args_process_func else serialized_args
instances = None
if list_func is not None:
instances = list_func(model_view, serialized_args)
if instances is None:
instances = model_view.model.query.all() instances = model_view.model.query.all()
if post_list_func is not None:
instances = post_list_func(instances)
template = template_func(instances) if template_func else None
if not template:
template = "{}/list.html".format(model_view.model_name)
template_ctx = template_ctx_func(instances) if template_ctx_func else {} template_ctx = template_ctx_func(instances) if template_ctx_func else {}
return render_template(template, instances=instances, **template_ctx) return render_template(template, instances=instances, **template_ctx)
return inner return inner
def get_view(model_view, template, template_ctx_func=None): def get_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
template = template if template else "{}/get.html".format(model_view.model_name) get_func=None, post_get_func=None, **kwargs):
def inner(uuid): def inner(uuid):
serialized_args = request.args
serialized_args = args_process_func(serialized_args) if args_process_func else serialized_args
instance = None
if get_func is not None:
instance = get_func(model_view, uuid, serialized_args)
if instance is not None:
instance = instance[0]
if instance is None:
instance = get_instance(model_view, uuid) instance = get_instance(model_view, uuid)
if not instance: if post_get_func is not None:
return redirect(request.referrer or url_for('home')) instance = post_get_func(instance)
template = template_func(instance) if template_func else None
if not template:
template = "{}/get.html".format(model_view.model_name)
template_ctx = template_ctx_func(instance) if template_ctx_func else {} template_ctx = template_ctx_func(instance) if template_ctx_func else {}
return render_template(template, instance=instance, **template_ctx) return render_template(template, instance=instance, **template_ctx)
@ -47,69 +67,117 @@ def serialize_form():
return dict(filter(lambda k: not k[0].startswith("__"), dict(request.form).items())) return dict(filter(lambda k: not k[0].startswith("__"), dict(request.form).items()))
def update_view(model_view, template, pre_process_func=None, post_process_func=None, **kwargs): def update_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
template = template if template else "{}/edit.html".format(model_view.model_name) should_update_func=None, post_add=None, post_commit=None, **kwargs):
def inner(uuid): def inner(uuid):
instance = get_instance(model_view, uuid) instance = get_instance(model_view, uuid)
if not instance: if not instance:
return redirect(request.referrer or url_for('home')) return redirect(request.referrer or url_for('home'))
if request.method == "GET": if request.method == "GET":
return render_template(template, instance=instance) template = template_func(instance) if template_func else None
if not template:
template = "{}/edit.html".format(model_view.model_name)
template_ctx = template_ctx_func(instance) if template_ctx_func else {}
return render_template(template, instance=instance, **template_ctx)
serialized_form = serialize_form() serialized_form = serialize_form()
_next = serialized_form.pop('_next') if '_next' in serialized_form else None _next = serialized_form.pop('_next') if '_next' in serialized_form else None
serialized_form = pre_process_func(serialized_form, instance) if pre_process_func else serialized_form serialized_form = args_process_func(serialized_form) if args_process_func else serialized_form
if should_update_func is not None:
should_update, msg = should_update_func(instance, serialized_form)
else:
should_update, msg = True, ""
if not should_update:
if msg:
flash(msg)
return redirect(_next or request.referrer or url_for('home'))
for k, v in serialized_form.items(): for k, v in serialized_form.items():
setattr(instance, k, v) setattr(instance, k, v)
db.session.add(instance) db.session.add(instance)
if post_add is not None:
post_add(instance)
db.session.commit() db.session.commit()
post_process_func(instance) if post_process_func else instance if post_commit is not None:
flash("Updated {}:{}".format(model_view.model_name, uuid)) post_commit(instance)
flash("Updated {}:{}".format(model_view.model_name, id))
return redirect(_next or request.referrer or url_for('home')) return redirect(_next or request.referrer or url_for('home'))
return inner return inner
def create_view(model_view, template, template_ctx_func=None, post_add=None, post_create=None): def create_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
template = template if template else "{}/create.html".format(model_view.model_name) should_func=None, post_add=None, post_commit=None):
def inner(): def inner():
if request.method == "GET": if request.method == "GET":
template = template_func() if template_func else None
if not template:
template = "{}/create.html".format(model_view.model_name)
template_ctx = template_ctx_func() if template_ctx_func else {} template_ctx = template_ctx_func() if template_ctx_func else {}
return render_template(template, **template_ctx) return render_template(template, **template_ctx)
serialized_form = serialize_form() serialized_form = serialize_form()
_next = serialized_form.pop('_next') if '_next' in serialized_form else None _next = serialized_form.pop('_next') if '_next' in serialized_form else None
serialized_form = args_process_func(serialized_form) if args_process_func else serialized_form
serialized_form['uuid'] = str(uuid4()) serialized_form['uuid'] = str(uuid4())
if should_func is not None:
should_create, msg = should_func(serialized_form)
else:
should_create, msg = True, ""
if not should_create:
if msg:
flash(msg)
return redirect(_next or request.referrer or url_for('home'))
instance = model_view.model(**serialized_form) instance = model_view.model(**serialized_form)
db.session.add(instance) db.session.add(instance)
if post_add is not None: if post_add is not None:
post_add(instance) post_add(instance)
db.session.commit() db.session.commit()
if post_create is not None: if post_commit is not None:
post_create(instance) post_commit(instance)
flash("Created {}".format(model_view.model_name)) flash("Created {}".format(model_view.model_name))
return redirect(_next or request.referrer or url_for('home')) return redirect(_next or request.referrer or url_for('home'))
return inner return inner
def delete_view(model_view): def delete_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
should_func=None, post_delete=None, post_commit=None, **kwargs):
def inner(uuid): def inner(uuid):
instance = get_instance(model_view, uuid) instance = get_instance(model_view, uuid)
if not instance: if not instance:
return redirect(request.referrer or url_for('home')) return redirect(request.referrer or url_for('home'))
if request.method == "GET": if request.method == "GET":
return render_template("delete_instance.html", instance=instance, template = template_func(instance) if template_func else None
model_name=model_view.model_name) if not template:
template = "delete_instance.html"
template_ctx = template_ctx_func(instance) if template_ctx_func else {}
return render_template(template,
instance=instance,
model_name=model_view.model_name,
**template_ctx)
serialized_form = serialize_form() serialized_form = serialize_form()
serialized_form = args_process_func(serialized_form) if args_process_func else serialized_form
_next = serialized_form.pop('_next') if '_next' in serialized_form else None _next = serialized_form.pop('_next') if '_next' in serialized_form else None
if should_func is not None:
should_delete, msg = should_func(instance, serialized_form)
else:
should_delete, msg = True, ""
if not should_delete:
if msg:
flash(msg)
return redirect(_next or request.referrer or url_for('home'))
db.session.delete(instance) db.session.delete(instance)
if post_delete is not None:
post_delete(instance)
db.session.commit() db.session.commit()
if post_commit is not None:
post_commit(instance)
flash("Deleted {}:{}".format(model_view.model_name, uuid)) flash("Deleted {}:{}".format(model_view.model_name, uuid))
return redirect(_next or request.referrer or url_for('home')) return redirect(_next or request.referrer or url_for('home'))
@ -126,36 +194,36 @@ class ModelView(object):
self.model_name = camel_case_to_snake_case(model.__name__) self.model_name = camel_case_to_snake_case(model.__name__)
self.model_name_pl = p.plural(self.model_name) self.model_name_pl = p.plural(self.model_name)
def register_create(self, create_template=None, **kwargs): def register_create(self, **kwargs):
url = '/{}/create'.format(self.model_name_pl) url = '/{}/create'.format(self.model_name_pl)
self.app.add_url_rule(url, methods=["GET", "POST"], self.app.add_url_rule(url, methods=["GET", "POST"],
endpoint='create_{}'.format(self.model_name), endpoint='create_{}'.format(self.model_name),
view_func=create_view(self, create_template, **kwargs)) view_func=create_view(self, **kwargs))
def register_list(self, list_template=None, **kwargs): def register_list(self, **kwargs):
url = '/{}'.format(self.model_name_pl) url = '/{}'.format(self.model_name_pl)
self.app.add_url_rule(url, self.app.add_url_rule(url,
'list_{}'.format(self.model_name), 'list_{}'.format(self.model_name),
list_view(self, list_template, **kwargs)) list_view(self, **kwargs))
def register_get(self, retrieve_template=None, **kwargs): def register_get(self, **kwargs):
url = '/{}/<uuid>'.format(self.model_name_pl) url = '/{}/<uuid>'.format(self.model_name_pl)
self.app.add_url_rule(url, self.app.add_url_rule(url,
'get_{}'.format(self.model_name), 'get_{}'.format(self.model_name),
get_view(self, retrieve_template, **kwargs)) get_view(self, **kwargs))
def register_update(self, update_template=None, **kwargs): def register_update(self, **kwargs):
url = '/{}/<uuid>/edit'.format(self.model_name_pl) url = '/{}/<uuid>/edit'.format(self.model_name_pl)
self.app.add_url_rule(url, methods=["GET", "POST"], self.app.add_url_rule(url, methods=["GET", "POST"],
endpoint='update_{}'.format(self.model_name), endpoint='update_{}'.format(self.model_name),
view_func=update_view(self, update_template, **kwargs)) view_func=update_view(self, **kwargs))
def register_delete(self): def register_delete(self, **kwargs):
url = '/{}/<uuid>/delete'.format(self.model_name_pl) url = '/{}/<uuid>/delete'.format(self.model_name_pl)
self.app.add_url_rule(url, methods=["GET", "POST"], self.app.add_url_rule(url, methods=["GET", "POST"],
endpoint='delete_{}'.format(self.model_name), endpoint='delete_{}'.format(self.model_name),
view_func=delete_view(self)) view_func=delete_view(self, **kwargs))
def catch_flash(f): def catch_flash(f):

109
vm_gen/templates/_hooks.py Normal file
View File

@ -0,0 +1,109 @@
def get_template_func(instance):
return None
def get_templ_ctx_func(instance):
rv = dict()
return rv
def get_func(model_view, uuid, serialized_args):
"""Should return a list of one element (or [None] if element is none) or None if you want default behaviour"""
return None
def post_get_func(instance):
return instance
def list_template_func(instances):
return None
def list_templ_ctx_func(instances):
rv = dict()
return rv
def list_func(model_view, serialized_args):
"""Should return a list elements or None if you want default behaviour"""
return None
def post_list_func(instances):
return instances
def create_template_func():
return None
def create_templ_ctx_func():
rv = dict()
return rv
def create_args_process_func(serialized_form):
return serialized_form
def create_should_func(serialized_form):
return True, ""
def create_post_add_func(instance):
pass
def create_post_commit_func(instance):
pass
def update_template_func(instance):
return None
def update_templ_ctx_func(instance):
rv = dict()
return rv
def update_args_process_func(serialized_form):
return serialized_form
def update_should_func(serialized_form):
return True, ""
def update_post_add_func(instance):
pass
def update_post_commit_func(instance):
pass
def delete_template_func(instance):
return None
def delete_templ_ctx_func(instance):
rv = dict()
return rv
def delete_args_process_func(serialized_form):
return serialized_form
def delete_should_func(instance, serialized_form):
return True, ""
def delete_post_delete_func(instance):
pass
def delete_post_commit_func(instance):
pass

View File

@ -0,0 +1,47 @@
"""
!!!AUTOGENERATED: DO NOT EDIT!!!
Edit the hooks in webapp/routes/[[ name|camel_to_snake ]]_hooks.py instead
"""
from oshipka.webapp import app
from oshipka.webapp.views import ModelView
from webapp.models import [[ name ]]
from webapp.routes.[[ name|camel_to_snake ]]_hooks import *
ModelView(app, [[name]]).register_get(
template_func=get_template_func,
template_ctx_func=get_templ_ctx_func,
get_func=get_func,
post_get_func=post_get_func,
)
ModelView(app, [[name]]).register_list(
template_func=list_template_func,
template_ctx_func=list_templ_ctx_func,
list_func=list_func,
post_list_func=post_list_func,
)
ModelView(app, [[name]]).register_create(
template_func=create_template_func,
template_ctx_func=create_templ_ctx_func,
args_process_func=create_args_process_func,
should_func=create_should_func,
post_add=create_post_add_func,
post_commit=create_post_commit_func,
)
ModelView(app, [[name]]).register_update(
template_func=update_template_func,
template_ctx_func=update_templ_ctx_func,
args_process_func=update_args_process_func,
should_func=update_should_func,
post_add=update_post_add_func,
post_commit=update_post_commit_func,
)
ModelView(app, [[name]]).register_delete(
template_func=delete_template_func,
template_ctx_func=delete_templ_ctx_func,
args_process_func=delete_args_process_func,
should_func=delete_should_func,
post_add=delete_post_delete_func,
post_commit=delete_post_commit_func,
)

View File

@ -1,4 +1,5 @@
import os import os
import shutil
import sys import sys
import autopep8 import autopep8
@ -61,6 +62,20 @@ def process_model(view_model):
f.write(model) f.write(model)
def process_routes(view_model):
template = env.get_template('routes_py')
model = autopep8.fix_code(template.render(**view_model), options=pep_options)
_model_name = view_model.get('name')
model_name_snake = camel_case_to_snake_case(_model_name.split('.yaml')[0])
filename = "{}.py".format(model_name_snake)
with open(os.path.join(ROUTES_PATH, filename), 'w+') as f:
f.write(model)
route_hooks_filename = os.path.join(ROUTES_PATH, "{}_hooks.py".format(model_name_snake))
if not os.path.exists(route_hooks_filename):
src_path = os.path.join(VM_TEMPLATES_PATH, "_hooks.py")
shutil.copy(src_path, route_hooks_filename)
def process_html_templates(view_model): def process_html_templates(view_model):
_model_name_snake = camel_case_to_snake_case(view_model.get('name')) _model_name_snake = camel_case_to_snake_case(view_model.get('name'))
model_dir = os.path.join(HTML_TEMPLATES_PATH, _model_name_snake) model_dir = os.path.join(HTML_TEMPLATES_PATH, _model_name_snake)
@ -76,7 +91,8 @@ def process_html_templates(view_model):
def main(): def main():
view_model_names = os.listdir(VIEW_MODELS_PATH) view_model_names = os.listdir(VIEW_MODELS_PATH)
all_imports = ['from oshipka.persistance import db'] all_model_imports = ['from oshipka.persistance import db']
all_route_imports = []
for view_model_name in view_model_names: for view_model_name in view_model_names:
with open(os.path.join(VIEW_MODELS_PATH, view_model_name), 'r') as stream: with open(os.path.join(VIEW_MODELS_PATH, view_model_name), 'r') as stream:
try: try:
@ -84,15 +100,23 @@ def main():
for view_model in view_models: for view_model in view_models:
view_model = enrich_view_model(view_model) view_model = enrich_view_model(view_model)
process_model(view_model) process_model(view_model)
process_routes(view_model)
view_model_name = view_model.get('name', '') view_model_name = view_model.get('name', '')
all_imports.append('from webapp.models.{} import {}'.format( model_snake_name = camel_case_to_snake_case(view_model_name)
camel_case_to_snake_case(view_model_name), view_model_name)) all_model_imports.append('from webapp.models.{} import {}'.format(
model_snake_name, view_model_name))
process_html_templates(view_model) process_html_templates(view_model)
all_route_imports.append('from webapp.routes.{} import *'.format(
model_snake_name
))
except yaml.YAMLError as e: except yaml.YAMLError as e:
breakpoint() breakpoint()
all_imports = autopep8.fix_code('\n'.join(all_imports), options=pep_options) all_model_imports = autopep8.fix_code('\n'.join(all_model_imports), options=pep_options)
all_route_imports = autopep8.fix_code('\n'.join(all_route_imports), options=pep_options)
with open(os.path.join(MODELS_PATH, "__init__.py"), 'w+') as f: with open(os.path.join(MODELS_PATH, "__init__.py"), 'w+') as f:
f.write(all_imports) f.write(all_model_imports)
with open(os.path.join(ROUTES_PATH, "__init__.py"), 'w+') as f:
f.write(all_route_imports)
if __name__ == "__main__": if __name__ == "__main__":
@ -104,7 +128,8 @@ if __name__ == "__main__":
WEBAPP_PATH = os.path.join(basepath, "webapp") WEBAPP_PATH = os.path.join(basepath, "webapp")
VIEW_MODELS_PATH = os.path.join(WEBAPP_PATH, "view_models") VIEW_MODELS_PATH = os.path.join(WEBAPP_PATH, "view_models")
MODELS_PATH = os.path.join(WEBAPP_PATH, "models") MODELS_PATH = os.path.join(WEBAPP_PATH, "models")
for d in [VIEW_MODELS_PATH,MODELS_PATH ]: ROUTES_PATH = os.path.join(WEBAPP_PATH, "routes")
for d in [VIEW_MODELS_PATH, MODELS_PATH, ROUTES_PATH, ]:
os.makedirs(d, exist_ok=True) os.makedirs(d, exist_ok=True)
HTML_TEMPLATES_PATH = os.path.join(WEBAPP_PATH, "templates") HTML_TEMPLATES_PATH = os.path.join(WEBAPP_PATH, "templates")