fix with view_context

This commit is contained in:
Daniel Tsvetkov 2020-06-06 13:33:39 +02:00
parent 958cde4baf
commit cf4ffc861a
18 changed files with 313 additions and 401 deletions

View File

@ -23,7 +23,6 @@ from sqlalchemy.orm.collections import InstrumentedList
from sqlalchemy_utils import Choice
from tww.lib import solve_query, resolve_timezone, dt_tz_translation, time_ago
from whooshalchemy import IndexService
from oshipka.search import add_to_index, remove_from_index, query_index
from oshipka.util.strings import camel_case_to_snake_case
db = SQLAlchemy()
@ -221,11 +220,17 @@ def register_filters(app):
class Proxy(object):
def __init__(self, proxied):
self.proxied = proxied
self.searchables = []
index_service = Proxy(None)
def register_index_svc():
for searchable in index_service.searchables:
index_service.proxied.register_class(searchable)
def init_db(app):
rv = False
app.config["SQLALCHEMY_DATABASE_URI"] = SQLALCHEMY_DATABASE_URI
@ -253,6 +258,7 @@ def init_db(app):
rv = True
global index_service
index_service.proxied = IndexService(config=app.config, session=db.session)
register_index_svc()
return rv
@ -280,46 +286,3 @@ def populate_static(app):
instance = model(**row)
db.session.add(instance)
db.session.commit()
class SearchableMixin(object):
@classmethod
def search(cls, expression, page, per_page):
ids, total = query_index(cls.__tablename__, expression, page, per_page)
if total == 0:
return cls.query.filter_by(id=0), 0
when = []
for i in range(len(ids)):
when.append((ids[i], i))
return cls.query.filter(cls.id.in_(ids)).order_by(
db.case(when, value=cls.id)), total
@classmethod
def before_commit(cls, session):
session._changes = {
'add': list(session.new),
'update': list(session.dirty),
'delete': list(session.deleted)
}
@classmethod
def after_commit(cls, session):
for obj in session._changes['add']:
if isinstance(obj, SearchableMixin):
add_to_index(obj.__tablename__, obj)
for obj in session._changes['update']:
if isinstance(obj, SearchableMixin):
add_to_index(obj.__tablename__, obj)
for obj in session._changes['delete']:
if isinstance(obj, SearchableMixin):
remove_from_index(obj.__tablename__, obj)
session._changes = None
@classmethod
def reindex(cls):
for obj in cls.query:
add_to_index(cls.__tablename__, obj)
db.event.listen(db.session, 'before_commit', SearchableMixin.before_commit)
db.event.listen(db.session, 'after_commit', SearchableMixin.after_commit)

View File

@ -1,27 +0,0 @@
from flask import current_app
def add_to_index(index, model):
if not hasattr(current_app, 'elasticsearch'):
return
payload = {}
for field in model.__searchable__:
payload[field] = getattr(model, field)
current_app.elasticsearch.index(index=index, id=model.id, body=payload)
def remove_from_index(index, model):
if not hasattr(current_app, 'elasticsearch'):
return
current_app.elasticsearch.delete(index=index, id=model.id)
def query_index(index, query, page, per_page):
if not hasattr(current_app, 'elasticsearch'):
return [], 0
search = current_app.elasticsearch.search(
index=index,
body={'query': {'multi_match': {'query': query, 'fields': ['*']}},
'from': (page - 1) * per_page, 'size': per_page})
ids = [int(hit['_id']) for hit in search['hits']['hits']]
return ids, search['hits']['total']['value']

View File

@ -1,9 +1,9 @@
{% extends "layout.html" %}
{% block content %}
<h1>Delete {{ model_name }}:{{ instance.id }} ?</h1>
<form action="{{ url_for('delete_' + model_name, uuid=instance.uuid) }}" method="post">
<input type="hidden" value="{{ request.args.next or url_for('list_' + model_name) }}" name="_next"/>
<h1>Delete {{ model_view.model_name }}:{{ instance.id }} ?</h1>
<form action="{{ url_for('delete_' + model_view.model_name, uuid=instance.uuid) }}" method="post">
<input type="hidden" value="{{ request.args.next or url_for('list_' + model_view.model_name) }}" name="_next"/>
<input type="submit"/>
</form>
<a href="{{ request.args.next }}">Back</a>

View File

