Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

flask_admin change inline_models behaviour

I want to change some existing Python code that uses flask_admin. One of the views uses inline_models with the (ClassName, Options) declaration pattern. The inlined class has, amongst others, a text field. I want to change the flask_admin default behaviour in the following ways:

  • I want to make the text field read-only. I.e. still display it, but prevent the user from changing existing content.
  • I do not want to allow users to delete instances of the inlined class, i.e. I want to get rid of the "Delete?" checkbox next to every entry.
  • I want to override the default "Add Item" button behaviour with some custom JavaScript.

I did some Googling around but anything that looked potentially promising also looked very non-trivial. I'm hoping for some reasonably straight forward way to achieve this.

Your help would be much appreciated.

like image 721
Carsten Avatar asked Sep 07 '25 02:09

Carsten


1 Answers

Yeesh. It looks like we're out in poorly-documented territory, here. It's hard to know if I'm improving on what you've already found, but I'll hope you're looking for something easier than writing a custom administrative view template.

  1. Following the calls, it looks like the options dictionary eventually gets passed to the constructor of InlineBaseFormAdmin where the various form_* keys are extracted and applied (not sure all are respected, but I see at least form_base_class, form_columns, form_excluded_columns, form_args, form_extra_fields, form_rules, form_label, form_column_labels, form_widget_args). I think you can accomplish what you need via form_widget_args, but you can probably also get there via form_rules or by overriding InlineBaseFormAdmin's get_form or postprocess_form methods:

    class SomeModelView(MyBaseModelView):
        ...
        inline_models = [(db.SomeOtherModel, {
            "form_widget_args": {
                "uneditable_field_name": {"readonly": True}
            }
        })]
        ...
    
  2. The delete option can be controlled by providing your own inline form model to override display_row_controls:

    from flask_admin.contrib.sqla.form import InlineModelConverter
    from flask_admin.contrib.sqla.fields import InlineModelFormList
    
    class CrouchingTigerHiddenModelFormList(InlineModelFormList):
        def display_row_controls(self, field): return False
    
    class MyInlineModelConverter(InlineModelConverter):
        inline_field_list_type = CustomInlineModelFormList
    
    #adding to above example
    class SomeModelView(MyBaseModelView):
        ...
        inline_model_form_converter = MyInlineModelConverter
        inline_models = [(db.SomeOtherModel, {
            "form_widget_args": {
                "uneditable_field_name": {"readonly": True}
            }
        })]
        ...
    

    NOTE: The widget args, such as readonly, are getting passed on to wtforms as render_kw, but at a blush the WTForms docs aren't clear that these get expressed as attributes in the resulting HTML input element (so any HTML input element attributes are valid here).

  3. It looks like form.js controls this behavior, so you should be able to monkey-patch its addInlineField method to execute your own code before or after the model addition. You could override the create and/or edit templates for this--but if you're using flask-admin 1.5.0+, this might be as simple as adding extra_js = ["your-custom.js"] to the view class (caution: it looks like this script gets included on every page for this view).

like image 118
abathur Avatar answered Sep 10 '25 11:09

abathur