Simon
Simon

Reputation: 41

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": "[email protected]"}
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.

Upvotes: 0

Views: 113

Answers (1)

Simon
Simon

Reputation: 41

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"))

Upvotes: 0

Related Questions