@ -1,185 +1,173 @@
from functools import wraps
from uuid import uuid4
import inflect
from flask import flash, render_template, redirect, request, url_for
from flask import flash, render_template, redirect, request, url_for, jsonify
from oshipka.persistance import db
from oshipka.util.strings import camel_case_to_snake_case
def get_instance(model_view, uuid):
model = model_view.model
if uuid.isdigit():
instance = model.query.filter_by(id=uuid).first()
def default_get_args_func(view_context):
view_context.serialized_args = request.args
def default_get_form_func(vc):
vc.redirect_next = request.form.get('_next')
vc.serialized_args = dict(filter(lambda k: not k[0].startswith("_"), dict(request.form).items()))
to_delete = []
for key, value in vc.serialized_args.items():
if key.endswith('_id'):
if value in ['']:
to_delete.append(key)
else:
vc.serialized_args[key] = int(value)
for key in to_delete:
del vc.serialized_args[key]
def default_jsonify_func(vc):
if type(vc.instances) is list:
return jsonify([instance.serialize() for instance in vc.instances])
return jsonify(vc.instances.serialize())
def default_redirect_func(vc):
return redirect(vc.redirect_next or request.referrer or url_for('home'))
def default_get_func(vc):
model = vc.model_view.model
uuid = vc.url_args.get('uuid')
if uuid and vc.url_args.get('uuid').isdigit():
vc.instances = model.query.filter_by(id=uuid).all()
else:
instance = model.query.filter_by(uuid=uuid).first()
if not instance:
flash("No {}:{}".format(model_view.model_name, uuid))
return instance
vc.instances = model.query.filter_by(uuid=uuid).all()
if not vc.instances:
flash("No {}:{}".format(vc.model_view.model_name, uuid))
def list_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
list_func=None, post_list_func=None, **kwargs):
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()
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 {}
return render_template(template, instances=instances, **template_ctx)
return inner
def default_list_args_get_func(vc):
vc.serialized_args = request.args
def get_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
get_func=None, post_get_func=None, **kwargs):
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)
if post_get_func is not None:
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 {}
return render_template(template, instance=instance, **template_ctx)
return inner
def default_list_func(vc):
vc.instances = vc.model_view.model.query.all()
def serialize_form():
return dict(filter(lambda k: not k[0].startswith("__"), dict(request.form).items()))
def default_search_func(vc):
q = vc.serialized_args.get('q')
if hasattr(vc.model_view.model, 'search_query'):
vc.instances = vc.model_view.model.search_query("{q}".format(q=q)).all()
def update_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
should_update_func=None, post_add=None, post_commit=None, **kwargs):
def inner(uuid):
instance = get_instance(model_view, uuid)
if not instance:
return redirect(request.referrer or url_for('home'))
def default_create_func(vc):
instance = vc.model_view.model(**vc.serialized_args)
db.session.add(instance)
vc.instances = [instance]
def default_update_func(vc):
instance = vc.instances[0]
for k, v in vc.serialized_args.items():
setattr(instance, k, v)
db.session.add(instance)
def default_delete_func(vc):
instance = vc.instances[0]
db.session.delete(instance)
def default_render_func(vc):
if len(vc.instances) == 1:
vc.template_ctx['instance'] = vc.instances[0]
vc.template_ctx['instances'] = vc.instances
vc.template_ctx['model_view'] = vc.model_view
return render_template(vc.template, **vc.template_ctx)
def default_commit_func(vc):
db.session.commit()
def default_none_func(vc):
pass
class ViewContext(object):
def __init__(self, args_get_func=None, args_process_func=None,
filter_func=None, redirect_func=None,
should_execute_func=None, execute_func=None, post_execute_func=None,
commit_func=None, post_commit_func=None,
jsonify_func=None, render_func=None, template_func=None, template_ctx_func=None,
should_redirect_no_instances_func=None,
should_redirect_at_end_func=None,
json=False, **kwargs):
self.args_get_func = args_get_func or default_get_args_func
self.args_process_func = args_process_func or default_none_func
self.filter_func = filter_func or default_none_func
self.should_redirect_no_instances_func = should_redirect_no_instances_func or default_none_func
self.redirect_func = redirect_func or default_redirect_func
self.should_execute_func = should_execute_func or default_none_func
self.execute_func = execute_func or default_none_func
self.post_execute_func = post_execute_func or default_none_func
self.commit_func = commit_func or default_commit_func
self.post_commit_func = post_commit_func or default_none_func
self.jsonify_func = jsonify_func or default_jsonify_func
self.render_func = render_func or default_render_func
self.template_func = template_func or default_none_func
self.template_ctx_func = template_ctx_func or default_none_func
self.should_redirect_at_end_func = should_redirect_at_end_func or default_none_func
self.json = json
self.serialized_args = {}
self.url_args = {}
self.instances = []
self.should_execute = True
self.should_redirect_at_end = True
self.template = None
self.template_ctx = {}
self.model_view = None
self.redirect_next = None
def create_view(model_view, view_context, is_json=False, **kwargs):
view_context.model_view = model_view
def return_json_or_template():
if is_json:
return view_context.jsonify_func(view_context)
view_context.template_func(view_context)
view_context.template_ctx_func(view_context)
return view_context.render_func(view_context)
def inner(**kwargs):
view_context.url_args = kwargs
view_context.args_get_func(view_context)
view_context.args_process_func(view_context)
view_context.filter_func(view_context)
if not view_context.instances:
if view_context.should_redirect_no_instances_func(view_context):
return view_context.redirect_func(view_context)
if request.method == "GET":
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()
return return_json_or_template()
_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
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():
setattr(instance, k, v)
view_context.should_execute_func(view_context)
if not view_context.should_execute:
return view_context.redirect_func(view_context)
db.session.add(instance)
if post_add is not None:
post_add(instance)
view_context.execute_func(view_context)
view_context.post_execute_func(view_context)
view_context.commit_func(view_context)
view_context.post_commit_func(view_context)
db.session.commit()
if post_commit is not None:
post_commit(instance)
flash("Updated {}:{}".format(model_view.model_name, id))
return redirect(_next or request.referrer or url_for('home'))
view_context.should_redirect_at_end_func(view_context)
if view_context.should_redirect_at_end:
return view_context.redirect_func(view_context)
return inner
def create_view(model_view, template_func=None, template_ctx_func=None, args_process_func=None,
should_func=None, post_add=None, post_commit=None):
def inner():
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 {}
return render_template(template, **template_ctx)
serialized_form = serialize_form()
_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())
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)
db.session.add(instance)
if post_add is not None:
post_add(instance)
db.session.commit()
if post_commit is not None:
post_commit(instance)
flash("Created {}".format(model_view.model_name))
return redirect(_next or request.referrer or url_for('home'))
return inner
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):
instance = get_instance(model_view, uuid)
if not instance:
return redirect(request.referrer or url_for('home'))
if request.method == "GET":
template = template_func(instance) if template_func else None
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 = args_process_func(serialized_form) if args_process_func else serialized_form
_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)
if post_delete is not None:
post_delete(instance)
db.session.commit()
if post_commit is not None:
post_commit(instance)
flash("Deleted {}:{}".format(model_view.model_name, uuid))
return redirect(_next or request.referrer or url_for('home'))
return return_json_or_template()
return inner
@ -194,36 +182,71 @@ class ModelView(object):
self.model_name = camel_case_to_snake_case(model.__name__)
self.model_name_pl = p.plural(self.model_name)
def register_create(self, **kwargs):
url = '/{}/create'.format(self.model_name_pl)
self.app.add_url_rule(url, methods=["GET", "POST"],
endpoint='create_{}'.format(self.model_name),
view_func=create_view(self, **kwargs))
def register_list(self, **kwargs):
url = '/{}'.format(self.model_name_pl)
self.app.add_url_rule(url,
'list_{}'.format(self.model_name),
list_view(self, **kwargs))
def _register_rule(self, url_args, **kwargs):
url = url_args.pop('rule')
api_url = '/api{}'.format(url)
endpoint = url_args.pop('endpoint')
api_endpoint = 'api_{}'.format(endpoint)
view_func = url_args.pop('view_func')
self.app.add_url_rule(rule=url, endpoint=endpoint,
view_func=view_func(self, **kwargs), **url_args)
kwargs['is_json'] = True
self.app.add_url_rule(rule=api_url, endpoint=api_endpoint,
view_func=view_func(self, **kwargs), **url_args)
def register_get(self, **kwargs):
url = '/{}/<uuid>'.format(self.model_name_pl)
url_args = dict(
rule='/{}/<uuid>/get'.format(self.model_name_pl),
methods=["GET"],
endpoint='get_{}'.format(self.model_name),
view_func=create_view,
)
self._register_rule(url_args, **kwargs)
self.app.add_url_rule(url,
'get_{}'.format(self.model_name),
get_view(self, **kwargs))
def register_list(self, **kwargs):
url_args = dict(
rule='/{}/list'.format(self.model_name_pl),
methods=["GET"],
endpoint='list_{}'.format(self.model_name),
view_func=create_view,
)
self._register_rule(url_args, **kwargs)
def register_create(self, **kwargs):
url_args = dict(
rule='/{}/create'.format(self.model_name_pl),
methods=["GET", "POST"],
endpoint='create_{}'.format(self.model_name),
view_func=create_view,
)
self._register_rule(url_args, **kwargs)
def register_update(self, **kwargs):
url = '/{}/<uuid>/edit'.format(self.model_name_pl)
self.app.add_url_rule(url, methods=["GET", "POST"],
endpoint='update_{}'.format(self.model_name),
view_func=update_view(self, **kwargs))
url_args = dict(
rule='/{}/<uuid>/update'.format(self.model_name_pl),
methods=["GET", "POST"],
endpoint='update_{}'.format(self.model_name),
view_func=create_view,
)
self._register_rule(url_args, **kwargs)
def register_delete(self, **kwargs):
url = '/{}/<uuid>/delete'.format(self.model_name_pl)
self.app.add_url_rule(url, methods=["GET", "POST"],
endpoint='delete_{}'.format(self.model_name),
view_func=delete_view(self, **kwargs))
url_args = dict(
rule='/{}/<uuid>/delete'.format(self.model_name_pl),
methods=["GET", "POST"],
endpoint='delete_{}'.format(self.model_name),
view_func=create_view,
)
self._register_rule(url_args, **kwargs)
def register_search(self, **kwargs):
url_args = dict(
rule='/{}/search'.format(self.model_name_pl),
methods=["GET"],
endpoint='search_{}'.format(self.model_name),
view_func=create_view,
)
self._register_rule(url_args, **kwargs)
def catch_flash(f):

