m_n create/update works UNLESS update is none

This commit is contained in:
Daniel Tsvetkov 2020-06-08 12:19:28 +02:00
parent a567739eaf
commit 4ef7da556c
8 changed files with 105 additions and 19 deletions

View File

@ -48,6 +48,16 @@
font-family: Open Sans, Arial sans-serif; font-family: Open Sans, Arial sans-serif;
font-size: 1em; font-size: 1em;
box-sizing: border-box; box-sizing: border-box;
min-width: 300px;
}
input[type=number] {
min-width: 70px;
width: 70px;
}
select {
min-width: 300px;
} }
.full-width { .full-width {

View File

@ -1,3 +1,4 @@
import importlib
from functools import wraps from functools import wraps
import inflect import inflect
@ -6,15 +7,21 @@ from flask import flash, render_template, redirect, request, url_for, jsonify
from oshipka.persistance import db from oshipka.persistance import db
from oshipka.util.strings import camel_case_to_snake_case from oshipka.util.strings import camel_case_to_snake_case
webapp_models = importlib.import_module("webapp.models")
MODEL_VIEWS = dict() MODEL_VIEWS = dict()
def default_get_args_func(view_context): def default_get_args_func(view_context):
view_context.serialized_args = request.args view_context.serialized_args = request.args
def default_get_form_func(vc): def default_get_form_func(vc):
vc.redirect_next = request.form.get('_next') vc.redirect_next = request.form.get('_next')
vc.serialized_args = dict(filter(lambda k: not k[0].startswith("_"), dict(request.form).items())) for k in request.form:
if k.startswith('_m_n_'):
vc.serialized_args[k] = request.form.getlist(k)
vc.serialized_args.update(dict(filter(lambda k: not k[0].startswith("_"), dict(request.form).items())))
to_delete = [] to_delete = []
for key, value in vc.serialized_args.items(): for key, value in vc.serialized_args.items():
if key.endswith('_id'): if key.endswith('_id'):
@ -61,16 +68,43 @@ def default_search_func(vc):
vc.instances = vc.model_view.model.search_query("{q}".format(q=q)).all() vc.instances = vc.model_view.model.search_query("{q}".format(q=q)).all()
def _filter_m_n(vc):
m_ns, to_delete = {}, []
for k in vc.serialized_args:
if k.startswith('_m_n_'):
m_n_name = k.split('_m_n_')[1]
m_ns[m_n_name] = vc.serialized_args[k]
to_delete.append(k)
for key in to_delete:
del vc.serialized_args[key]
return m_ns
def _update_m_ns(vc, m_ns):
instance = vc.instance
for key, ids in m_ns.items():
child_rel = getattr(vc.instance, "_m_n_table_{}".format(key))
child_table = getattr(webapp_models, child_rel)
children = db.session.query(child_table).filter(child_table.id.in_(ids)).all()
setattr(instance, key, children)
def default_create_func(vc): def default_create_func(vc):
m_ns = _filter_m_n(vc)
instance = vc.model_view.model(**vc.serialized_args) instance = vc.model_view.model(**vc.serialized_args)
db.session.add(instance) vc.instance = instance
vc.instances = [instance] vc.instances = [instance]
_update_m_ns(vc, m_ns)
db.session.add(instance)
def default_update_func(vc): def default_update_func(vc):
m_ns = _filter_m_n(vc)
instance = vc.instances[0] instance = vc.instances[0]
vc.instance = instance
for k, v in vc.serialized_args.items(): for k, v in vc.serialized_args.items():
setattr(instance, k, v) setattr(instance, k, v)
_update_m_ns(vc, m_ns)
db.session.add(instance) db.session.add(instance)

View File

@ -1,9 +1,13 @@
[%- if not column.secondary %] [%- if not column.multiple %]
[[ column.name ]]_id = db.Column(db.Integer, db.ForeignKey('[%- if column.to %][[ column.to|camel_to_snake ]][%- else %][[ column.name ]][% endif %].id')) [[ column.name ]]_id = db.Column(db.Integer, db.ForeignKey('[%- if column.to %][[ column.to|camel_to_snake ]][%- else %][[ column.name ]][% endif %].id'))
[%- endif %] [%- endif %]
[[ column.name|pluralize if column.secondary else column.name ]] = db.relationship('[%- if column.to %][[ column.to ]][%- else %][[ column.name|snake_to_camel ]][% endif %]', [[ column.name|pluralize if column.multiple else column.name ]] = db.relationship('[%- if column.to %][[ column.to ]][%- else %][[ column.name|snake_to_camel ]][% endif %]',
[%- if column.secondary %]secondary=[[ column.secondary ]], [%- endif %] [%- if column.multiple %]secondary=[[ column.secondary.name ]], [%- endif %]
backref=db.backref("[%- if column.backref %][[ column.backref ]][%- else %][[ name|camel_to_snake|pluralize ]][%- endif %]"), backref=db.backref("[%- if column.backref %][[ column.backref ]][%- else %][[ name|camel_to_snake|pluralize ]][%- endif %]"),
[%- if column.foreign_keys %]foreign_keys=[ [[ column.foreign_keys ]]_id],[%- endif %] [%- if column.foreign_keys %]foreign_keys=[ [[ column.foreign_keys ]]_id],[%- endif %]
) )
[%- if column.multiple %]
_m_n_table_[[ column.name|pluralize ]] = '[%- if column.to %][[ column.to ]][%- else %][[ column.name|snake_to_camel ]][% endif %]'
[%- endif %]

View File

@ -3,13 +3,22 @@
[%- for column in columns %] [%- for column in columns %]
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>: <label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>:
[%- if column.type in ['relationship'] %] [%- if column.type in ['relationship'] %]
<select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]" [%- if column.secondary %]multiple[%- endif %] <select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]" [%- if column.multiple %]multiple
name="[[ column.name ]]_id"> name="_m_n_[[ column.name|pluralize ]]"[% else %]name="[[ column.name ]]_id"[%- endif %]>
[%- if not column.secondary %]
<option selected="selected">Choose...</option> <option selected="selected">Choose...</option>
[%- endif %]
{%- for sub_instance in model_views.[[ column.name ]].model.query.all() %} {%- for sub_instance in model_views.[[ column.name ]].model.query.all() %}
<option value="{{ sub_instance.id }}" {% if instance and instance.id == sub_instance.id %}selected="selected"{% endif %}>{{ sub_instance.name }}</option> <option value="{{ sub_instance.id }}" {% if instance and instance.id == sub_instance.id %}selected="selected"{% endif %}>{{ sub_instance.name }}</option>
{%- endfor %} {%- endfor %}
</select> </select>
[%- elif column.type in ['choice', ] %]
<select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
name="[[ column.name ]]_id">
[%- for value, display in column.choices.items() %]
<option value="[[ value ]]" {% if instance and instance.[[ column.name ]] == "[[ value ]]" %}selected="selected"{% endif %}>[[ display ]]</option>
[%- endfor %]
</select>
[%- elif column.type in ['number', 'int', 'integer', ] %] [%- elif column.type in ['number', 'int', 'integer', ] %]
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]" <input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
type="number" name="[[ column.name ]]" type="number" name="[[ column.name ]]"
@ -19,6 +28,7 @@
type="text" name="[[ column.name ]]" autocomplete="off" type="text" name="[[ column.name ]]" autocomplete="off"
/> />
[%- endif %] [%- endif %]
<br>
[%- endfor %] [%- endfor %]
<input type="submit"> <input type="submit">
</form> </form>

