Skip to content

Optimize relationship loading

When dealing with any kind of relationship in your models, be it One-To-Many, Many-To-One or Many-To-Many, SQLAdmin will load related models in your edit page.

For example if we have the following model definition:

class Parent(Base):
    __tablename__ = "parent_table"

    id = mapped_column(Integer, primary_key=True)
    children = relationship("Child", back_populates="parent")


class Child(Base):
    __tablename__ = "child_table"

    id = mapped_column(Integer, primary_key=True)
    parent_id = mapped_column(ForeignKey("parent_table.id"))
    parent = relationship("Parent", back_populates="children")

When we are editing a Parent object in the Admin, there will be an HTML select option which loads all possible Child objects to be selected.

This is fine for small projects, but if you more than a few hundred records in your tables, it will be very slow and inefficient. Practically for each request to the Edit page, all records of Child table will be loaded.

In order to solve this you can use Form options available in configuration.

You have a few options to improve this:

Using form_ajax_refs

Instead of loading all the Child objects when editing a Parent object, you can use form_ajax_refs to load Child objects with an AJAX call:

class ParentAdmin(ModelView, model=Parent):
    form_ajax_refs = {
        "children": {
            "fields": ("id",),
            "order_by": "id",
        }
    }

This will allow you to search Child objects using the id field while also ordering the results.

Using form_columns or form_excluded_columns

Another option, which is not as useful as the previous one, is that you might not need the relationship children to be edited for your Pranet objects.

In that case you can just exclude that or specifically include the columns which should be available in the form.

class ParentAdmin(ModelView, model=Parent):
    form_excluded_columns = [Parent.children]

Using form_edit_query to customize the edit form data

If you would like to fully customize the query to populate the edit object form, you may override the form_edit_query function with your own SQLAlchemy query. In the following example, overriding the default query will allow you to filter relationships to show only related children of the parent.

class ParentAdmin(ModelView, model=Parent):
    def form_edit_query(self, request: Request) -> Select:
        parent_id = request.path_params["pk"]
        return (
            self._stmt_by_identifier(parent_id)
            .join(Child)
            .options(contains_eager(Parent.children))
            .filter(Child.parent_id == parent_id)
        )