Redirect to external link from the layout function

Hi guys!

So as we know when we use the dash pages
in each page we have a layout function (it can be a variable but in my case I need a function)
now I get an argument of id in the layout function and I need to check if the id is a number if not I want to redirect the user to an external 404 page

if not plan_id.isnumeric():
    abort(404)

any idea how I can do this?
(tried using the flask abort and redirect functions doesn’t work)

Hello @Matan,

Can you give an MRE of what you tried?

Could you try tacking it into your function where you check before_request criteria?

It’s on another network so that would be a challenge let’s see if we can figure this out without an MRE.

I have a page where in the URL you are supposed to get an id
localhost:8080/great-app/5
5 is the id

def layout(plan_id):
    if not plan_id.isnumeric():
        abort(404) # Try 1 The redirect and abort is two different things I tried 
        redirect('external url') # Try 2 # And didn't work

now the function where I check before_request For some reason dash calls the before_request every second so except from my sso check that I have no other way to do it I try to avoid the decorator

When debug=‘True’, dash will fire the before_request because it checks to see if there are updates, due to hot_reload.

You can avoid that by checking to see if the request.method != 'POST':. This would catch when there is a GET request.

Another thing you could do, is just have a fallback to where it loads a default / error message in the layout.

It happens when the debug=False
also calls the function with GET not POST every time .

and yes I can do the default / error message instead but my boss asks me to redirect it to the 404 page they made in a django app so no can do.

Weird, it shouldn’t be calling it that often with straight get requests.

Do you have n_intervals?

No, not even one in the entire project

Can you print what the url is for the get requests?

http://localhost:8080/page1/main/_reload-hash

Also @jinnyzor If I go to another page through dcc link when I printed the URLs in the before_request it didn’t print the new URL just the update-component, reload-hash, graph.js and so on no where can I get the URL with the argument in the before_request

Hmm, something’s not right with that… Also, if you are running with debug false, it sounds like you have a browser open when you were testing…

Can you show your before_request function?

it does this even if my function is

@server.before_request
def requestCheck():
    print(request.url)

And I had only one browser open and only one tab of the app

Where is this before_request registered?

Before or after the app=Dash(__name__)?

tried before and after I get the same result

@jinnyzor I made a bit of progress but I am still stuck.
I found out how to get the last part of the URL check if it’s a number and try to redirect the page but I get a Redirect is not allowed for a preflight request.

@server.before_request
def requestCheck():
    if request.method == 'GET' and request.referrer is not None:
        referrer = request.referrer.split('/')
        if referrer[-3] == 'page1' and referrer[-2] == 'main':
            if referrer[-1] and not referrer[-1].isnumeric():
                return redirect(external link)

let’s say I have the link
localhost:8080/page1/main/5f
the last part 5f is not a number so its suppose to redirect to the external link but I get the error above

@Matan,

I got this to work by adding it before the app.

image
image

from dash import Dash, html, dcc
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import numpy as np
import json
from flask import Flask, request

server = Flask(__name__)

@server.before_request
def requestCheck():
    print(request.url)

app = Dash(__name__, server=server)


df_pivot = np.array(np.linspace(0, 100, 100)).reshape(10, 10)
fig = px.imshow(
    df_pivot,
    color_continuous_scale=px.colors.sequential.Agsunset,
)


app.layout = html.Div(
    children=[
        dbc.Row(
            [
                dcc.Graph(
                    id="plot",
                    figure=fig,
                ),
            ]
        ),
        html.Div(id="selected-data"),
    ]
)


@app.callback(
    Output("selected-data", "children"),
    Input("plot", "clickData"),
)
def display_selected_data(selected_data):
    return json.dumps(selected_data, indent=2)


if __name__ == "__main__":
    app.run_server(debug=True)

Not sure why you cant get the browsed to location.

I can’t get the URL if I go to another page through a dcc link.
If I reload my page with f5 I get it, but I need to get it with the dcc link too.

Hmm, yeah, I see the issue.

The problem with the referrer bit is that it uses post requests to figure it out, which are a bit of a chore to get into and redirect from there.

You could use a dcc.Location and update the location upon non-numeric id.

I am using dash pages, I don’t want to switch to using dcc location instead, and start switching between pages using the URL instead of automatically with dash pages…