View File

@ -6,7 +6,11 @@
<source src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" type="video/webm"> <source src="{{ url_for('oshipka_bp.get_media', filepath=instance.[[ column.name ]]) }}" type="video/webm">
</video> </video>
[%- elif column.type in ['relationship'] %] [%- elif column.type in ['relationship'] %]
[%- if column.multiple %]
<li id="display-[[ name|camel_to_snake ]]-[[ column.name|pluralize ]]"><strong>[[ column.name|pluralize ]]</strong>: {{ instance.[[ column.name|pluralize ]] }}</li>
[%- else %]
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]] }}</li> <li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]] }}</li>
[%- endif %]
[%- else %] [%- else %]
<li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]] }}</li> <li id="display-[[ name|camel_to_snake ]]-[[ column.name ]]"><strong>[[ column.name ]]</strong>: {{ instance.[[ column.name ]] }}</li>
[%- endif %] [%- endif %]

View File

@ -14,7 +14,17 @@
<tr> <tr>
[%- for column in columns %] [%- for column in columns %]
{% if "[[ column.name ]]" not in skip_columns %} {% if "[[ column.name ]]" not in skip_columns %}
<td>{{ instance.[[ column.name ]] }}</td> <td>
[%- if column.type in ['relationship'] %]
[%- if column.multiple %]
{{ instance.[[ column.name|pluralize ]] }}
[%- else %]
{{ instance.[[ column.name ]] }}
[%- endif %]
[%- else %]
{{ instance.[[ column.name ]] }}
[%- endif %]
</td>
{% endif %} {% endif %}
[%- endfor %] [%- endfor %]
<td> <td>

