Flask-admin: How to make read-only columns according to the value of other columns?

I created a system that allows users to apply for code verification and wait for the manager to approve.

And now I want to achieve, as shown below:

  • If approved enter image description here then all fields become read-only (I manually set the Project Name as read-only):

enter image description here

  1. If rejected ,

    enter image description here

    then all fields become editable . Of course, when creating a new project, all fields must be editable.
    enter image description here

    The code for the Project and ProjectView class is as follows:

      from flask_sqlalchemy import SQLAlchemy from flask_admin.contrib import sqla from flask_security import current_user # Create Flask application app = Flask(__name__) app.config.from_pyfile('config.py') db = SQLAlchemy(app) class Project(db.Model): id = db.Column(db.Integer, primary_key=True) project_name = db.Column(db.Unicode(128)) version = db.Column(db.Unicode(128)) SVN = db.Column(db.UnicodeText) approve = db.Column(db.Boolean()) def __unicode__(self): return self.name class ProjectView(sqla.ModelView): def is_accessible(self): if not current_user.is_active or not current_user.is_authenticated: return False return False @property def _form_edit_rules(self): return rules.RuleSet(self, self.form_rules) @_form_edit_rules.setter def _form_edit_rules(self, value): pass @property def _form_create_rules(self): return rules.RuleSet(self, self.form_rules) @_form_create_rules.setter def _form_create_rules(self, value): pass @property def form_rules(self): form_rules = [ rules.Field('project_name'), rules.Field('version'), rules.Field('SVN'), ] if not has_app_context() or current_user.has_role('superuser'): form_rules.append('approve') 

    In my opinion, since arguing is a logical variable , it should be to determine if it is 0 or 1, and then the field becomes read-only or edited accordingly.

    Thanks for any advice in advance.

+5
source share
3 answers

As you already noticed, the readonly property for a field is pretty simple , but making it dynamic is a bit tricky.

First of all, you need a custom field class:

 from wtforms.fields import StringField class ReadOnlyStringField(StringField): @staticmethod def readonly_condition(): # Dummy readonly condition return False def __call__(self, *args, **kwargs): # Adding `readonly` property to `input` field if self.readonly_condition(): kwargs.setdefault('readonly', True) return super(ReadOnlyStringField, self).__call__(*args, **kwargs) def populate_obj(self, obj, name): # Preventing application from updating field value # (user can modify web page and update the field) if not self.readonly_condition(): super(ReadOnlyStringField, self).populate_obj(obj, name) 

Set form_overrides for your view:

 class ProjectView(sqla.ModelView): form_overrides = { 'project_name': ReadOnlyStringField } 

You need to pass the custom function readonly_condition to the ReadOnlyStringField instance. The easiest way I've found is to override the edit_form method:

 class ProjectView(sqla.ModelView): def edit_form(self, obj=None): def readonly_condition(): if obj is None: return False return obj.approve form = super(ProjectView, self).edit_form(obj) form.project_name.readonly_condition = readonly_condition return form 

Happy coding!

+3
source

The previous answer I did was a major flaw. The following approach takes a different approach by analyzing the form itself and adding readonly: True to render_kw for a particular form if a certain condition is met.

 class ProjectView(sqla.ModelView): # ... other class code def edit_form(self, obj=None): # grab form from super form = super(ProjectView, self).edit_form(obj) # form.approved.data should be the same as approved # if approved is included in the form if form.approved.data: if form.project_name.render_kw: form.project_name.render_kw.update({ 'readonly': True }) else: form.project_name.render_kw = {'readonly': True} return form 

This is a bit hacked and requires approved be in the edit form. If you used this solution, you can either add approved as the readonly field, or instead of readonly you can remove the approved field from the form in the method above the class.

+1
source

For me, this trick was the easiest way:

 from flask_sqlalchemy import SQLAlchemy from flask_admin.contrib.sqla import ModelView from flask_admin.form.rules import Field class Example(db.Model): id = db.Column(db.Integer, primary_key=True) not_editable = db.Column(db.Unicode(128)) editable = db.Column(db.Unicode(128)) class ReadonlyFiledRule(Field): def __call__(self, form, form_opts=None, field_args={}): field_args['readonly'] = True return super(ReadonlyFiledRule, self).__call__(form, form_opts, field_args) class ExampleView(ModelView): form_edit_rules = (ReadonlyFiledRule('not_editable'), 'editable', ) 
+1
source

Source: https://habr.com/ru/post/1266341/


All Articles