postgresqlflask-admin

How to show a JSON value in Flask-Admin as separate fields?


Hi Stackoverflow community,

I'm trying to learn Flask-Admin. The documentation is a very good start, however I've found a very specific use-case that I'm not able to resolve. I have a table in PostgreSQL for variables. I've chosen for this approach since I've got quite a lot of variables but they don't share the same attributes (for example, the region doesn't have the property email).

Variable Value
User1 {"name": "Name", "email": "test@example.com"}
Region1 {"region": "Europe", "name": "DHL", "color": "blue"}

I'd like to have the functionality that the end-user can edit the variables themselves. They don't have any knowledge about JSON of course so it would be nice to render out the fields. Currently it's one field where the JSON value is. It would be perfect if there's a field for every item in the edit view in Flask-Admin. For example this would mean that editing the User1 variable shows 2 fields, one for name and one for email.


Solution

  • Finally found a solution after months!

    Variable = Base.classes.variables
    
    class VariableView(ModelView):
        list_columns = ["variable", "value"]
        form_columns = ["variable", "value"]
        column_default_sort = ("variable", False)
        column_filters = ["variable"]
        column_sortable_list = ["variable"]
        column_searchable_list = ["variable"]
        column_formatters = {
            "variable": lambda view, context, model, name: model.variable.replace(
                "_", " "
            ).capitalize(),
        }
        def edit_form(self, obj):
            class VariableForm(FlaskForm):
                pass
    
            setattr(
                VariableForm,
                "variable",
                StringField("Variable", validators=[Optional()], default=obj.variable),
            )
            try:
                json_data = json.loads(obj.value)
                for key in json_data:
                    setattr(
                        VariableForm,
                        key,
                        StringField(
                            key.capitalize(),
                            validators=[Optional()],
                            default=json_data[key],
                            ),
                        )
            except json.decoder.JSONDecodeError:
                setattr(
                    VariableForm,
                    "Value",
                    StringField("Label", validators=[Optional()], default=obj.value),
                )
            return VariableForm(obj=obj)
    
        def on_model_change(self, form, model, is_created):
            # Update the model with the data from the form
            json_output = {}
            for field in form:
                if field.name == "value":
                    return model
                if field.name != "variable" and field.name != "csrf_token":
                    json_output[field.name] = field.data
            model.value = json.dumps(json_output)
            return model
    
    admin.add_view(VariableView(Variable, user.session, name="Variables"))