Link to Current Page in Django, with Additional GET Params?
How do I place an HTML link what refers to the current page, and which adds additional GET parameters (or overwriting existing ones, if they already exist)?
Right now I have something like:
<a href="{{ request.path }}?Key=Value"> My Link </a>
Currently, request
is passed to the page. If reques开发者_如何学Pythont.path
is https://stackoverflow.com/, then the resulting link becomes https://stackoverflow.com/?Key=Value
The problem?
But of course, if the current URL is https://stackoverflow.com/?PrevKey=PrevValue then it becomes:
https://stackoverflow.com/?PrevKey=PrevValue?Key=Value
Notice the incorrect second question mark -- it should in fact be:
https://stackoverflow.com/?PrevKey=PrevValue&Key=Value
Furthermore, if there is already a key with the same name, then instead of overwriting it, my current solution ignores it -- which is wrong.
How do I solve these two problems?
You'll need a custom tag. There are a couple on djangosnippets - this one looks pretty comprehensive.
For anyone seeing this in future: https://bitbucket.org/monwara/django-url-tools
You can use: {{ request.get_full_path }} to get the current path with additional parameters.
I'm just a beginner with Django, so you'll have to take my response with a grain of salt.
Firstly, request.path
should return the path to the page without the domain, according to the documentation. So if the request is for http://example.com/, request.path
should be just "/"
. Correct me if I'm wrong.
But that's not relevant. More importantly, request.path
won't have any query parameters, so if the page requested is http://example.com/?PrevKey=PrevValue, then request.path
will still be "/"
. If you want to get the query parameters, you have to make use of the dictionary-like access of the GET and POST properties (in this case GET) of the request
object. Or better yet, access them through the QueryDict methods.
What I would do here, and this is by no means the best method nor code, is to prepare a custom template filter in which you pass the current request object and the key-value pair to test against.
This is how your template code would look. Note that you can still hard code the key value pair, although here it is formatted as a string with "key colon value". The filter function can handle (if you need to) more than just one set of key-value pairs.
<a href="{{ request | addQueryParameter:'Key:Value'}}">My Link</a>
The filter function:
from urllib import urlencode
def addQueryParameter(request, parameter):
# parse the key-value pair(s) in parameter (which looks like a JSON string)
# then add to dictionary d
# note i am not taking into account white-space.
for param in string.split(','):
key, value = param.split(':', 1)
d[key] = value
# check if any keys in d are already in the request query parameters
# if so, delete from d. If I misunderstood your question, then refactor
# to delete from request.GET instead:
for key in d.keys():
if key in request.GET.keys():
del d[key]
# add the keys in request.GET into d:
d.extend(request.GET.items())
# convert dictionary of key value pairs into a query string for urls,
# prepend a ?
queryString = "?%s" % urlencode(d)
return "%s%s" % (request.path, queryString if queryString else "")
I should point out that if the request is for the page http://example.com/login/?prev=news and your template looks like
<a href="{{ request | addQueryParameter:'goto:dashboard,feature:products'}}">My Link</a>
Then the output would be (hopefully, if it works):
<a href="/login/?prev=news&goto=dashboard&feature=products">
My Link</a>
<!-- the order of the above parameters may differ -->
Note that there is no domain (i.e. the http://example.com/ part) in this link. That is because the filter doesn't add it. But you can modify it to do so.
I'll leave it to you to register this template filter. More here. Hope this helps.
A JavaScript solution is much suitable in this case. Example :
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a page_number="1">First Page</a>
<a page_number="{{ page_obj.previous_page_number }}">Last Page</a>
{% endif %}
{% if page_obj.has_previous or page_obj.has_next %}
<span class="current">{{ page_obj.number }}/{{ page_obj.paginator.num_pages }}</span>
{% endif %}
{% if page_obj.has_next %}
<a page_number="{{ page_obj.next_page_number }}">Next Page</a>
<a page_number="{{ page_obj.paginator.num_pages }}">End Page</a>
{% endif %}
</span>
<script type="text/javascript">
document.querySelectorAll('.pagination a').forEach(link => {
let page_number = link.getAttribute('page_number');
const gotopageUrl = new URL(location.href);
gotopageUrl.searchParams.set("page", page_number);
link.href = gotopageUrl.href;
});
</script>
</div>
精彩评论