Search code examples
pythonflaskflask-sqlalchemyflask-admin

Displaying joined fields in Flask-Admin ModelView


I have a Flask app using Flask-SQLAlchemy with some simple relational data mapping, e.g. between Orders and OrderItems belonging to those orders.

In my Flask-Admin backend I would like to show some of the order attributes in the list of OrderItems — as opposed to having the entire order object. E.g. make the "Order.email" listed (can be read-only) in the OrderItems' rows.

I've looked into the inline_models attribute of the ModelView, but this seems to be more feared towards actually editing the relational object — I just want to display (and sort/search by) some value of the "parent".

Is there a way to achieve this?


Solution

  • You can easily include fields via a foreign key relationship by including them in column_list value - documentation. Consider the two simplified models, note the company back reference in the Address model:

    class Company(db.Model):
        __tablename__ = 'companies'
    
        id = db.Column(db.Integer, primary_key=True)
        name = db.Column(db.Unicode(255), nullable=False, unique=True, index=True)
        website = db.Column(db.Unicode(255), nullable=True)
        notes = db.Column(db.UnicodeText())
    
        @hybrid_property
        def address_count(self):
            return len(self.addresses)
    
        @address_count.expression
        def address_count(cls):
            return select([func.count(Address.id)]).where(Address.company_id == cls.id).label("address_count")
    
    
        def __str__(self):
            return self.name
    
    
    class Address(db.Model):
        __tablename__ = 'addresses'
    
        id = db.Column(db.Integer, primary_key=True)
        address1 = db.Column(db.Unicode(255), nullable=False)
        town = db.Column(db.Unicode(255), index=True, nullable=False)
        county = db.Column(db.Unicode(255))
        country = db.Column(db.Unicode(255))
        post_code = db.Column(db.Unicode(10))
    
        company_id = db.Column(db.Integer, db.ForeignKey('companies.id'), index=True)
        company = db.relationship(Company, backref=db.backref('addresses', uselist=True, lazy='select', cascade='delete-orphan,all'))
    
    
        def __str__(self):
            return ', '.join(filter(None, [self.address1, self.town, self.county, self.post_code, self.country]))
    

    In the Address view you can access a "parent" company using dotted notation. For example:

    class AddressView(ModelAdmin):
    
        column_list = (
            'company.name',
            'company.website',
            'address1',
            'address2'
            )