View File

@ -1,109 +1,62 @@
def get_template_func(instance):
return None
from oshipka.webapp.views import ViewContext, default_get_args_func, default_get_func, default_list_func, \
default_get_form_func, default_create_func, default_update_func, default_delete_func, default_search_func
def get_templ_ctx_func(instance):
rv = dict()
return rv
def get_template(vc):
vc.template = "{}/get.html".format(vc.model_view.model_name)
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 search_template(vc):
vc.template = "{}/search.html".format(vc.model_view.model_name)
def post_get_func(instance):
return instance
def list_template(vc):
vc.template = "{}/list.html".format(vc.model_view.model_name)
def list_template_func(instances):
return None
def create_template(vc):
vc.template = "{}/create.html".format(vc.model_view.model_name)
def list_templ_ctx_func(instances):
rv = dict()
return rv
def update_template(vc):
vc.template = "{}/update.html".format(vc.model_view.model_name)
def list_func(model_view, serialized_args):
"""Should return a list elements or None if you want default behaviour"""
return None
def delete_template(vc):
vc.template = "delete_instance.html".format(vc.model_view.model_name)
def post_list_func(instances):
return instances
get_view_context = ViewContext(
filter_func=default_get_func,
template_func=get_template,
)
list_view_context = ViewContext(
filter_func=default_list_func,
template_func=list_template,
)
def create_template_func():
return None
search_view_context = ViewContext(
filter_func=default_search_func,
template_func=list_template,
)
create_view_context = ViewContext(
args_get_func=default_get_form_func,
template_func=create_template,
execute_func=default_create_func,
)
def create_templ_ctx_func():
rv = dict()
return rv
update_view_context = ViewContext(
args_get_func=default_get_form_func,
filter_func=default_get_func,
template_func=update_template,
execute_func=default_update_func,
)
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
delete_view_context = ViewContext(
args_get_func=default_get_form_func,
filter_func=default_get_func,
template_func=delete_template,
execute_func=default_delete_func,
)

