# Redirect with different Query Strings

**URL:** <https://community.plotly.com/t/redirect-with-different-query-strings/75745>\
**Category:** Dash Python\
**Tags:** question\
**Created:** [June 1, 2023, 9:33am UTC](https://community.plotly.com/t/redirect-with-different-query-strings/75745 "2023-06-01T09:33:09Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![FirstNumberTwo](https://avatars.discourse-cdn.com/v4/letter/f/ea666f/32.png) [@FirstNumberTwo](https://community.plotly.com/u/FirstNumberTwo)\
**Post date:** [June 1, 2023, 9:33am UTC](https://community.plotly.com/t/redirect-with-different-query-strings/75745/1 "2023-06-01T09:33:09Z")

</div>

Hello Everyone 🙂 ,  
I am building a dashboard to get “general” data from a database. I would like to make it possible that when a user wants to view more details of a specific entry, he can click on a button and should be redirected to another details page. I use [Query Strings](https://dash.plotly.com/urls) on both the first and second page.

The problem now is the following: I cannot get from, for example,  
“**[http://127.0.0.1:8050/PageAlpha?keyA=valueX](http://127.0.0.1:8050/PageAlpha?keyA=valueX)**”  
to  
“**[http://127.0.0.1:8050/PageBeta?keyB=valueY](http://127.0.0.1:8050/PageBeta?keyB=valueY)**”.

I have already tried it with dozens of variants. To better understand my approach I also have a code example.

### app.py

```python
from dash import Dash, html, dcc
import dash

app = Dash(
    __name__ ,
    use_pages=True,
    suppress_callback_exceptions=True
)

app.layout = html.Div([
    html.H1('Multi-page app with Dash Pages'),

    html.Div(
        [
            html.Div(
                dcc.Link(
                    f"{page['name']} - {page['path']}", href=page["relative_path"]
                )
            )
            for page in dash.page_registry.values()
        ]
    ),

    dash.page_container
])

if __name__ == ' __main__':
    app.run_server(
        debug=True,
        port=8051,
    )

```

### home.py

```python
import urllib

import dash
from dash import html, dcc, callback, Input, Output, State

dash.register_page( __name__ , path='/')

def layout(options=False, **other_unknown_query_strings):

   return html.Div(
       children=[
           dcc.Location(id='currentLocation'),
           html.H1(children='Page Home'),
           html.Button(
               id='showFruitsButton',
               children='Show Fruits?',
           ),
           html.Div(id='showFruitsRedirectDiv'),
           html.Hr(),
           html.Div(
               children=[
                   html.P('Select Fruit'),
                   dcc.RadioItems(id='showOptionsRadioItems'),
                   html.Button('Show Fruit Details', id='goToFruitDetailsButton')
               ]
           ),
           html.Div(id='redirectToDetailsDiv')
       ]
   )

# Disable/Enable Buttons Logic
@callback(
   Output('showFruitsButton', 'disabled'),
   Output('goToFruitDetailsButton', 'disabled'),
   Input('currentLocation', 'search'),
   prevent_initial_call=False
)
def check_if_button_is_needed(search):
   # Convert '?options=True' to '{'options': ['True']}'
   param = urllib.parse.parse_qs(urllib.parse.urlparse(search).query)
   # This means basically:
   # If 'a URL-Parameter Exists':
   # 'return this Parameter'
   # else:
   # 'return False'
   showFruitsButton_bool = eval(param['options'][0]) if bool(param) else False
   goToFruitDetailsButton_bool = not showFruitsButton_bool

   return showFruitsButton_bool, goToFruitDetailsButton_bool

# Set URL Parameter: options
@callback(
   Output('showFruitsRedirectDiv', 'children'),
   Input('showFruitsButton', 'n_clicks'),
   prevent_initial_call=True
)
def show_fruits_redirect(button_click):
   return dcc.Location(
       id='someIdDoesntMatter',
       pathname='/',
       search='?options=True'
   )

# Listen to URL and do/don't show RadioButtons
@callback(
   Output('showOptionsRadioItems', 'options'),
   Output('showOptionsRadioItems', 'value'),
   Input('currentLocation', 'search'),
   prevent_initial_call=False
)
def show_options(search):
   if bool(search):
       if eval(urllib.parse.parse_qs(urllib.parse.urlparse(search).query)['options'][0]):
           # Example Data...
           database_response = ['Apple', 'Banana', 'Peach']
           return database_response, database_response[0]
   raise dash.exceptions.PreventUpdate

# Redirect to Detail-Page with URL-Parameter 'fruit'
@callback(
   Output('redirectToDetailsDiv', 'children'),
   Input('goToFruitDetailsButton', 'n_clicks'),
   State('showOptionsRadioItems', 'value'),
   prevent_initial_call=True
)
def redirect_details(n_clicks, selected_fruit):
   # Here is the Error...
   location = dcc.Location(
       id='someOtherId',
       pathname='/details',
       search='?fruit={}'.format(selected_fruit)
   )
   return location

```

### details.py

```python
import dash
from dash import html

dash.register_page(
   __name__ ,
   path='/details',
)

def layout(fruit='nothing', **other_unknown_query_strings):
   return html.Div(
       children=[
           html.H1(children='Archive'),
           html.P('Show details for {}'.format(fruit))
       ]
   )

```

It never changes the entire URL. Either only the “pathname” or “search” changes, depending on whether I comment out “search”. I have also tried to access “url” directly, but this usually ends in an unwanted loop. It also makes no difference if I change ‘pathname’ and ‘search’ from a dcc.Location in an output or return a whole dcc.Location in a div.

I’m running out of ideas. Can anyone help me?  
Thanks in advance.

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [June 1, 2023, 1:53pm UTC](https://community.plotly.com/t/redirect-with-different-query-strings/75745/2 "2023-06-01T13:53:02Z")

</div>

Hi @FirstNumberTwo and welcome to the Dash community 🙂

You should avoid using `eval` because it can introduce security risks. This could execute what someone typed in the URL

```auto
if eval(urllib.parse.parse_qs(urllib.parse.urlparse(search).query)['options'][0]):

```

For more information see:

> [@Writing Secure Dash Apps - Community Thread](https://community.plotly.com/t/writing-secure-dash-apps-community-thread/54619):
>
> Hey folks – Here’s a community thread to kick off security-related patterns & concerns when writing Dash apps. The Dash framework itself is architected in a way to avoid many security issues outright (like many XSS issues encountered when rendering arbitrary HTML) and our commercial Dash Enterprise platform provides strict security controls beyond the application code (with authorization, authentication, sandboxing apps in containers away from the host server, security audits, and more). Howe…

Since you are using Pages, you can do the navigation without adding any `dcc.Location` components to your app.

To disable/enable buttons and to update the options of the RadioItems, you can use a `dcc.Store` component rather than the `search` prop of a `dcc.Location`

Then to navigate to the details page, you can update the href prop of the `gotToFruitDetailButton`. That way, when the button is clicked, then Pages will automatically navigate to that page automatically - you don’t have to write that callback.

So your callback might look something like:

```auto
@callback(   
   Output('goToFruitDetailsButton', 'href'),
   Input('showOptionsRadioItems', 'value'),   
)
def redirect_details(selected_fruit):
   return f'/details?fruit={selected_fruit}'

```

You can see some examples in this repo. I recommend cloning it and running some of the examples so you can see it working. Example 10 shows navigating to a new page and using the query strings to show different details on the page. Examples 15 and 16 show how to navigate by updating buttons or links in a callback.

> **[GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page...](https://github.com/AnnMarieW/dash-multi-page-app-demos)**
>
> Minimal examples of multi-page apps using Dash Pages - GitHub - AnnMarieW/dash-multi-page-app-demos: Minimal examples of multi-page apps using Dash Pages

---

<div class="post-metadata">

**Author:** ![FirstNumberTwo](https://avatars.discourse-cdn.com/v4/letter/f/ea666f/32.png) [@FirstNumberTwo](https://community.plotly.com/u/FirstNumberTwo)\
**Post date:** [June 5, 2023, 10:23am UTC](https://community.plotly.com/t/redirect-with-different-query-strings/75745/3 "2023-06-05T10:23:15Z")

</div>

Hello @AnnMarieW,  
Thank you very much for the quick reply. The approach via href works 👍. It seems like a simple solution but I struggled with this for 3 days. I guess I had a Tunnel Vision 😅

> You should avoid using `eval` because it can introduce security risks. This could execute what someone typed in the URL

> To disable/enable buttons and to update the options of the RadioItems, you can use a `dcc.Store` component rather than the `search` prop of a `dcc.Location`

The button to deactivate should be an example for my app-structure. In my app, the user is supposed to enter something into an input field, gets Information with which he then can be forwarded to another page.

I initially took the input for all subcomponents from the InputField, but this quickly became messy. I didnt know the Store-Component until now. That’s why I keep the input as a parameter in the URL. This also has the advantage that users can send links to each other, where the search then starts automatically.

I see the problem when working with dropdown, radio buttons, etc. So the URL parameters offer unwanted selection possibilities. I don’t see any security concerns in my case (Correct me if Im wrong). Whether the user can enter via. URL or via. InputField should not matter for the time being. Each of my components just look at the URL and check the parameter if it exists and if it is valid. If both do not occur a PreventUpdate is simply raised.

However, your repo with the examples looks very helpful though. I will definitely have a closer look at it. Thanks a lot for your help!

---

<div class="post-metadata">

**Author:** ![AnnMarieW](https://avatars.discourse-cdn.com/v4/letter/a/ec9cab/32.png) [@AnnMarieW](https://community.plotly.com/u/AnnMarieW)\
**Post date:** [June 5, 2023, 3:48pm UTC](https://community.plotly.com/t/redirect-with-different-query-strings/75745/4 "2023-06-05T15:48:28Z")

</div>

@FirstNumberTwo

> [@FirstNumberTwo](#):
>
> I don’t see any security concerns in my case (Correct me if Im wrong)

**This is very important. Yes you still have security risks in your code.**

The issue is in code like here: `eval(param['options'][0])`

If you type in the URL ?options=print(“hello”) you will see hello printed to the console because it **executed** `print("hello")`

For more info please read

> **[Eval really is dangerous](https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)**
>
> eval() is tempting, but it’s truly dangerous. Here’s how common safety attempts can be circumvented.

---

<div class="post-metadata">

**Author:** ![jinnyzor](https://sea2.discourse-cdn.com/flex024/user_avatar/community.plotly.com/jinnyzor/32/21194_2.png) [@jinnyzor](https://community.plotly.com/u/jinnyzor)\
**Post date:** [June 5, 2023, 4:08pm UTC](https://community.plotly.com/t/redirect-with-different-query-strings/75745/5 "2023-06-05T16:08:46Z")

</div>

@FirstNumberTwo,

This is a very basic example, something more scary would be to wipe your entire system data. Or, transmit all of it, download malware, etc.

A fun thing would be if they took a look at your app setup and was able to use dash to infect all your clients too. 🙂