View File

@ -4,12 +4,23 @@
<label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>: <label for="input-[[ name|camel_to_snake ]]-[[ column.name ]]">[[ column.name ]]</label>:
[%- if column.type in ['relationship'] %] [%- if column.type in ['relationship'] %]
<select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]" <select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
name="[[ column.name ]]_id"> [%- if column.multiple %]multiple name="_m_n_[[ column.name|pluralize ]]"[% else %]name="[[ column.name ]]_id"[%- endif %]>
{%- for sub_instance in model_views.[[ column.name ]].model.query.all() %} {%- for sub_instance in model_views.[[ column.name ]].model.query.all() %}
<option value="{{ sub_instance.id }}" <option value="{{ sub_instance.id }}"
[%- if column.multiple %]
{% if sub_instance in instance.[[ column.name|pluralize ]] %}selected="selected"{% endif %}>{{ sub_instance.name }}</option>
[%- else %]
{% if instance.[[ column.name ]]_id == sub_instance.id %}selected="selected"{% endif %}>{{ sub_instance.name }}</option> {% if instance.[[ column.name ]]_id == sub_instance.id %}selected="selected"{% endif %}>{{ sub_instance.name }}</option>
[%- endif %]
{%- endfor %} {%- endfor %}
</select> </select>
[%- elif column.type in ['choice', ] %]
<select id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
name="[[ column.name ]]_id">
[%- for value, display in column.choices.items() %]
<option value="[[ value ]]" {% if instance.[[ column.name ]] == "[[ value ]]" %}selected="selected"{% endif %}>[[ display ]]</option>
[%- endfor %]
</select>
[%- elif column.type in ['number', 'int', 'integer', ] %] [%- elif column.type in ['number', 'int', 'integer', ] %]
<input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]" <input id="input-[[ name|camel_to_snake ]]-[[ column.name ]]"
value="{{ instance.[[ column.name ]] }}" value="{{ instance.[[ column.name ]] }}"
@ -21,6 +32,7 @@
type="text" name="[[ column.name ]]" autocomplete="off" type="text" name="[[ column.name ]]" autocomplete="off"
/> />
[%- endif %] [%- endif %]
<br>
[%- endfor %] [%- endfor %]
<input type="submit"> <input type="submit">
</form> </form>

View File

@ -24,14 +24,15 @@ def _process_choice(column):
} }
def process_secondary(secondary): def process_secondary(view_model, column_name):
col1, col2 = secondary.split('_') model_name = camel_case_to_snake_case(view_model.get('name'))
secondary = "{}__{}".format(model_name, column_name)
return { return {
'name': secondary, 'name': secondary,
'columns': [{ 'columns': [{
'name': col1 'name': model_name
}, { }, {
'name': col2 'name': column_name
}] }]
} }
@ -49,11 +50,12 @@ def enrich_view_model(view_model):
_column_type = 'db.Boolean' _column_type = 'db.Boolean'
elif column_type in ['relationship', ]: elif column_type in ['relationship', ]:
_column_type = 'relationship' _column_type = 'relationship'
secondary = column.get('secondary') multiple = column.get('multiple')
if secondary: if multiple:
if '_secondaries' not in view_model: if '_secondaries' not in view_model:
view_model['_secondaries'] = [] view_model['_secondaries'] = []
secondary_model = process_secondary(secondary) secondary_model = process_secondary(view_model, column_name)
column.update({'secondary': secondary_model})
view_model['_secondaries'].append(secondary_model) view_model['_secondaries'].append(secondary_model)
elif column_type in ['choice', ]: elif column_type in ['choice', ]:
if '_choice_types' not in view_model: if '_choice_types' not in view_model: