aminalaee / sqladmin

SQLAlchemy Admin for FastAPI and Starlette
https://aminalaee.dev/sqladmin/
BSD 3-Clause "New" or "Revised" License
1.85k stars 184 forks source link

Ajax query passes incorrect urn when admin mounted on sub fastapi app #741

Open infanasotku opened 6 months ago

infanasotku commented 6 months ago

Checklist

Describe the bug

Ajax request from browser doesn't consider urn which setted up by sub fastapi app.

Steps to reproduce the bug

1) Link admin to sub fastapi app:

from fastapi import FastApi
from sqladmin import Admin

app = FastApi()
subapp = FastApi()
app.mount('/suburn', subapp)

admin = Admin(subapp, base_url='/') 

2) Link any ModelView with relationship with admin which forces ajax request at select list on create page. 3) Click on select list on create page and try to type symbols.

Expected behavior

Ajax should request to uri as: .../suburn/ModelViewName/ajax/...

Actual behavior

Ajax request to uri: .../ModelViewName/ajax/... with skipping suburn.

P.S. Admin page routing is correct with sub app.

Debugging material

In my way: suburn='/admin' base_url='/'

[INFO] uvicorn.access: 127.0.0.1:64082 - "GET /admin/enterprise/list HTTP/1.1" 200
[INFO] uvicorn.access: 127.0.0.1:64082 - "GET /admin/enterprise/create HTTP/1.1" 200
[INFO] uvicorn.access: 127.0.0.1:64082 - "GET /enterprise/ajax/lookup?name=company&term=2 HTTP/1.1" 404

Environment

OS: MacOS 14.4.1

Python: 3.11.8

sqladmin==0.16.1 fastapi==0.110.1

Additional context

I understand that suburn not passed to template ajax, but all another routing work correctly - it confused me. (I think that we need additional param like sub_url separatly off base_url to specific behavior.)

IBestuzhev commented 4 months ago

I encountered a very similar issue: we use FastAPI.root_path parameter because app is running behind a proxy.

I think the most correct way is to rely on FastAPI resolver - call fastapi.Request.url_for.

Meanwhile, I did a quick workaround in my project:

        admin = Admin(
            app,
            engine,
            authentication_backend=auth_backend,
            base_url='/admin-ui',
        )
        admin.add_view(view)
        if view.is_model and app.root_path:
            # This URL goes directly into template into Select2 widget
            # With current code (sqladmin 0.16.1) it goes as is
            # The URL will be: /admin-ui/my-model/ajax/lookup
            # But the correct one for production is prefixed
            # /proxy-prefix/admin-ui/my-model/ajax/lookup
            view.ajax_lookup_url = app.root_path + view.ajax_lookup_url
infanasotku commented 4 months ago

@IBestuzhev yes, it works.

aminalaee commented 4 months ago

@IBestuzhev But the Request.url_for is not available in this context.