In my django project I have a page displaying a list of times. On this page there is 3 GET forms which are for:
Parsing through pages
Selecting graph data
Sorting items
If a user is to select a field in all of these forms the URL should look something like this:
http://127.0.0.1:8000/watchlist/?page=1&graph_data=price&sort=quantity_desc
But when a user submits one of these forms it only saves that GET parameter in the URL. eg:
selects page = 2
http://127.0.0.1:8000/watchlist/?page=2
selects sort = quantity_asc
http://127.0.0.1:8000/watchlist/?sort=quantity_asc
The page parameter is over written when both parameters should be present in the URL. How can i preserve multiple GET parameters in the URL?
views.py
def watchlist(request):
#get requests
graph_metric = request.GET.get("graph-data-options", "avg_price")
page = int(request.GET.get("page", 1))
sort_field = request.GET.get("sort-field", "avg_price-asc")
return render(request, "App/watchlist.html", context=context)
html
<!-- Page number -->
<form id="page-buttons-form" action="{% url 'watchlist' %}" method="GET">
{% for page_button in num_pages %}
<input name="page" type="submit" value="{{page_button}}">
{% endfor %}
</form>
<!-- Sort items -->
<form id="sort-form" action="{% url 'watchlist' %}" method="GET">
<label for="sort-field">Sort:</label>
<select onchange="this.form.submit()" name="sort-field">
{% for sort in sort_options %}
<option value="{{sort.value}}">{{sort.text}}</option>
{% endfor %}
</select>
</form>
<!-- Graph data -->
<form action="{% url 'watchlist' %}" method="GET">
<label for="graph-data-options">Graph Data</label>
<select onchange="this.form.submit()" name="graph-data-options">
{% for graph_option in graph_options %}
<option value="{{graph_option.value}}">{{graph_option.text}}</option>
{% endfor %}
</select>
</form>
CodePudding user response:
To preserve multiple GET parameters in the URL, you can include the current GET parameters in the form's action attribute. One way to do this is to use the request.GET dictionary to construct the URL.
In your views.py, you can modify the watchlist function like this:
def watchlist(request):
#get requests
graph_metric = request.GET.get("graph-data-options", "avg_price")
page = int(request.GET.get("page", 1))
sort_field = request.GET.get("sort-field", "avg_price-asc")
context = {...}
context['url_params'] = request.GET.copy()
context['url_params'].pop("page", None)
return render(request, "App/watchlist.html", context=context)
Then in your template, you can include the current GET parameters in the form's action attribute like this:
<form id="page-buttons-form" action="{% url 'watchlist' %}?{% for key, value in url_params.items %}{{key}}={{value}}&{% endfor %}" method="GET">
{% for page_button in num_pages %}
<input name="page" type="submit" value="{{page_button}}">
{% endfor %}
</form>
CodePudding user response:
This is a proof of concept to demonstrate how you can preserve GET parameters when submitting different forms. Each form runs a function fillHiddenFields
before submitting, inserting existing URL parameters into the hidden fields.
Note: Apparently this does not work as a StackOverflow snippet, so you'll have to run this on your local machine.
function fillHiddenFields(event){
// extract query params from URL
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
// find hidden fields in form
let form = event.target;
const hiddentElmts = form.querySelectorAll('input[type=hidden]');
// update hidden fields with URL query params
for(let elmt of hiddentElmts){
if(elmt.name in params){
elmt.value = params[elmt.name];
}
}
// console.log form data to check that hidden fields are updated
let formdata = new FormData(form);
console.log(Object.fromEntries(formdata));
}
<body>
<form id="form1" action="javascript:void(0)" method="GET" onsubmit="fillHiddenFields(event)">
<input type="text" name="field1" value="Field 1">
<input type="hidden" name="field2" value="">
<input type="submit" value="Submit">
</form>
<form id="form2" action="javascript:void(0)" method="GET" onsubmit="fillHiddenFields(event)">
<input type="hidden" name="field1" value="">
<input type="text" name="field2" value="Field 2">
<input type="submit" value="Submit">
</form>
</body>