View File

@ -1,11 +1,16 @@
<h2>Create [[ name ]]</h2>
<form action="{{ url_for('create_[[ name|camel_to_snake ]]') }}" method="post">
<input type="hidden" name="_next" value="{{ url_for('list_[[ name|camel_to_snake ]]') }}"/>
[%- for column in columns %]
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>:
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
type="text" name="[[ column.name ]]" autocomplete="off"
/>
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>:
[%- if column.type in ['relationship'] %]
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
type="number" name="[[ column.name ]]_id" autocomplete="off"
/>
[%- else %]
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
type="text" name="[[ column.name ]]" autocomplete="off"
/>
[%- endif %]
[%- endfor %]
<input type="submit">
</form>

View File

@ -1,3 +0,0 @@
<h2>{% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
<a href="{{ url_for('update_[[ name|camel_to_snake ]]', uuid=instance.id) }}">edit</a> |
<a href="{{ url_for('delete_[[ name|camel_to_snake ]]', uuid=instance.id) }}">delete</a>

View File

@ -1,6 +1,3 @@
<h2>[[ name|pluralize ]]</h2>
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">Create</a>
<br>
{% for instance in instances %}
<li>
<a href="{{ url_for('get_[[ name|camel_to_snake ]]', uuid=instance.id) }}">

View File

@ -0,0 +1,11 @@
{% for instance in instances %}
<li>
<a href="{{ url_for('get_[[ name|camel_to_snake ]]', uuid=instance.id) }}">
{% include "[[ name|camel_to_snake ]]/_title.html" %}</a>
|
[
<a href="{{ url_for('update_[[ name|camel_to_snake ]]', uuid=instance.id) }}">e</a> |
<a href="{{ url_for('delete_[[ name|camel_to_snake ]]', uuid=instance.id) }}">x</a>
]
</li>
{% endfor %}

View File

@ -1,4 +1,3 @@
<h2>Edit {% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
<form action="{{ url_for('update_[[ name|camel_to_snake ]]', uuid=instance.id) }}" method="post">
<input type="hidden" name="_next" value="{{ url_for('get_[[ name|camel_to_snake ]]', uuid=instance.id) }}"/>
[%- for column in columns %]

View File

@ -1,5 +1,6 @@
{% extends "layout.html" %}
{% block content %}
<h2>Create [[ name ]]</h2>
{% include "[[ name|camel_to_snake ]]/_create.html" %}
{% endblock %}

View File

@ -1,5 +0,0 @@
{% extends "layout.html" %}
{% block content %}
{% include "[[ name|camel_to_snake ]]/_edit.html" %}
{% endblock %}

View File

@ -1,5 +1,9 @@
{% extends "layout.html" %}
{% block content %}
<a href="{{ url_for('list_[[ name|camel_to_snake ]]', uuid=instance.id) }}">list</a> |
<h2>{% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
<a href="{{ url_for('update_[[ name|camel_to_snake ]]', uuid=instance.id) }}">edit</a> |
<a href="{{ url_for('delete_[[ name|camel_to_snake ]]', uuid=instance.id) }}">delete</a>
{% include "[[ name|camel_to_snake ]]/_get.html" %}
{% endblock %}

View File

@ -1,5 +1,8 @@
{% extends "layout.html" %}
{% block content %}
<h2>[[ name|pluralize ]]</h2>
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">Create</a>
<br>
{% include "[[ name|camel_to_snake ]]/_list.html" %}
{% endblock %}

View File

@ -0,0 +1,8 @@
{% extends "layout.html" %}
{% block content %}
<h2>Search results for [[ name|pluralize ]]</h2>
<a href="{{ url_for('create_[[ name|camel_to_snake ]]') }}">Create</a>
<br>
{% include "[[ name|camel_to_snake ]]/_search.html" %}
{% endblock %}

View File

@ -0,0 +1,6 @@
{% extends "layout.html" %}
{% block content %}
<h2>Edit {% include "[[ name|camel_to_snake ]]/_title.html" %}</h2>
{% include "[[ name|camel_to_snake ]]/_update.html" %}
{% endblock %}

View File

@ -1,4 +1,4 @@
from oshipka.persistance import db, ModelController
from oshipka.persistance import db, ModelController, index_service
[%- if imports %]
[%- for import in imports %]
@ -11,3 +11,7 @@ from oshipka.persistance import db, ModelController
[%- else %]
[% include "_model_py" %]
[%- endif %]
[%- if searchable %]
index_service.searchables.append([[ name ]])
[%- endif %]

View File

@ -9,39 +9,9 @@ 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,
)
ModelView(app, [[name]]).register_get(view_context=get_view_context)
ModelView(app, [[name]]).register_list(view_context=list_view_context)
ModelView(app, [[name]]).register_search(view_context=search_view_context)
ModelView(app, [[name]]).register_create(view_context=create_view_context)
ModelView(app, [[name]]).register_update(view_context=update_view_context)
ModelView(app, [[name]]).register_delete(view_context=delete_view_context)