pallets-eco/flask-admin

Creating custom views for BaseView grouped in a category and passing an id

Acrofil opened this issue · 1 comments

Hi, i try to achieve something that should be simple to do but i cant.

class ObjectDataView(BaseView):
    @expose('/')
    def index(self):
        return self.render('path/to/index.html')
    
    @expose('/<int:object_id>/')
    def object_data(self, object_id):
        object = Objects.query.get(object_id)
        return self.render('path/to/object_render_data.html', object=object')

# Get all objects and group them under 1 category
# Each object then will get his own page where we render the data it contains
objects = Objects.query.all()
for object in objects:
    admin.add_view(ObjectDataView(name=object.name,
                            category='Objects',
                            endpoint=f'object_data/{object.id}',
                            url=f'object_data/{object.id}',)

With the code above, what I achieve is:
Category is created with all objects and when I select any I get routed to:
http://127.0.0.1:5000/admin/object_data/99/ (or any other ID from the selected in the dropdown)/ which renders the index.html
if I manually edit the URL to include another ID:
http://127.0.0.1:5000/admin/object_data/99/99/ - I get routed to object_render_data.html Which is what i want to achieve in the first place.

If i change the url url='object_data' i get redirected again to the index and if i add manually the object id object_data/99 i will go to the page i want.

I also tried creating them as menu links. Then I get to the specified route and receive the id, but then if i want to extend the flask admin template, I can't and i dont really want to do it that way.

custom_bp = Blueprint('custom_bp', __name__)

@custom_bp.route("/admin/custom_route/<int:object_id>", methods=['GET', 'POST'])
def room_availability_test(object_id):
    return render_template('path/to/object_render_data.html')

admin.add_link(MenuLink(name=...., 
category=...., 
url=f'custom_route/{object.id}

What I am missing or doing wrong?
Any help appreciated!
Thanks!

It looks like you're creating an data view for each individual object - you don't need to do this. You create a single object data view, and it will work for any instance of your Object class.

Note: untested code, but should be about right.

class ObjectDataView(BaseView):
    @expose('/')
    def index(self):
        return self.render('path/to/index.html')
    
    @expose('/<int:object_id>/')
    def object_data(self, object_id):
        object = Objects.query.get(object_id)
        return self.render('path/to/object_render_data.html', object=object)

admin.add_view(
    ObjectDataView(
        name='Objects',
        url=f'object_data/',
    )
)

It's possible you're intentionally doing what you're doing, in order to have a link for each specific object in the title bar, but I think this is probably not the right approach. Have you tried something more like what I've got above?