Note to regular readers: ** There is a bug in the previous chapter about notification messages, which means that notify messages sent to administrators must be moved to the end of new_comment.save(), otherwise action_object stores will be NULL and the HTML concatenation anchors in this chapter will be invalid.
The original article has been corrected to apologize for the blogger’s oversight.
The previous chapter has implemented the message notification function, which can be very humanized to guide the user to the page that is replied by others.
But if you think about it, there’s another inconvenience: if there are a lot of comments on a page, it can take a bit of effort to find the one you’re interested in. So this message notification, preferably, can not only go to the right page, but also to the right place (the demand is endless..). .
To do this, this chapter introduces a very old feature: anchor location. And how to implement it in Django.
What are the anchor points
We often use the id attribute when writing containers for HTML files:
<div id="fruit">apple</div>
Copy the code
This ID attribute can be used not only as a tag for Javascript or CSS code to query a container, but also as an anchor point for where the page should go. Enter the following address:
http://www.myblog.com/home#fruit
Copy the code
The browser opens the Home page and the window goes to the container with id=”fruit”.
Now that you know what anchors are, here’s a look at how they are used in Django blog projects through three different implementations.
Three kinds of implementation
HTML stitching
The anchor’s first function is that when an administrator clicks on a notification, the browser window goes to the comment location of that notification.
So first modify the article details page and add an ID attribute to the div container that renders the comment:
templates/article/detail.html
...
<! -- Existing code, traversing the tree structure -->
{% recursetree comments %}
{% with comment=node %}
<! -- unique new code: id attribute -->
<div class="..." id="comment_elem_{{ comment.id }}" >.<! The following is the existing code
<div class="children">
{{ children }}
</div>
{% endif %}
</div>
{% endwith %}
{% endrecursetree %}
...
Copy the code
Let’s use comment.id to give each comment a unique ID value. Note that the ID attribute remains unique. Do not repeat comment_{{comment.id}} used in Modal in secondary replies.
Then modify the notification list template to add anchor points:
templates/notice/list.html
...
{% for notice in notices %}
<li .>
<! -- Added comment_elem_{{notice.action_object.id}} anchor point -->
<a href="{% url "notice:update"%}?article_id={{ notice.target.id}} ¬ice_id={{ notice.id}} #comment_elem_{{ notice.action_object.id }}"
target="_blank"
>.</a>.</li>
{% endfor %}
...
Copy the code
Notice that two things are concatenated in the URL:
- With the
?
The query parameters, which are used to pass parameters to the view, are old code that was written earlier - With the
#
And then there’s the anchor point, which is what we’re studying in this chapter
? An important difference between # and? Cannot be passed to the url of the next page, whereas # can.
To test this out, post a few level 1 comments from a regular user account, log in to the admin account and click on notifications:
The browser window is not at the top of the page, but goes directly to the comment.
HTML concatenation is the easiest and most straightforward way to implement anchors.
View together
HTML concatenation is good, but it’s not a panacea. What if you want to go to a container for which the current page has not yet been created?
Here’s an example. In our current blog design, when a user makes a comment, the page refreshes and the window stays at the top of the post details. But it actually makes sense for the window to stop at newly posted comments, because the user might want to check that they are correct. However, since the new comments on the original page have not been published, comment.id does not exist, so there is no way to use HTML to join anchor points. Consider for a moment whether this is the case.
In this case, you need to concatenate anchor points in the view. Modify the article comment view to concatenate anchor points into the Redirect function:
comment/views.py
...
# post comment view
def post_comment(request, article_id, parent_comment_id=None):.# Existing code
if request.method == 'POST':...if comment_form.is_valid():
...
if parent_comment_id:
...
new_comment.save()
if not request.user.is_superuser:
notify.send(...)
# Add code, add anchor points
redirect_url = article.get_absolute_url() + '#comment_elem_' + str(new_comment.id)
Modify redirect parameters
return redirect(redirect_url)
Copy the code
Get_absolute_url () is the method used in the previous section to query the address of an article.
In essence, the concatenation is moved from the template to the view, because new comments must be saved in the view before they are assigned an ID value.
Flowing data
And finally, let’s do a slightly more complicated case.
When a user makes a first-level comment, we solve the problem of refreshing the current page and positioning by stitching anchor points in the view. But what if secondary comments are implemented via iframe + Ajax?
Clear your head.
First, the ID value of the new comment is created in the view, but since the view is requested from the iframe, there is no way to refresh the parent page of the iframe in the view. So the only thing we can do is pass the data out to the front end for processing.
Modify the article comment view:
comment/views.py
# introduction JsonResponse
from django.http import JsonResponse
...
# post comment view
def post_comment(request, article_id, parent_comment_id=None):
article = get_object_or_404(ArticlePost, id=article_id)
# Existing code
if request.method == 'POST':...if comment_form.is_valid():
...
if parent_comment_id:
...
# Change the code here
# return HttpResponse("200 OK")
return JsonResponse({"code": "200 OK"."new_comment_id": new_comment.id})
...
Copy the code
The newly introduced JsonResponse returns jSON-formatted data that passes the ID of the new comment.
Json is a lightweight data format commonly used in Web development, much like a Python dictionary.
Note that the JSON format must be in double quotes.
The data is now in the iframe. However, we need to refresh the parent page of the iframe, so we still need to “throw” data to the parent page.
Modify the template for secondary comments:
templates/comment/reply.html
...
<script>. function confirm_submit(article_id, comment_id){ ... $.ajax({ ...// Success callback function
success: function(e){
/ / the old code
// if(e === '200 OK'){
// parent.location.reload();
// };
/ / the new code
if(e.code === '200 OK') {// Call the parent page functionparent.post_reply_and_show_it(e.new_comment_id); }; }}); }</script>
Copy the code
Because ajax now gets json data, use E. code to get the state returned by the view.
The old code refreshes the parent page with parent-location.reload (). Similarly, the ABC () function of the parent page can be called with parent.abc(). This passes the data to the parent page.
There you go. Add functions to the parent page (the article details template) that need to perform anchor concatenation:
templates/article/detail.html
...
{% block script %}
...
<script>.// Add a function to handle secondary response
function post_reply_and_show_it(new_comment_id) {
let next_url = "{% url 'article:article_detail' article.id %}";
// Remove the '/' at the end of the URL
next_url = next_url.charAt(next_url.length - 1) = ='/' ? next_url.slice(0.- 1) : next_url;
// Refresh and locate the anchor point
window.location.replace(next_url + "#comment_elem_" + new_comment_id);
};
</script>
{% endblock script %}
Copy the code
The function uses the JavaScript ternary operator A? If a is true, return B; if a is not true, return C. The effect is to remove the/at the end of the URL, otherwise the anchor will not work. Ternary operators are troublesome, you ask, so why not just strip out the last character of the URL? The answer is that writing code this way is more robust. What if One day Django doesn’t parse urls with trailing slashes?
Window.location.replace () redirects the page, where you can finally happily concatenate anchor points.
Everything is OK. Test to publish second level comments, lucky students should be able to successfully locate the window to the position of the previous comment.
Feel the flow of data?
conclusion
This chapter has learned the HTML splicing, view splicing, Ajax + IFrame comprehensive application of anchor points, after understanding can deal with most of the situation.
The anchor points are old, but not old.
The proper use of anchors can make your blog very personal, which is a sign of a good website.
- If you have any questions please leave a message on Doucet’s personal website and I will reply as soon as possible.
- Or Email me a private message: [email protected]
- Project code: Django_blog_tutorial