Skip to content

Commit

Permalink
implement allow_frozen_fields and excluded_frozen_fields
Browse files Browse the repository at this point in the history
Setting `allow_frozen_fields` to True adds another button
to the create and the edit view which acts like
"Save and Add Another", but "freezes" the fields (i.e.,
doesn't reset their contents).

`excluded_frozen_fields` can be used to specify fields
which should always be cleared (e.g., password fields).

Previous to this commit, `freeze_fields` has been introduced
for this purpose. It has now been removed due to being
replaced with the aforementioned two new properties.
  • Loading branch information
falko17 committed Aug 10, 2022
1 parent 84e9dbe commit 6ac7c65
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 8 deletions.
6 changes: 4 additions & 2 deletions doc/api/mod_model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
form_overrides, action_disallowed_list,
form_widget_args, form_extra_fields,
form_ajax_refs, form_create_rules,
form_edit_rules, freeze_fields
form_edit_rules,
allow_frozen_fields, exclude_frozen_fields
page_size, can_set_page_size

.. autoattribute:: can_create
Expand Down Expand Up @@ -55,7 +56,8 @@
.. autoattribute:: form_create_rules
.. autoattribute:: form_edit_rules

.. autoattribute:: freeze_fields
.. autoattribute:: allow_frozen_fields
.. autoattribute:: exclude_frozen_fields

.. autoattribute:: action_disallowed_list

Expand Down
55 changes: 49 additions & 6 deletions flask_admin/model/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -732,9 +732,29 @@ class MyModelView(ModelView):
Customized rules for the create form. Override `form_rules` if present.
"""

freeze_fields = False
allow_frozen_fields = False
"""
Keep field contents when clicking on "Save and Add Another".
If true, renders an additional button in the create and edit form which
acts like "Save and Add Another", but keeps ("freezes") field contents
instead of clearing them.
Fields in `excluded_frozen_fields` will never be frozen.
"""

excluded_frozen_fields = []
"""
If `allow_frozen_fields` is set to `True` and the user clicks on
the corresponding button, only fields whose name is not included
in this list will be frozen.
In other words, add any fields here which shall be cleared even if the user
clicks on "Save And Add Another (Freeze Fields)", such as password fields.
Example::
class MyModelView(BaseModelView):
excluded_frozen_fields = ('password', 'confirm_password')
"""

# Actions
Expand Down Expand Up @@ -848,6 +868,10 @@ def _refresh_forms_cache(self):
else:
self.column_editable_list = {}

# Initialize frozen fields
if not hasattr(self, "_saved_frozen_fields"):
self._saved_frozen_fields = None

def _refresh_filters_cache(self):
self._filters = self.get_filters()

Expand Down Expand Up @@ -2088,17 +2112,28 @@ def create_view(self):
if not hasattr(form, '_validated_ruleset') or not form._validated_ruleset:
self._validate_form_instance(ruleset=self._form_create_rules, form=form)

# handle frozen fields, coming from an edit form
if self._saved_frozen_fields:
for (field, data) in self._saved_frozen_fields.items():
getattr(form, field).data = data
self._saved_frozen_fields = None

if self.validate_form(form):
# in versions 1.1.0 and before, this returns a boolean
# in later versions, this is the model itself
model = self.create_model(form)
if model:
flash(gettext('Record was successfully created.'), 'success')
if '_add_another' in request.form:
# if the content of the fields should remain, we don't redirect.
# this way the model is created without changing page contents.
if not self.freeze_fields:
return redirect(request.url)
return redirect(request.url)
elif '_freeze_fields' in request.form and self.allow_frozen_fields:
# we need to do is reset the excluded fields and then persist
# the frozen fields.
for field in self.excluded_frozen_fields:
if field in form.data:
getattr(form, field).data = ""
self._saved_frozen_fields = form.data
return redirect(request.url)
elif '_continue_editing' in request.form:
# if we have a valid model, try to go to the edit view
if model is not True:
Expand Down Expand Up @@ -2152,6 +2187,14 @@ def edit_view(self):
flash(gettext('Record was successfully saved.'), 'success')
if '_add_another' in request.form:
return redirect(self.get_url('.create_view', url=return_url))
elif '_freeze_fields' in request.form and self.allow_frozen_fields:
# we simply don't redirect here, which will cause the fields to
# stay as they are. All we need to do is reset the excluded fields.
for field in self.excluded_frozen_fields:
if field in form.data:
getattr(form, field).data = ""
self._saved_frozen_fields = form.data
return redirect(self.get_url('.create_view', url=return_url))
elif '_continue_editing' in request.form:
return redirect(request.url)
else:
Expand Down
3 changes: 3 additions & 0 deletions flask_admin/templates/bootstrap2/admin/lib.html
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ <h3>{{ text }}</h3>
{% if admin_view.can_create %}
<input name="_add_another" type="submit" class="btn" value="{{ _gettext('Save and Add Another') }}" />
{% endif %}
{% if admin_view.can_create and admin_view.allow_frozen_fields %}
<input name="_freeze_fields" type="submit" class="btn" value="{{ _gettext('Save and Add Another (Freeze Fields)') }}" />
{% endif %}
{% if admin_view.can_edit %}
<input name="_continue_editing" type="submit" class="btn" value="{{ _gettext('Save and Continue Editing') }}" />
{% endif %}
Expand Down
3 changes: 3 additions & 0 deletions flask_admin/templates/bootstrap3/admin/lib.html
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ <h3>{{ text }}</h3>
{% if admin_view.can_create %}
<input name="_add_another" type="submit" class="btn btn-default" value="{{ _gettext('Save and Add Another') }}" />
{% endif %}
{% if admin_view.can_create and admin_view.allow_frozen_fields %}
<input name="_freeze_fields" type="submit" class="btn btn-default" value="{{ _gettext('Save and Add Another (Freeze Fields)') }}" />
{% endif %}
{% if admin_view.can_edit %}
<input name="_continue_editing" type="submit" class="btn btn-default" value="{{ _gettext('Save and Continue Editing') }}" />
{% endif %}
Expand Down
3 changes: 3 additions & 0 deletions flask_admin/templates/bootstrap4/admin/lib.html
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,9 @@ <h3>{{ text }}</h3>
{% if admin_view.can_create %}
<input name="_add_another" type="submit" class="btn btn-secondary" value="{{ _gettext('Save and Add Another') }}" />
{% endif %}
{% if admin_view.can_create and admin_view.allow_frozen_fields %}
<input name="_freeze_fields" type="submit" class="btn btn-secondary" value="{{ _gettext('Save and Add Another (Freeze Fields)') }}" />
{% endif %}
{% if admin_view.can_edit %}
<input name="_continue_editing" type="submit" class="btn btn-secondary" value="{{ _gettext('Save and Continue Editing') }}" />
{% endif %}
Expand Down
Binary file modified flask_admin/translations/de/LC_MESSAGES/admin.mo
Binary file not shown.
5 changes: 5 additions & 0 deletions flask_admin/translations/de/LC_MESSAGES/admin.po
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,11 @@ msgstr "Abbrechen"
msgid "Save and Add Another"
msgstr "Speichern und neuer Eintrag"

#: ../flask_admin/templates/bootstrap2/admin/lib.html:263
#: ../flask_admin/templates/bootstrap3/admin/lib.html:254
msgid "Save and Add Another (Freeze Fields)"
msgstr "Speichern und neuer Eintrag (Felder einfrieren)"

#: ../flask_admin/templates/bootstrap2/admin/lib.html:259
#: ../flask_admin/templates/bootstrap3/admin/lib.html:250
msgid "Save and Continue Editing"
Expand Down

0 comments on commit 6ac7c65

Please sign in to comment.